hermes - 💡(How to fix) Fix [Bug]: google-workspace Gmail wrapper loses To/Subject due to case-sensitive header handling

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Error Message

Additional Logs / Traceback (optional)

Root Cause

Root Cause Analysis (optional)

Fix Action

Fix / Workaround

  1. Compare with the raw Gmail API payload or with a patched _headers_dict() that normalizes header names case-insensitively.

Code Example

GAPI="python ${HERMES_HOME:-$HOME/.hermes}/skills/productivity/google-workspace/scripts/google_api.py"
$GAPI gmail send --to recipient@example.com --subject "Header test" --body "body"

---

$GAPI gmail get MESSAGE_ID

---

{
  "to": "[email protected]",
  "subject": "Header test"
}

---

{
  "to": "",
  "subject": ""
}

---

~/.hermes/skills/productivity/google-workspace/scripts/google_api.py
message["to"]      present
message["To"]      absent
message["subject"] present
message["Subject"] absent

---

gh search issues --repo NousResearch/hermes-agent 'google workspace gmail headers lowercase' => []
gh search issues --repo NousResearch/hermes-agent 'gmail get empty subject' => []
gh search prs    --repo NousResearch/hermes-agent 'google workspace gmail headers' => []

---

message["to"] = args.to
message["subject"] = args.subject
message["cc"] = args.cc
message["from"] = args.from_header

---

def _headers_dict(msg: dict) -> dict[str, str]:
    return {h["name"]: h["value"] for h in msg.get("payload", {}).get("headers", [])}

headers.get("To", "")
headers.get("Subject", "")

---

message["To"] = ...
message["Subject"] = ...
message["Cc"] = ...
message["From"] = ...

---

python -m pytest tests/skills/test_google_workspace_api.py -q -o 'addopts='
11 passed in 0.29s

python -m pytest tests/skills/test_google_workspace_api.py tests/skills/test_google_oauth_setup.py -q -o 'addopts='
26 passed in 0.47s
RAW_BUFFERClick to expand / collapse

Bug Description

The google-workspace skill's Gmail wrapper writes MIME headers with lowercase names (to, subject, cc, from) but later reads Gmail API headers with exact canonical names (To, Subject, From).

As a result, google_api.py gmail get MESSAGE_ID can report an empty to and subject for messages sent through google_api.py gmail send, even though the raw Gmail API payload contains those headers in lowercase.

Steps to Reproduce

  1. Use the installed google-workspace skill on Hermes v0.15.1.
  2. Send a Gmail message through the wrapper:
GAPI="python ${HERMES_HOME:-$HOME/.hermes}/skills/productivity/google-workspace/scripts/google_api.py"
$GAPI gmail send --to [email protected] --subject "Header test" --body "body"
  1. Read the returned message ID through the same wrapper:
$GAPI gmail get MESSAGE_ID
  1. Compare with the raw Gmail API payload or with a patched _headers_dict() that normalizes header names case-insensitively.

Expected Behavior

gmail get should return the sent message metadata with populated fields:

{
  "to": "[email protected]",
  "subject": "Header test"
}

gmail send / gmail reply should also emit conventional RFC header names (To, Subject, Cc, From) instead of lowercase variants.

Actual Behavior

The wrapper can return:

{
  "to": "",
  "subject": ""
}

The message is not necessarily missing those headers. The raw Gmail API payload contains them as lowercase to / subject, while _headers_dict() stores and reads header names case-sensitively.

Affected Component

  • Skills (skill loading, skill hub, skill guard)

Messaging Platform (if gateway-related)

  • N/A (CLI only)

Debug Report

N/A. This is a small code-level bug in skills/productivity/google-workspace/scripts/google_api.py, reproduced directly with the skill wrapper and confirmed by inspecting the Gmail API payload.

Operating System

Fedora Linux 43 (Sway)

Python Version

Hermes runtime: Python 3.12.13 System Python: Python 3.14.5

Hermes Version

Hermes Agent v0.15.1 (2026.5.29)

Additional Logs / Traceback (optional)

Installed skill markers on v0.15.1:

~/.hermes/skills/productivity/google-workspace/scripts/google_api.py
message["to"]      present
message["To"]      absent
message["subject"] present
message["Subject"] absent

Duplicate search performed before filing:

gh search issues --repo NousResearch/hermes-agent 'google workspace gmail headers lowercase' => []
gh search issues --repo NousResearch/hermes-agent 'gmail get empty subject' => []
gh search prs    --repo NousResearch/hermes-agent 'google workspace gmail headers' => []

Root Cause Analysis (optional)

gmail_send() and gmail_reply() build MIME messages with lowercase header names:

message["to"] = args.to
message["subject"] = args.subject
message["cc"] = args.cc
message["from"] = args.from_header

gmail_get() then uses _headers_dict() and exact canonical lookups:

def _headers_dict(msg: dict) -> dict[str, str]:
    return {h["name"]: h["value"] for h in msg.get("payload", {}).get("headers", [])}

headers.get("To", "")
headers.get("Subject", "")

Header field names are case-insensitive by RFC, but this dict access is case-sensitive.

Proposed Fix (optional)

  1. Emit canonical MIME header names in gmail_send() and gmail_reply():
message["To"] = ...
message["Subject"] = ...
message["Cc"] = ...
message["From"] = ...
  1. Make _headers_dict() robust by preserving original keys and also adding canonical aliases for common headers case-insensitively (from, to, cc, subject, date, message-id).

  2. Add regression tests covering:

    • _headers_dict() normalizes lowercase Gmail API header names.
    • gmail_send() builds raw MIME messages with canonical To / Subject header names.

Local validation with this fix:

python -m pytest tests/skills/test_google_workspace_api.py -q -o 'addopts='
11 passed in 0.29s

python -m pytest tests/skills/test_google_workspace_api.py tests/skills/test_google_oauth_setup.py -q -o 'addopts='
26 passed in 0.47s
  • I'd like to fix this myself and submit a PR

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

hermes - 💡(How to fix) Fix [Bug]: google-workspace Gmail wrapper loses To/Subject due to case-sensitive header handling