Skip to content

New function forward_gmail_message (with tests)#455

Open
jcwatson11 wants to merge 1 commit into
taylorwilsdon:mainfrom
jcwatson11:forward-gmail-message
Open

New function forward_gmail_message (with tests)#455
jcwatson11 wants to merge 1 commit into
taylorwilsdon:mainfrom
jcwatson11:forward-gmail-message

Conversation

@jcwatson11
Copy link
Copy Markdown

Summary

  • Extract _forward_gmail_message_impl for testability
  • Add 8 unit tests covering text/HTML forwarding, attachments, CC/BCC, and subject handling

Test plan

  • All 8 new tests pass (uv run pytest tests/gmail/test_forward_gmail_message.py -v)
  • Existing tests unaffected

Extract _forward_gmail_message_impl for testability and add 8 unit tests
covering text/HTML forwarding, attachments, CC/BCC, and subject handling.
@jcwatson11 jcwatson11 changed the title Add tests for forward_gmail_message New function forward_gmail_message (with tests) Feb 11, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a testable internal implementation for forwarding Gmail messages and introduces unit tests to validate forwarding behavior across common scenarios (plain/HTML, optional message, attachments, CC/BCC, subject prefixing).

Changes:

  • Extracted forwarding logic into _forward_gmail_message_impl to enable direct unit testing.
  • Implemented forward construction for plain/HTML, optional prepended message, and optional attachments.
  • Added 8 async unit tests covering core forward scenarios.

Reviewed changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated 5 comments.

File Description
gmail/gmail_tools.py Introduces _forward_gmail_message_impl and wires forward_gmail_message to it for testability and feature coverage (HTML + attachments).
tests/gmail/test_forward_gmail_message.py Adds new pytest async unit tests for forwarding behavior using mocked Gmail service chain calls.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread gmail/gmail_tools.py
Comment on lines +1207 to +1215
forward_header_html = (
'<div style="color: #777;">'
"---------- Forwarded message ---------<br/>"
f"From: {original_from}<br/>"
f"Date: {original_date}<br/>"
f"Subject: {original_subject}<br/>"
f"To: {original_to}"
"</div>"
)
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the HTML forward path, header values (original_from, original_subject, etc.) and forward_message when forward_message_format == 'html' are interpolated directly into HTML without escaping/sanitization. This can break the generated markup and can also allow HTML/script injection if any of these values contain markup. Consider HTML-escaping header values, and either sanitizing forward_message (if you intend to allow HTML input) or treating all forward_message content as plain text and escaping it consistently.

Copilot uses AI. Check for mistakes.
Comment thread gmail/gmail_tools.py
Comment on lines +1221 to +1223
if forward_message:
if forward_message_format == "html":
user_message_html = f"<div>{forward_message}</div><br/>"
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the HTML forward path, header values (original_from, original_subject, etc.) and forward_message when forward_message_format == 'html' are interpolated directly into HTML without escaping/sanitization. This can break the generated markup and can also allow HTML/script injection if any of these values contain markup. Consider HTML-escaping header values, and either sanitizing forward_message (if you intend to allow HTML input) or treating all forward_message content as plain text and escaping it consistently.

Copilot uses AI. Check for mistakes.
Comment thread gmail/gmail_tools.py
Comment on lines +1261 to +1270
urlsafe_data = attachment_data.get("data", "")
# Convert from URL-safe to standard base64
standard_b64 = urlsafe_data.replace("-", "+").replace("_", "/")
attachments_to_send.append(
{
"content": standard_b64,
"filename": att["filename"],
"mime_type": att["mimeType"],
}
)
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gmail attachment data is URL-safe base64 and is commonly returned without padding. Replacing -/_ is not sufficient: base64.b64decode() (used later in _prepare_gmail_message) can raise Incorrect padding for unpadded input. A robust fix is to normalize by adding required = padding (length multiple of 4), or decode with base64.urlsafe_b64decode() and then re-encode to standard base64 before passing into _prepare_gmail_message.

Copilot uses AI. Check for mistakes.
Comment thread gmail/gmail_tools.py
Comment on lines +1278 to +1280
forward_subject = original_subject
if not forward_subject.lower().startswith("fwd:"):
forward_subject = f"Fwd: {original_subject}"
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The double-prefix guard only checks for fwd:. Subjects often use variants like FW: / FWD / localized equivalents. With the current logic, a subject like FW: Something will become Fwd: FW: Something, which conflicts with the stated intent of avoiding double-prefixing. Consider expanding the detection (e.g., accept fw: and common fwd variants, potentially allowing optional spaces).

Copilot uses AI. Check for mistakes.
Comment on lines +8 to +12
import sys
import os

sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../..")))

Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Modifying sys.path inside tests is brittle and can mask packaging/import issues (and can behave differently depending on how tests are invoked). Prefer configuring imports via the test runner/environment (e.g., pyproject.toml/pytest settings, editable install, or a conftest.py that configures the project root once) so the tests run consistently in CI and local environments.

Suggested change
import sys
import os
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../..")))

Copilot uses AI. Check for mistakes.
Repository owner deleted a comment from kapilthakare-cyberpunk Feb 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants