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
        .references

View on GitHub (pinned to a3768d0e82)

Solutions

  1. Verify with `gws gmail users.messages get ... | jq '.payload.headers[] | select(.name=="Message-ID")'` that the header is truly absent or empty.
  2. If absent, the message cannot be threaded — reply manually or from a different client for that one message.
  3. Keep the CLI updated; header parsing changes land in `helpers/gmail/mod.rs`.
  4. 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

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


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