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

  1. 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.
  2. If the message legitimately lacks From, reply is impossible — report the ID to the sender/gateway owner or pick another message.
  3. 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).
  4. 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

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


AI-assisted analysis of googleworkspace/cli@a3768d0e82 (2026-08-16). Data as JSON: /api/errors/004351f65fa639f2. Report an issue: GitHub.