Skip to content

fix(gmail): use case-insensitive matching for email headers in parse_message_headers#643

Open
gura105 wants to merge 3 commits intogoogleworkspace:mainfrom
gura105:fix/header-case-insensitive
Open

fix(gmail): use case-insensitive matching for email headers in parse_message_headers#643
gura105 wants to merge 3 commits intogoogleworkspace:mainfrom
gura105:fix/header-case-insensitive

Conversation

@gura105
Copy link
Copy Markdown

@gura105 gura105 commented Mar 30, 2026

Description

parse_message_headers uses 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

// Before: exact match — "CC" falls through to _ => {}
match name {
    "Cc" => append_address_list_header_value(&mut parsed.cc, value),
    ...
}

Fix

Use eq_ignore_ascii_case match guards for zero-allocation case-insensitive matching, consistent with the existing get_part_header and extract_header functions in the same file.

// After: case-insensitive — "CC", "Cc", "cc" all match
match name {
    s if s.eq_ignore_ascii_case("cc") => {
        append_address_list_header_value(&mut parsed.cc, value)
    }
    ...
}

This also simplifies the Message-ID arm from "Message-ID" | "Message-Id" to just eq_ignore_ascii_case("message-id").

Scope

All headers in the match block are affected, not just Cc:

Header Impact if missed
From Hard error ("Message is missing From header")
Message-ID Hard error ("Message is missing Message-ID header")
To +reply-all misses To recipients
CC +reply-all drops CC recipients
Reply-To Reply goes to wrong recipient
References Threading breaks

Tests

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 headers
  • test_parse_message_headers_mixed_case — canonical + non-canonical mix

All existing tests pass unchanged.

Fixes #642

Checklist:

  • My code follows the AGENTS.md guidelines (no generated google-* crates).
  • I have run cargo fmt --all to format the code perfectly.
  • I have run cargo clippy -- -D warnings and resolved all warnings.
  • I have added tests that prove my fix is effective or that my feature works.
  • I have provided a Changeset file (e.g. via pnpx changeset) to document my changes.

…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-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 30, 2026

🦋 Changeset detected

Latest commit: 1656739

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@googleworkspace/cli Patch

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

@google-cla
Copy link
Copy Markdown

google-cla bot commented Mar 30, 2026

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.

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, 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

  • Case-Insensitive Header Matching: Updated parse_message_headers to normalize email header names to lowercase before matching, ensuring compatibility with non-canonical header casing from various MTAs.
  • Improved Robustness: Prevents silent data loss for CC recipients and other critical headers when messages are processed through systems like Microsoft Exchange.
  • Expanded Test Coverage: Added three new test cases covering all-uppercase, all-lowercase, and mixed-case header scenarios to verify the fix.
Using Gemini Code Assist

The 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 /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

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 .gemini/ folder in the base of the repository. Detailed instructions can be found here.

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

  1. Review the Generative AI Prohibited Use Policy, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@googleworkspace-bot googleworkspace-bot added the area: core Core CLI parsing, commands, error handling, utilities label Mar 30, 2026
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

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.

Comment on lines 261 to 271
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),
_ => {}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

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.

Suggested change
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),
_ => {}
}

@googleworkspace-bot
Copy link
Copy Markdown
Collaborator

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

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.
@googleworkspace-bot
Copy link
Copy Markdown
Collaborator

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: core Core CLI parsing, commands, error handling, utilities

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(gmail): parse_message_headers uses case-sensitive match, drops CC/headers with non-canonical casing

2 participants