From 716ee9ccfa31e910ec4321f9b742ca46cd83ef15 Mon Sep 17 00:00:00 2001 From: Lucas Pretti <10896096+lucaspretti@users.noreply.github.com> Date: Wed, 10 Jun 2026 05:26:35 +0200 Subject: [PATCH 1/2] fix(gmail): match message headers case-insensitively Microsoft Exchange / Outlook emit non-canonical header casing (e.g. "CC"), and the Gmail API preserves the original casing. parse_message_headers matched header names case-sensitively, so +reply-all silently dropped Cc recipients (and any header not in canonical casing) per RFC 5322 1.2.2. Match on the lowercased header name, and add a regression test covering uppercase FROM/TO/CC and lowercase message-id. Fixes #642 --- .../src/helpers/gmail/mod.rs | 55 ++++++++++++++++--- 1 file changed, 46 insertions(+), 9 deletions(-) diff --git a/crates/google-workspace-cli/src/helpers/gmail/mod.rs b/crates/google-workspace-cli/src/helpers/gmail/mod.rs index caeb8b6b..f4f4711b 100644 --- a/crates/google-workspace-cli/src/helpers/gmail/mod.rs +++ b/crates/google-workspace-cli/src/helpers/gmail/mod.rs @@ -258,15 +258,19 @@ fn parse_message_headers(headers: &[Value]) -> ParsedMessageHeaders { let name = header.get("name").and_then(|v| v.as_str()).unwrap_or(""); let value = header.get("value").and_then(|v| v.as_str()).unwrap_or(""); - match name { - "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" | "Message-Id" => parsed.message_id = value.to_string(), - "References" => append_header_value(&mut parsed.references, value), + // RFC 5322 §1.2.2: header field names are case-insensitive. Some MTAs + // (notably Microsoft Exchange / Outlook) emit non-canonical casing such + // as "CC", and the Gmail API preserves the original casing. Match on the + // lowercased name so those headers are not silently dropped (issue #642). + 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), _ => {} } } @@ -2160,6 +2164,39 @@ mod tests { assert_eq!(original.message_id, "bare-id@example.com"); } + #[test] + fn test_parse_original_message_case_insensitive_headers() { + // RFC 5322 §1.2.2: header names are case-insensitive. Microsoft Exchange / + // Outlook commonly emit non-canonical casing such as "CC", and the Gmail API + // preserves it. These must still be recognized so reply-all does not silently + // drop recipients (issue #642). + let msg = json!({ + "threadId": "t1", + "snippet": "", + "payload": { + "mimeType": "text/plain", + "headers": [ + { "name": "FROM", "value": "alice@example.com" }, + { "name": "TO", "value": "bob@example.com" }, + { "name": "CC", "value": "carol@example.com" }, + { "name": "cc", "value": "dave@example.com" }, + { "name": "Subject", "value": "Hi" }, + { "name": "message-id", "value": "" } + ], + "body": { "data": URL_SAFE.encode("text") } + } + }); + let original = parse_original_message(&msg).unwrap(); + assert_eq!(original.from.email, "alice@example.com"); + assert_eq!(original.to.len(), 1); + assert_eq!(original.to[0].email, "bob@example.com"); + let cc = original.cc.expect("CC recipients must not be dropped"); + assert_eq!(cc.len(), 2); + assert_eq!(cc[0].email, "carol@example.com"); + assert_eq!(cc[1].email, "dave@example.com"); + assert_eq!(original.message_id, "min@example.com"); + } + #[test] fn test_parse_original_message_missing_payload() { let msg = json!({ From 68e85e583407276852bf42e7a2797d6a78547427 Mon Sep 17 00:00:00 2001 From: Lucas Pretti <10896096+lucaspretti@users.noreply.github.com> Date: Wed, 10 Jun 2026 05:55:23 +0200 Subject: [PATCH 2/2] chore: add changeset for gmail header case-insensitive fix --- .changeset/gmail-header-case-insensitive.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/gmail-header-case-insensitive.md diff --git a/.changeset/gmail-header-case-insensitive.md b/.changeset/gmail-header-case-insensitive.md new file mode 100644 index 00000000..793e8190 --- /dev/null +++ b/.changeset/gmail-header-case-insensitive.md @@ -0,0 +1,5 @@ +--- +"@googleworkspace/cli": patch +--- + +Fix Gmail message header parsing to be case-insensitive (RFC 5322 §1.2.2). `+reply-all` no longer silently drops `Cc` recipients (or other headers) from Microsoft Exchange / Outlook senders that use non-canonical casing such as `CC`.