googleworkspace/cli · error · GwsError
Message is missing Message-ID header
Error message
Message is missing Message-ID header
What it means
Raised right after the From check in `parse_original_message`: the parsed headers contained no usable `Message-ID` (the value is run through `strip_angle_brackets` and comes back empty). Message-ID is required because `+reply`/`+reply-all` set `In-Reply-To`/`References` threading headers, and `+forward` preserves the original ID — without it the helper cannot build a standards-compliant continuation.
Source
Thrown at crates/google-workspace-cli/src/helpers/gmail/mod.rs:323
.unwrap_or("")
.to_string();
let parsed_headers = msg
.get("payload")
.and_then(|p| p.get("headers"))
.and_then(|h| h.as_array())
.map(|headers| parse_message_headers(headers))
.unwrap_or_default();
if parsed_headers.from.is_empty() {
return Err(GwsError::Other(anyhow::anyhow!(
"Message is missing From header"
)));
}
let message_id = strip_angle_brackets(&parsed_headers.message_id);
if message_id.is_empty() {
return Err(GwsError::Other(anyhow::anyhow!(
"Message is missing Message-ID header"
)));
}
let PayloadContents {
body_text: extracted_text,
body_html,
parts: original_parts,
} = msg
.get("payload")
.map(extract_payload_contents)
.unwrap_or_default();
let body_text = extracted_text.unwrap_or(snippet);
// Parse references: split on whitespace and strip any angle brackets, producing bare IDs
let references = parsed_headers
.referencesView on GitHub (pinned to a3768d0e82)
Solutions
- Verify with `gws gmail users.messages get ... | jq '.payload.headers[] | select(.name=="Message-ID")'` that the header is truly absent or empty.
- If absent, the message cannot be threaded — reply manually or from a different client for that one message.
- Keep the CLI updated; header parsing changes land in `helpers/gmail/mod.rs`.
- If you control the sending side, fix the origin MTA to always emit a Message-ID (RFC 5322 requires one).
Defensive patterns
Strategy: type-guard
Validate before calling
// Check Message-ID presence (non-empty after <> stripping) before invoking reply
let mid = msg.pointer("/payload/headers")
.and_then(|h| h.as_array())
.and_then(|hs| hs.iter().find(|h| h.get("name").and_then(|n| n.as_str()).map(|n| n.eq_ignore_ascii_case("Message-ID")).unwrap_or(false)))
.and_then(|h| h.get("value").and_then(|v| v.as_str()))
.map(|v| v.trim().trim_start_matches('<').trim_end_matches('>'));
if mid.map_or(true, |m| m.is_empty()) {
eprintln!("No usable Message-ID; thread will not be continuable");
} Type guard
fn has_message_id(msg: &serde_json::Value) -> bool {
msg.pointer("/payload/headers")
.and_then(|h| h.as_array())
.map(|hs| hs.iter().any(|h| {
let is_mid = h.get("name").and_then(|n| n.as_str()).map(|n| n.eq_ignore_ascii_case("Message-ID")).unwrap_or(false);
let non_empty = h.get("value").and_then(|v| v.as_str()).map(|v| !v.trim().trim_matches(|c| c == '<' || c == '>').is_empty()).unwrap_or(false);
is_mid && non_empty
}))
.unwrap_or(false)
} Try / catch
match run_reply(message_id).await {
Err(GwsError::Other(e)) if e.to_string().contains("Message-ID") => { skip_and_log(message_id); }
rest => rest?,
} Prevention
- Skip Message-ID-less messages in automated reply pipelines rather than aborting the batch.
- Remember the value `<>` counts as missing — strip brackets in your own guard exactly like strip_angle_brackets does.
- Ensure origin systems you control always emit a Message-ID header (RFC 5322).
When it happens
Trigger: Replying to mail generated by broken MTAs, some automated senders, or spam that omit Message-ID; drafts never sent; messages fetched where the header exists but is empty (`<>`) so angle-bracket stripping yields an empty string.
Common situations: `gws gmail +reply --message-id <ID>` against machine-generated notifications, calendar digests, or mail imported from legacy systems; reply chains that break threading on the recipient's client.
Related errors
- Message is missing From header
- Failed to fetch message: {e}
- Failed to parse message: {e}
- Failed to fetch sendAs settings: {e}
- Failed to parse sendAs response: {e}
AI-assisted analysis of googleworkspace/cli@a3768d0e82 (2026-08-16).
Data as JSON: /api/errors/e6d1570b64059a9e.
Report an issue: GitHub.