googleworkspace/cli · error · GwsError
Message is missing From header
Error message
Message is missing From header
What it means
Raised by `parse_original_message` (used by `+reply`/`+reply-all`/`+forward`) after fetching a Gmail message with `format=full`: the `payload.headers` array was parsed but contained no `From` header, or `payload`/`headers` was absent so `parse_message_headers` fell back to empty defaults. The helper refuses to operate on a message it cannot attribute, because a reply needs a sender to address.
Source
Thrown at crates/google-workspace-cli/src/helpers/gmail/mod.rs:316
.and_then(|v| v.as_str())
.filter(|s| !s.is_empty())
.map(String::from);
let snippet = msg
.get("snippet")
.and_then(|v| v.as_str())
.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)View on GitHub (pinned to a3768d0e82)
Solutions
- Inspect the message first: `gws gmail users.messages get --userId me --id <ID> --params '{"format":"full"}' | jq '.payload.headers'` to confirm From is really absent.
- If the message legitimately lacks From, reply is impossible — report the ID to the sender/gateway owner or pick another message.
- If headers exist but are nested, this indicates an API/shape change; check the Gmail API release notes and update the CLI (`cargo install` latest / bump version).
- For scripting, pre-filter message IDs through a metadata list query that excludes malformed messages.
Example fix
// before: any message without From aborts the helper
if parsed_headers.from.is_empty() {
return Err(GwsError::Other(anyhow::anyhow!("Message is missing From header")));
}
// after: fall back to the raw-size sender only if present, else a clear per-message error
if parsed_headers.from.is_empty() {
return Err(GwsError::Other(anyhow::anyhow!(
"Message {} has no From header; cannot determine reply recipient (malformed or synthesized message)",
message_id
)));
} Defensive patterns
Strategy: type-guard
Validate before calling
// Before replying, fetch the message once and check header presence
let msg: Value = fetch_message(...).await?;
if !has_from_header(&msg) {
eprintln!("Skipping {}: no From header", message_id);
return Ok(());
} Type guard
fn has_from_header(msg: &serde_json::Value) -> bool {
msg.get("payload")
.and_then(|p| p.get("headers"))
.and_then(|h| h.as_array())
.map(|hs| hs.iter().any(|h| h.get("name").and_then(|n| n.as_str()).map(|n| n.eq_ignore_ascii_case("from")).unwrap_or(false) && h.get("value").and_then(|v| v.as_str()).is_some_and(|v| !v.trim().is_empty())))
.unwrap_or(false)
} Try / catch
// When calling the reply helper, match on GwsError and skip malformed messages in batch flows:
match run_reply(message_id).await {
Ok(_) => {},
Err(GwsError::Other(e)) if e.to_string().contains("missing From header") => {
eprintln!("skipping malformed message {message_id}");
continue;
}
Err(e) => return Err(e),
} Prevention
- In batch reply scripts, pre-filter candidates with a metadata fetch and the has_from_header guard.
- Treat From-less messages as data-quality issues at the source (fix the sending MTA).
- Pin the fetch to format=full — other formats omit payload headers.
When it happens
Trigger: Replying/forwarding a message whose raw MIME lacked a From header (rare bounce/NDR or spam synthesized by legacy MTAs); fetching a draft or partial message object; a Gmail API response where headers live under a nested part rather than the top-level payload; passing a message ID that returns a minimal object.
Common situations: Users hitting `gws gmail +reply` on automated notifications, bounce messages, or imported mail from broken gateways; scripts that feed message IDs obtained from a different format (`format=metadata` vs `format=full`).
Related errors
- Message is missing Message-ID header
- Failed to serialize email: {e}
- Failed to fetch message: {e}
- Failed to parse message: {e}
- Failed to fetch sendAs settings: {e}
AI-assisted analysis of googleworkspace/cli@a3768d0e82 (2026-08-16).
Data as JSON: /api/errors/004351f65fa639f2.
Report an issue: GitHub.