fix(gmail): use case-insensitive matching for email headers in parse_message_headers#643
fix(gmail): use case-insensitive matching for email headers in parse_message_headers#643gura105 wants to merge 3 commits intogoogleworkspace:mainfrom
Conversation
…message_headers The Gmail API preserves original header casing from the sending MTA. For example, Microsoft Exchange emits "CC" instead of "Cc". Per RFC 5322 §1.2.2, header field names are case-insensitive. parse_message_headers used exact case-sensitive string matching, so headers like "CC", "FROM", or "message-id" silently fell through to the catch-all, dropping recipients and metadata. This change normalizes header names via to_ascii_lowercase() before matching, consistent with the existing get_part_header function in the same file which already uses eq_ignore_ascii_case. Fixes googleworkspace#642
🦋 Changeset detectedLatest commit: 1656739 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 |
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
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 an issue where email header parsing was failing due to strict case-sensitive matching. By normalizing header names to lowercase, the system now correctly handles headers regardless of how they are formatted by the sending mail transfer agent, ensuring that essential metadata is correctly extracted and preserved. 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 implements case-insensitive matching for Gmail email headers in parse_message_headers to comply with RFC 5322. It includes a changeset and comprehensive unit tests for various casing scenarios. A performance improvement was suggested to use eq_ignore_ascii_case with match guards instead of to_ascii_lowercase() to avoid unnecessary string allocations within the loop.
| match name.to_ascii_lowercase().as_str() { | ||
| "from" => parsed.from = value.to_string(), | ||
| "reply-to" => append_address_list_header_value(&mut parsed.reply_to, value), | ||
| "to" => append_address_list_header_value(&mut parsed.to, value), | ||
| "cc" => append_address_list_header_value(&mut parsed.cc, value), | ||
| "subject" => parsed.subject = value.to_string(), | ||
| "date" => parsed.date = value.to_string(), | ||
| "message-id" => parsed.message_id = value.to_string(), | ||
| "references" => append_header_value(&mut parsed.references, value), | ||
| _ => {} | ||
| } |
There was a problem hiding this comment.
While this correctly implements case-insensitive matching, calling to_ascii_lowercase() inside the loop creates a new String allocation for every header. This can be inefficient, especially for messages with many headers.
For better performance and consistency with other functions in this file (like get_part_header), you can use eq_ignore_ascii_case with match guards. This performs a case-insensitive comparison without any heap allocations.
| match name.to_ascii_lowercase().as_str() { | |
| "from" => parsed.from = value.to_string(), | |
| "reply-to" => append_address_list_header_value(&mut parsed.reply_to, value), | |
| "to" => append_address_list_header_value(&mut parsed.to, value), | |
| "cc" => append_address_list_header_value(&mut parsed.cc, value), | |
| "subject" => parsed.subject = value.to_string(), | |
| "date" => parsed.date = value.to_string(), | |
| "message-id" => parsed.message_id = value.to_string(), | |
| "references" => append_header_value(&mut parsed.references, value), | |
| _ => {} | |
| } | |
| match name { | |
| s if s.eq_ignore_ascii_case("from") => parsed.from = value.to_string(), | |
| s if s.eq_ignore_ascii_case("reply-to") => append_address_list_header_value(&mut parsed.reply_to, value), | |
| s if s.eq_ignore_ascii_case("to") => append_address_list_header_value(&mut parsed.to, value), | |
| s if s.eq_ignore_ascii_case("cc") => append_address_list_header_value(&mut parsed.cc, value), | |
| s if s.eq_ignore_ascii_case("subject") => parsed.subject = value.to_string(), | |
| s if s.eq_ignore_ascii_case("date") => parsed.date = value.to_string(), | |
| s if s.eq_ignore_ascii_case("message-id") => parsed.message_id = value.to_string(), | |
| s if s.eq_ignore_ascii_case("references") => append_header_value(&mut parsed.references, value), | |
| _ => {} | |
| } |
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request updates the Gmail parse_message_headers function to perform case-insensitive matching of email header names by converting them to lowercase, ensuring compliance with RFC 5322. It also adds unit tests to verify correct parsing of uppercase, lowercase, and mixed-case headers. I have no feedback to provide.
Avoids per-header String allocation in the loop. Consistent with get_part_header in the same file. Addresses gemini-code-assist review feedback.
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request updates the parse_message_headers function in the Gmail helper module to implement case-insensitive matching for email headers, ensuring compliance with RFC 5322. The implementation replaces static string matching with match guards using eq_ignore_ascii_case. New unit tests have been added to validate the handling of uppercase, lowercase, and mixed-case header names. I have no feedback to provide as the changes correctly address the issue and include appropriate test coverage.
Description
parse_message_headersuses exact case-sensitive string matching for header names ("Cc","From", etc.), but the Gmail API preserves original header casing from the sending MTA. Per RFC 5322 §1.2.2, header field names are case-insensitive.This causes
+reply-all(and other commands) to silently drop CC recipients when the original message was sent through an MTA that uses non-canonical casing (e.g., Microsoft Exchange emits"CC"instead of"Cc").Root cause
Fix
Use
eq_ignore_ascii_casematch guards for zero-allocation case-insensitive matching, consistent with the existingget_part_headerandextract_headerfunctions in the same file.This also simplifies the
Message-IDarm from"Message-ID" | "Message-Id"to justeq_ignore_ascii_case("message-id").Scope
All headers in the match block are affected, not just
Cc:From"Message is missing From header")Message-ID"Message is missing Message-ID header")To+reply-allmisses To recipientsCC+reply-alldrops CC recipientsReply-ToReferencesTests
3 new tests (701 total, up from 698):
test_parse_message_headers_all_uppercase— all-caps headers (Exchange/Outlook pattern)test_parse_message_headers_all_lowercase— all-lowercase headerstest_parse_message_headers_mixed_case— canonical + non-canonical mixAll existing tests pass unchanged.
Fixes #642
Checklist:
AGENTS.mdguidelines (no generatedgoogle-*crates).cargo fmt --allto format the code perfectly.cargo clippy -- -D warningsand resolved all warnings.pnpx changeset) to document my changes.