fix(gmail): fix self-reply detection in +reply and +reply-all#685
fix(gmail): fix self-reply detection in +reply and +reply-all#685malob wants to merge 1 commit intogoogleworkspace:mainfrom
Conversation
When replying to a message you sent, +reply addressed the reply back to yourself instead of the original recipients. The self-reply detection from PR googleworkspace#530 only covered +reply-all and only checked the primary email and resolved alias, missing other send-as identities. Use the full send-as identity list (filtered by treatAsAlias, with the default identity always included) for both self-reply detection and self-exclusion. Fetch identities once and share between sender resolution (resolve_sender_with_identities) and the new SelfEmails type used by is_self_reply and collect_excluded_emails. Plain +reply degrades gracefully if the sendAs fetch fails; +reply-all hard-fails since incorrect self-exclusion would produce wrong recipients. Gmail's self-reply preserves original To verbatim (follow-up behavior, no self-exclusion).
🦋 Changeset detectedLatest commit: 831cced The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request addresses issues with self-reply detection in the Gmail CLI tool. Previously, self-reply detection was limited or missing, leading to replies being incorrectly addressed to the sender instead of the original recipients. The changes introduce a more comprehensive approach to identifying the user's own email addresses, including all send-as aliases, and ensure this information is consistently used to determine correct reply recipients. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request improves self-reply detection for Gmail +reply and +reply-all commands by utilizing all send-as identities and respecting the "treat as alias" setting. It refactors identity fetching to reduce API calls and introduces a SelfEmails helper for consistent email comparison. Feedback suggests sanitizing error messages before terminal output to prevent potential escape sequence injection.
| Err(e) => { | ||
| crate::output::warn(&format!( | ||
| "Could not fetch send-as identities ({}). If this is a \ | ||
| reply to your own message, the reply may be addressed \ | ||
| to you instead of the original recipients.", | ||
| e | ||
| )); | ||
| vec![] | ||
| } |
There was a problem hiding this comment.
The error string e should be sanitized before being printed to the terminal to prevent escape sequence injection. This is a security best practice for terminal output.
| Err(e) => { | |
| crate::output::warn(&format!( | |
| "Could not fetch send-as identities ({}). If this is a \ | |
| reply to your own message, the reply may be addressed \ | |
| to you instead of the original recipients.", | |
| e | |
| )); | |
| vec![] | |
| } | |
| Err(e) => { | |
| crate::output::warn(&format!( | |
| "Could not fetch send-as identities ({}). If this is a \ | |
| reply to your own message, the reply may be addressed \ | |
| to you instead of the original recipients.", | |
| crate::output::sanitize_for_terminal(&e.to_string()) | |
| )); | |
| vec![] | |
| } |
There was a problem hiding this comment.
crate::output::warn() already calls sanitize_for_terminal on its entire input (output.rs line 79), so the error string is sanitized before reaching the terminal. Adding an explicit sanitize_for_terminal here would double-sanitize.
Description
Fixes self-reply detection for both
+replyand+reply-all. When replying to a message sent by the same account, the reply was addressed back to the sender instead of to the original recipients.The problem
PR #530 added self-reply detection to
+reply-all, but it had two gaps:+replyhad no self-reply detection at all. Replying to a self-sent message addressed the reply to the From address (yourself) instead of the original To recipients.+reply-allonly checked two addresses — the primary email (via/users/me/profile) and the resolved--fromalias. Any other configured send-as alias was missed, so replying to a message sent from a non-default alias also went to the sender instead of the original recipients.How it was found
+replyon a real email thread to reply to a self-sent message. The reply was addressed to the sender instead of to the original recipient. Had to be manually re-sent with the correct address.The fix
The full send-as identity list is now used for self-reply detection, matching Gmail web's behavior:
SelfEmailsnewtype — pre-lowercased set of the user's email addresses, constructed from sendAs identities filtered by Gmail'streatAsAliassetting. The default identity is always included (Workspace accounts havetreatAsAlias: falseon the primary, but it is still "self"). Non-default, non-alias addresses (e.g. external send-as) are excluded.Single sendAs fetch —
handle_replycallsfetch_send_as_identitiesonce and shares the result betweenresolve_sender_with_identities(From resolution + display name enrichment) andSelfEmails::from_identities(self-reply detection + self-exclusion). No duplicate API calls.build_reply_recipients— new function for plain+reply, parallel tobuild_reply_all_recipients. Detects self-reply and uses original To recipients with no self-exclusion (Gmail's "follow-up" behavior, per Google's documentation and community expert confirmation).Graceful degradation — if the sendAs fetch fails for
+reply, self-reply detection is disabled with a warning but the reply still works. For+reply-all, it is a hard error since incorrect self-exclusion would produce wrong recipients.What changed
SelfEmailsnewtype inmod.rswithfrom_identities,empty,contains_email,iterSendAsIdentitygainstreat_as_aliasfield (parsed from Gmail API'streatAsAlias)resolve_sender_with_identitiesextracted fromresolve_senderfor pre-fetched identity sharingis_self_reply,build_reply_recipients,collect_excluded_emails,build_reply_all_recipientsrefactored to use&SelfEmailsfetch_user_emailremoved (replaced by sendAs identity list)resolve_senderdoc comment updated;resolve_sender_from_identitiesstays privateVerified with real email
Tested against the actual message that triggered the bug:
(yourself)(original recipient)Test coverage
717 total tests (17 new, net +15 after removing
fetch_user_emailtests). New tests cover:is_self_reply(5): primary match, alias match, case insensitivity, non-match, empty set fallbackbuild_reply_recipients(10): self-reply ignoring Reply-To, normal reply using Reply-To, preserve all To including self (no self-exclusion), note-to-self, alias detection, BCC-only fallback to From, extra CC passthrough, graceful degradation with/without Reply-ToSelfEmails(1):treatAsAliasfiltering with realistic Workspace data (primarytreatAsAlias: falsestill included)build_reply_all_recipients(1): BCC-only self-sent produces empty To (documents asymmetry with plain reply)Note on merge conflicts
This PR and #684 (display name fallback) both touch the People API display name enrichment code in
mod.rs. This PR extracts it intoresolve_sender_with_identities; #684 changes the endpoint from People API to OAuth userinfo. Whichever merges second will need a straightforward rebase to apply the endpoint change in its new location.Checklist:
AGENTS.mdguidelines (no generatedgoogle-*crates).cargo fmt --allapplied.cargo clippy -- -D warningsresolved all warnings.