Repository navigation
Conversation
The helpers that render an original message's address the way Gmail shows it in quoted text (parse, plain, HTML with a mailto: link) are about to render a forward's From, To and Cc as well as a reply's sender. Move them out of gmail_reply.go into gmail_quote_mailbox.go, alongside their tests, and name them for mailboxes rather than senders: parseQuoteMailbox, formatQuoteMailbox, formatQuoteMailboxHTML. No behavior change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lay the forwarded headers out the way Gmail Web does: no grey styling or
bold labels, the separator running straight into the From line, and two
blank lines before the original body in both parts. From, To and Cc
follow the reply attribution's rule ("Name <email>", or "<email>"
without a name, names unquoted), with each address linked in HTML. The
sender's name is bold with Gmail's gmail_sendername class, which also
keeps it free of *asterisks* when Gmail rebuilds the text part of a
message sent through the API. Like Gmail, a group shows only its
members, so a To of only "undisclosed-recipients:;" leaves the line
empty; a To or Cc that isn't a parseable address list is shown as it
came, unlinked.
The header lines are built once and passed to both formatters, and both
parts share one separator constant, which the tests use to find the
block. The new tests replace the older substring tests of the
formatters, the send-only and drafts-only tests of a forward's subject,
note and threading become one test that runs both commands, and the
forward test helpers shared across files move to gmail_testutil_test.go.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
🦞👀 Pull request received. I will update this pull request when review starts. ClawSweeper review completeClawSweeper finished reviewing this revision. The review result is being finalized. |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Codex review: needs maintainer review before merge. What this changesThis PR aligns forwarded-message headers with Gmail’s layout and address formatting in plain text and HTML. Example: Forward a message whose To header is bob@example.com.
Review scores
ProductKind: Bug fix · Worth it: Yes · Fix scope: Complete Merge readiness✅ Ready for maintainer review Keep this PR open: current main retains the formatting mismatch, and the focused shared fix has relevant live Gmail proof with no actionable code findings. Priority: P3 Before mergeNone. FindingsNone. Agent review detailsHow this fits togetherGmail send and draft commands share a composition builder that reads the original message and produces MIME bodies, headers, and attachments for the Gmail API. flowchart LR
A[Original Gmail message] --> B[Shared forward composer]
C[Note and signature] --> B
B --> D[Mailbox and header renderers]
D --> E[Plain and HTML MIME bodies]
E --> F[Gmail send or draft API]
Technical reviewBest possible solution: Land the shared forward-header fix with its existing mailbox escaping and focused command coverage. Do we have a high-confidence way to reproduce the issue? Current-main source confirms the mismatched header formatting, and contributor terminal output demonstrates baseline failures through live Gmail draft readback; this read-only review ran no target code. Is this the best way to solve the issue? The existing shared forward composer and mailbox renderer are the appropriate owners, and the patch preserves reply output, recipient selection, signatures, attachments, and threading. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning medium; reviewed against d8917466326d. Provenance checked
TestingProof path: shipped entry point. SecurityNone. EvidenceWhat I checked:
Likely related people:
Review metrics
LabelsLabel changes:
Label justifications:
Rating scale6/6 🦀 challenger crab · 5/6 🦞 diamond lobster · 4/6 🐚 platinum hermit · 3/6 🦐 gold shrimp · 2/6 🦪 silver shellfish · 1/6 🧂 unranked krab. Overall follows the weaker of proof and patch quality; ✨ marks media proof (a screenshot, video, or linked artifact) that directly shows the changed behavior. WorkflowClawSweeper edits this one comment on every review. Comment Reviewed October 19, 2026, 4:17 PM ET / 20:17 UTC. |
What
People use gog in place of Gmail’s own interface, so by default what gog writes should match what Gmail writes. A forward’s header block, the one that introduces the forwarded message, didn’t:
"Carol, Quoted" <carol@example.org>).*From:* … *Date:* ….Both parts now follow the layout and address formatting of Gmail Web’s own forwards, compared against forwards saved as drafts in Gmail Web. In text/plain:
In HTML the same text, one header per
<br>, with each address linked and the sender’s name in bold the way Gmail marks it:This covers
gmail forwardandgmail drafts forward, which share the formatter.Changes
refactor(gmail): move the quote mailbox helpers into their own file. The helpers fix(gmail): match Gmail's reply attribution line #1213 added for the reply attribution line (parse a mailbox, render it as text, render it as linked HTML) move fromgmail_reply.gotogmail_quote_mailbox.gowith their tests, renamed for mailboxes rather than senders (formatQuoteMailbox,formatQuoteMailboxHTML), since the forwarded headers now use them for recipients too. No behavior change.fix(gmail): match Gmail's forwarded-message header block.Layout. The HTML block no longer has grey styling or bold labels: the separator line runs straight into
From:, and each header is one<br>line. Two blank lines separate the headers from a non-empty body, in both parts. Thegmail_quotewrapper is unchanged. Two things Gmail does are left out on purpose: its plain-text hard wrap, which splits addresses mid-way (Carol, Quoted <on one line,carol@example.org>on the next), and a doubled HTML space before a nameless address, which doesn’t render.Addresses. From, To and Cc use the attribution line’s rule:
Name <email>, or<email>without a name, with display names unquoted. To and Cc entries are joined by,. In HTML each address is amailto:link, percent-encoded as in fix(gmail): match Gmail's reply attribution line #1213.The sender’s name is bold with Gmail’s own markup,
<strong class="gmail_sendername">. A plain<strong>would bring the asterisks back: the rebuilt text part would readFrom: *Sender, Example* <…>. Gmail leaves agmail_sendernamename as it is. I checked this by sending test messages to a second account and reading the delivered copies; the text part of one whose HTML held both forms arrived as:Groups. Like Gmail Web, a group lists its members without its name. An empty group inside a list (
undisclosed-recipients:;, …) drops out, and a To of onlyundisclosed-recipients:;keeps an emptyTo:line.Values that don’t parse. A To or Cc that isn’t a parseable address list is shown trimmed but otherwise as it came, escaped in HTML, without links. A From that isn’t a single mailbox keeps fix(gmail): match Gmail's reply attribution line #1213’s fallback, the same treatment. Gmail Web instead splits such a list at its commas and links what it can (
Evil, Name <evil@example.com>became<Evil>, Name <evil@example.com>). gog doesn’t guess where a name ends, so the line loses only its links.The header lines are built once and passed to both formatters, whose argument lists shrink from nine to four, and Gmail’s separator line is one constant both parts share.
docs/gmail-workflows.mddescribes the block.Display names with a comma need nothing special. In probes, the Gmail API returned encoded names containing a comma quoted (
=?UTF-8?Q?Sender=2C_Example?=arrives as"Sender, Example" <…>), and they parse. Only a CRLF inside an encoded name came back unquoted (=?UTF-8?Q?Evil=0D=0AName?=arrives asEvil, Name <…>); that isn’t a valid address, so it takes the fallback above.Not in this PR
dirattributes and thegmail_quote_containerandgmail_attrclasses. Gmail puts them on replies’ quoted text as well as forwards, so they belong in one separate change that covers both.Behavior proof
Live against a personal Gmail account (
personalis an account alias); nothing is sent.proof_forward_header.py(below; Python 3 standard library plusgog) inserts five synthetic source messages withgmail.users.messages.insert, saves adrafts forwardof each, reads the draft back withgog gmail raw, and compares the header block in both MIME parts with the expected block. The fixtures cover a named sender with several recipients, a nameless sender, RFC 5322 comments and groups, a To naming no mailbox, and an unparseable display name. The first four expect the formatting Gmail Web produced for the same kinds of headers; the fifth expects the fallback. The script prints HTML one<br>per line, and moves everything it created to Trash; its last check confirms each move succeeded.Run against a build of current
mainwithout this change (gog-main: ten header-block checks fail, exit 1), then a build of this branch (gog-branch: all twelve checks pass, exit 0):proof_forward_header.pyTesting
TestForwardedHeaderLineschecks whole lines in both parts for:?in an address.TestForwardedHeaderLayoutchecks that:From:;gmail_sendername;gmail forwardandgmail drafts forward,TestGmailForward_HeaderBlockLikeGmailchecks that the original’s headers reach both decoded MIME parts (the plain block exactly, the HTML lines in order), andTestGmailForward_SubjectNoteAndNoThreadingchecks theFwd:subject, the note, the original’s body and the absence of thread and reply headers.make cigreen.🤖 Generated with Claude Code