Skip to content

feat(gmail): add forward command#482

Open
spencer-c-reed wants to merge 1 commit intosteipete:mainfrom
spencer-c-reed:feat/gmail-forward
Open

feat(gmail): add forward command#482
spencer-c-reed wants to merge 1 commit intosteipete:mainfrom
spencer-c-reed:feat/gmail-forward

Conversation

@spencer-c-reed
Copy link
Copy Markdown

Summary

  • Adds gog gmail forward <messageId> --to <recipients> (alias fwd) to forward a Gmail message to new recipients
  • Fetches the original message in full format, constructs a proper RFC 2822 MIME forward with original headers (From, Date, Subject, To, Cc), plain text + HTML body, and re-downloaded attachments
  • Sets threadId, In-Reply-To, and References headers so the forward stays in the sender's Gmail thread
  • Supports --note / --note-file for introductory text above the forwarded content
  • --skip-attachments flag to omit original attachments
  • --from for send-as alias support
  • Full --dry-run, --json, --plain output mode support
  • Deduplicates forward subject prefixes (Fwd: Fwd:Fwd:)

Motivation

The Gmail API has no native forward endpoint — forwarding is done by constructing a new message via messages.send. gog currently supports replies (--reply-to-message-id, --quote) but not forwards, which is a common workflow gap. This command fills that gap using the same buildRFC822() and replyInfo infrastructure that replies already use.

Test plan

  • TestExecute_GmailForward_Basic — verifies subject, forward separator, original headers in body, note text, original body content, threadId, In-Reply-To header
  • TestExecute_GmailForward_WithAttachments — verifies attachments are fetched and included in MIME
  • TestExecute_GmailForward_SkipAttachments — verifies --skip-attachments prevents attachment fetch
  • TestBuildForwardSubject — subject prefix handling (new, existing Fwd:, double Fwd:, Fw:, FWD:, empty, Re:)
  • TestStripForwardPrefix — prefix stripping edge cases
  • TestFormatForwardedMessage — plain text body construction with all fields
  • TestFormatForwardedMessage_NoNote — no leading blank lines when note is empty
  • TestFormatForwardedMessageHTML — HTML body construction
  • All 10 tests passing
  • Tested live against real Gmail account — verified proper threading and content

🤖 Generated with Claude Code

Add `gog gmail forward` (alias `fwd`) to forward a Gmail message to new
recipients with proper threading, original attachments, and forwarded
message headers.

The command fetches the original message in full format, constructs a new
RFC 2822 MIME message with the forwarded content (plain text + HTML),
downloads and re-attaches all original attachments, and sets threadId /
In-Reply-To / References headers for proper Gmail thread grouping.

Flags: --to, --cc, --bcc, --note, --note-file, --from, --skip-attachments
Supports: --dry-run, --json, --plain output modes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 772193f818

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +99 to +101
origAtts := collectAttachments(origMsg.Payload)
for _, att := range origAtts {
data, dlErr := fetchAttachmentBytes(ctx, svc, messageID, att.AttachmentID)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Include inline-data attachments when forwarding

Forwarding currently builds attachment payloads only from collectAttachments(origMsg.Payload) and then refetches bytes by AttachmentID. That helper only surfaces parts with a non-empty attachmentId, so MIME parts where Gmail already provides bytes in part.body.data are skipped entirely. In those messages, gog gmail forward silently drops some original files even when --skip-attachments is not set.

Useful? React with 👍 / 👎.

Comment on lines +105 to +108
attachments = append(attachments, mailAttachment{
Filename: att.Filename,
MIMEType: att.MimeType,
Data: data,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve inline MIME metadata for HTML forwards

The forward path reconstructs attachments using only filename, MIME type, and raw data, which discards inline metadata (for example Content-ID/inline disposition). Because the original HTML body is forwarded verbatim, any message that uses cid: references will render broken images after forwarding: the parts are reattached as generic attachments instead of inline MIME parts.

Useful? React with 👍 / 👎.

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.

1 participant