Problem
Gmail's web UI URLs no longer expose the API thread ID. The address bar now shows opaque "sync IDs" prefixed with FMfcgz...:
https://mail.google.com/mail/u/0/#inbox/FMfcgzQgLjNPlfJCVRfnNkPGkLhWClCW
Passing this directly to the API returns Invalid id value:
$ gws gmail users threads get --params '{"userId":"me","id":"FMfcgzQgLjNPlfJCVRfnNkPGkLhWClCW"}'
{
"error": {
"code": 400,
"message": "Invalid id value",
"reason": "invalidArgument"
}
}
The Gmail API only accepts hex thread IDs like 19e1acd465710c93, which the new Gmail UI never shows to the user. So the most natural input an agent or human has for "this email" — the URL they can copy from the browser — is unusable with gws.
Why a client-side conversion is not possible
I checked whether the sync ID can be decoded into the hex thread ID locally. Decoded as base64url, it is 24 bytes:
FMfcgzQgLjNPlfJCVRfnNkPGkLhWClCW
↓
14 C7 DC 83 34 | 20 2E 33 4F 95 F2 42 55 17 E7 36 43 C6 90 B8 56 0A 50 96
└── magic ────┘└──────── 19 bytes opaque payload ────────┘
- The first 5 bytes are a constant scheme tag (every URL starts with
FMfcgz).
- The remaining 19 bytes contain no recognizable substring of the corresponding hex thread ID. Length and entropy suggest a ciphertext + authentication tag, and sync IDs differ across accounts for the same thread — i.e. wrapped with a per-account server-side key.
This matches the upstream consensus that "the newer 'sync' style IDs that appear in the browser's address bar don't yet work with the Gmail API". A deterministic offline conversion is not on the table.
Real-world use case
When an agent (or a human) wants gws to act on a specific email, the most natural reference is the Gmail web URL they're currently looking at. Today that requires:
- Realize the URL ID won't work.
- Run
gws gmail users threads list ....
- Eyeball snippets to guess which thread is the right one.
- Copy the hex
id into the next command.
Step 3 is unreliable when the inbox is busy or when the email isn't recent.
Proposed solution
A helper that does the fuzzy lookup explicitly, taking either a URL or a free-form hint:
# Resolve from a Gmail web URL by listing candidates around its likely time window
gws gmail +find --url 'https://mail.google.com/mail/u/0/#inbox/FMfcgz...'
# Or by hint (subject / sender / time window)
gws gmail +find "Supabase monthly"
gws gmail +find --from kimdh@example.com --since 24h
gws gmail +find --subject "ChatGPT" --label INBOX
The helper would:
- Parse the URL, extract the label segment (
#inbox, #sent, #label/Foo, …) and use it as a labelIds filter. The sync ID itself is treated as opaque context, not decoded.
- Call
users.threads.list with the matching label and a reasonable maxResults (e.g. 50).
- If
--subject/--from/--since narrows it to one thread, return the hex id (and snippet) ready to pipe into gws gmail users threads get.
- Otherwise print a numbered list with sender, subject, date, and snippet — same shape as
+triage — so the user/agent can disambiguate without re-running the full API call.
JSON output for agents:
{
"matches": [
{
"id": "19e1acd465710c93",
"threadId": "19e1acd465710c93",
"from": "Supabase <newsletter@supabase.com>",
"subject": "Supabase Monthly — April",
"date": "2026-05-11T08:14:00Z",
"snippet": "Everything that happened in the last month at Supabase ..."
}
],
"source": {
"url": "https://mail.google.com/mail/u/0/#inbox/FMfcgz...",
"label": "INBOX"
}
}
This stays within the public API surface, requires no decryption, and is consistent with how other + helpers (+triage, +watch) abstract listing operations.
Alternative: documentation only
At minimum, a one-sentence note in the README and gws-gmail SKILL.md that Gmail web URL IDs (FMfcgz...) are not valid API IDs would save users from the confusing Invalid id value error and a round of debugging. The current SKILL examples implicitly assume the user already has a hex ID, which is increasingly hard to obtain from a browser.
Environment
gws 0.22.5 (installed via npm install -g @googleworkspace/cli)
- Node 24.13
- Windows 11
Problem
Gmail's web UI URLs no longer expose the API thread ID. The address bar now shows opaque "sync IDs" prefixed with
FMfcgz...:Passing this directly to the API returns
Invalid id value:The Gmail API only accepts hex thread IDs like
19e1acd465710c93, which the new Gmail UI never shows to the user. So the most natural input an agent or human has for "this email" — the URL they can copy from the browser — is unusable withgws.Why a client-side conversion is not possible
I checked whether the sync ID can be decoded into the hex thread ID locally. Decoded as base64url, it is 24 bytes:
FMfcgz).This matches the upstream consensus that "the newer 'sync' style IDs that appear in the browser's address bar don't yet work with the Gmail API". A deterministic offline conversion is not on the table.
Real-world use case
When an agent (or a human) wants
gwsto act on a specific email, the most natural reference is the Gmail web URL they're currently looking at. Today that requires:gws gmail users threads list ....idinto the next command.Step 3 is unreliable when the inbox is busy or when the email isn't recent.
Proposed solution
A helper that does the fuzzy lookup explicitly, taking either a URL or a free-form hint:
The helper would:
#inbox,#sent,#label/Foo, …) and use it as alabelIdsfilter. The sync ID itself is treated as opaque context, not decoded.users.threads.listwith the matching label and a reasonablemaxResults(e.g. 50).--subject/--from/--sincenarrows it to one thread, return the hexid(and snippet) ready to pipe intogws gmail users threads get.+triage— so the user/agent can disambiguate without re-running the full API call.JSON output for agents:
{ "matches": [ { "id": "19e1acd465710c93", "threadId": "19e1acd465710c93", "from": "Supabase <newsletter@supabase.com>", "subject": "Supabase Monthly — April", "date": "2026-05-11T08:14:00Z", "snippet": "Everything that happened in the last month at Supabase ..." } ], "source": { "url": "https://mail.google.com/mail/u/0/#inbox/FMfcgz...", "label": "INBOX" } }This stays within the public API surface, requires no decryption, and is consistent with how other
+helpers (+triage,+watch) abstract listing operations.Alternative: documentation only
At minimum, a one-sentence note in the README and
gws-gmailSKILL.md that Gmail web URL IDs (FMfcgz...) are not valid API IDs would save users from the confusingInvalid id valueerror and a round of debugging. The current SKILL examples implicitly assume the user already has a hex ID, which is increasingly hard to obtain from a browser.Environment
gws0.22.5 (installed vianpm install -g @googleworkspace/cli)