[BUG] [PRIVACY] GMail MCP Rewrites URL with google tracking URLS as of 5th of June

Status Open
Maintainer reply None cached
Activity 20 comments · opened Jun 7, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

As of few days GMail MCP is rewriting - silently URL in the emails created as drafts with google tracking URLs - this is privacy nightmare and it's been done silently without telling anyone.

This should be fixed immediately and this "feature" should be opt-in.

What Should Happen?

URLs should be passed verbatim and not modified on the flight.

Error Messages/Logs

No error logs, no information about this happening

Steps to Reproduce

  1. Send draft email with embedded URL
  2. Observe the URL in draft is silently rewritten to https://www.google.com/url?q=…&source=gmail&ust=…&sa=E)

Claude Model

None

Is this a regression?

Yes, this worked in a previous version

Last Working Version

_No response_

Claude Code Version

v2.1.168

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

iTerm2

Additional Information

Please - don't do it.

View original on GitHub ↗

20 Comments

yurukusa · 4 months ago

The rewritten form you're seeing — https://www.google.com/url?q=…&source=gmail&ust=…&sa=E — is Gmail's own link redirector, not something Claude Code or the MCP generates. The source=gmail / ust / sa=E parameters are Gmail's server-side signature; that wrapper is applied by Google's mail infrastructure to links inside email bodies, which lines up with the external label here.
That said, "it worked in a previous version" is a real signal, so the useful question is what changed on the MCP side that now makes Gmail wrap the links. The usual trigger is the MIME content type of the body:

  • If the draft body is submitted as text/plain, Gmail generally leaves URLs verbatim.
  • If it's submitted as text/html (or multipart with an HTML part), Gmail tends to rewrap <a href>/auto-linked URLs through the google.com/url?q=… redirector.

So a likely explanation is that the MCP started sending drafts as HTML where it previously sent plain text.
How to pin down where the rewrite happens (and who owns the fix), without guessing:

  1. Create the draft as you did, then fetch it back raw via the Gmail API: users.drafts.get with format=RAW (or users.messages.get?format=raw), and base64url-decode the payload.
  2. Inspect the raw MIME:
  • If the stored body already contains the google.com/url?q=… form → Gmail rewrote it at accept-time (or the MCP sent it pre-wrapped). Check the Content-Type header in that same MIME — if it's text/html, that's almost certainly the cause.
  • If the stored body contains your verbatim URL and only the Gmail web UI shows the wrapped form → it's display-layer link-wrapping and the actual stored data is intact.

If the raw MIME is text/html and contains the wrapped URLs, the fix belongs in the Gmail MCP server (send text/plain, or expose a content-type option), not in Claude Code core — and it'd be worth filing against that MCP server repo with the raw MIME attached. If the stored body is verbatim, then nothing was actually modified in your data and it's purely Gmail's render-time redirect.
Either way, the raw-draft dump is the one artifact that settles it conclusively.

crion66 · 4 months ago

Just to verify if google is doing something global I tested with Grok to send an email with https link and there was no URL google.com wrapping then.

floodwayprintco · 3 months ago

Reproducing this via Claude Desktop + Gmail MCP (Gmail:create_draft)

Same issue here. When Claude creates a draft using htmlBody with clean <a href="https://example.com">anchor text</a> tags, the links in the resulting draft already contain the google.com/url?q=... wrapper before the email is ever sent. This means recipients are hitting a redirect warning interstitial and have to click "Continue to site" before the link loads.

The rewriting is happening inside the MCP at draft-creation time, not as a Gmail send-time behaviour. The href in the draft's HTML source is already wrapped when you inspect the draft in Gmail.

Reddit thread also tracking this: https://www.reddit.com/r/ClaudeCowork/comments/1uci5fz/links_in_coworkdrafted_gmail_started_arriving_as/

nathansudo · 2 months ago

Still reproducing on v2.1.197 (macOS), ~6 weeks after this report — not fixed.

**Minimal repro (confirms it's not reply-specific): a brand-new draft via create_draft with two plain-text URLs comes back with both** rewritten to https://www.google.com/url?q=…&source=gmail&ust=<ts>&sa=E in the stored body — as visible text, not just the href. Both share one ust= timestamp → a single wrapping pass at creation. No replyToMessageId, no quoted original involved.

Contrast on the same account: creating the identical draft via the community workspace-mcp draft_gmail_message tool stores the URLs verbatim. So the raw URL reaches the pipeline intact — the built-in connector is what mangles it.

Impact: hits client-facing links — e.g. a payment link renders as google.com/url?q=… next to "Pay $X," which reads as phishing on a payment email and forces manual fixes or switching tools.

+1 that URLs should be passed verbatim.

v3xQ · 2 months ago

This is causing problems on my end as well - trying to embed a img reference in an htmlBody messge. The google url wrapper is breaking the image embeding.

floodwayprintco · 1 month ago

Still present on v2.1.193. Adding a datapoint that may narrow this, because the rewrite
does not appear to survive sending, at least for <a href> in htmlBody.

Created a draft via create_draft with a plain href. Reading it back with list_drafts
returns it wrapped:

<a href="https://www.google.com/url?q=https://example.com/order/12345/?key%3DREDACTED&amp;source=gmail&amp;ust=1787344494791000&amp;sa=E">your Order</a>

A different draft on the same thread, created the same way and then sent by hand, reads
back from get_message with the href intact:

<a href="https://example.com/order/12345/?key=REDACTED" target="_blank">your Order</a>

Plain, no wrapper, no tracking params. Same for every other sent message on that thread.
So in our case the wrapping is in the draft representation only, and the recipient gets
the URL verbatim.

Worth separating two claims in this thread, since they have different severities:

  1. Drafts are stored/returned rewritten. Reproduced, consistently.
  2. Recipients receive Google tracking URLs. We could not reproduce this. Every sent

message we checked carried the author's original URL.

If others are seeing (2) with actual received mail, that is a much bigger problem than
(1) and probably deserves splitting out, because right now the report reads as if both
are established.

The practical cost of (1) on its own is still real, just different from a privacy leak:
anything that diffs a draft against the message that was eventually sent now sees a
spurious change on every link. We do exactly that to track which parts of generated
drafts humans edit by hand, and it produces false positives on nearly every draft, since
most of ours carry at least one link. Workaround is to normalize google.com/url?q=
back to its q param on both sides before comparing.

No data to add on the <img> case from the comment above, we do not embed images.

Environment: Claude Code v2.1.193, macOS, Gmail connector, create_draft / list_drafts /
get_message.

jpstroop · 1 month ago

Confirming this is still reproducing as of September 2, 2026, and that it affects sent messages, not only drafts.

My setup is a scheduled task that composes a daily news digest and sends it via mcp__Gmail__send_message. Every source URL in the delivered mail arrives wrapped as https://www.google.com/url?q=…&ust=….

Three tests that narrow the cause:

  • Not HTML anchor rewriting. I sent with body only, no htmlBody at all. Bare URLs in the plain-text body were wrapped too, despite there being no anchor tags anywhere in the message.
  • Not applied at delivery. The wrapper is already present in Gmail's own copy of the sent message, so it is introduced before the message is transmitted.
  • Not the recipient's provider. In my test the receiving domain is handled by SimpleLogin and Proton. Nothing Google-hosted is involved on that side.

That points to the rewriting happening in the connector at send time, applied to URLs in the message content regardless of MIME part.

On impact: the digest cites sources for a research brief. A wrapped URL is not the citation it claims to be. The destination is not visible before clicking, copying a link yields the redirect rather than the article, and every click is routed through Google. For a daily digest that becomes a standing record of what the recipient reads.

Agreed with the original request. Verbatim URLs seem like the right default for a send API, with wrapping opt-in at most.

patrick5633 · 1 month ago

This is occurring for me too, and very frustrating as adding the https://www.google.com/url?q=... wrapper makes it mandatory that I edit the URL in the email before sending it, despite Claude CoWork supposedly making crafting an email faster. I tried asking Claude to create plain text URLs, but it still was required to add brackets such as [.] and make it still time consuming to edit when I'm wanting to focus on other aspects of the email to ensure they are accurate rather than things like this.

pedrovillalobos · 1 month ago

This is from Google's own API, which is consumed by GMail MCP. The only way around it is not using the MCP, but an "App Password" to send it directly via SMTP.

App passwords basically open up your account for anyone with access to it, so be careful :)

nathansudo · 1 month ago

One thing i found that works, have Claude write as an HTML email and then at least the url wrapper is in the background and not visible in the email -- this works for me and allows me to send without editing. Hope this helps some others here!

timshelxyz · 20 days ago

This is still a bug which makes it so that Claude is unusable for creating drafts in Gmail. Seems like a P1 issue if Claude wants to be a work partner!

floodwayprintco · 19 days ago
This is from Google's own API, which is consumed by GMail MCP. The only way around it is not using the MCP, but an "App Password" to send it directly via SMTP. App passwords basically open up your account for anyone with access to it, so be careful :)

Yes, this is a highly annoying bug. I read this comment, but took it a step further. The only way around is to NOT use the MCP but there are many other ways besides an app password.

What other connectors do you have, that use Gmail?

For me, I have Zapier so I use the Zapier Connector for creating drafts now. Problem solved.

tomaroyal · 10 days ago

Facing the same issue here.

ehn · 10 days ago

I've reported this to Google, since the rewrite happens on their side and Anthropic can't fix it:

https://issuetracker.google.com/issues/569219200 (Gmail API component)

What I found (raw MIME via get_draft with RAW):

  • create_draft with only body, no htmlBody, still comes back with a wrapped URL in the text/plain part. The server also adds an HTML part we never sent, with the same wrapper. So switching to text/plain doesn't avoid it.
  • The headers show Received: … by gmailapi.google.com with HTTPREST, so the rewrite happens server-side when the draft is created.
  • ust is creation time + 24h, so the wrapped links appear to go stale after a day.

I've also opened a Workspace support case and asked for it to be linked to the issue.

If you're affected, please ★ the Google issue (top left of the issue page). Stars are how Google gauges impact, and if you're on Workspace, opening a support case that references the issue adds more weight.

floodwayprintco · 9 days ago
I've reported this to Google, since the rewrite happens on their side and Anthropic can't fix it: https://issuetracker.google.com/issues/569219200 (Gmail API component) What I found (raw MIME via get_draft with RAW): create_draft with only body, no htmlBody, still comes back with a wrapped URL in the text/plain part. The server also adds an HTML part we never sent, with the same wrapper. So switching to text/plain doesn't avoid it. The headers show Received: … by gmailapi.google.com with HTTPREST, so the rewrite happens server-side when the draft is created. * ust is creation time + 24h, so the wrapped links appear to go stale after a day. I've also opened a Workspace support case and asked for it to be linked to the issue. If you're affected, please ★ the Google issue (top left of the issue page). Stars are how Google gauges impact, and if you're on Workspace, opening a support case that references the issue adds more weight.

Can I ask, how are you sure that it's the Google side? Other platforms, MCP etc do not have this issue.

jescalan · 9 days ago

This is really bad. It makes the gmail tool unusable, accidentally sending anything that reads like a link results in an embarrassing mess. It will also split hostnames, so foo.bar.example.com becomes foo.https://www.google.com/url?q=http://bar.example.com&source=gmail&ust=...&sa=E, and it will keep adding "Re:"s to the subject line, even if there'a already one there, so an email with "Re: example" becomes "Re: Re: example"

ehn · 9 days ago
Can I ask, how are you sure that it's the Google side? Other platforms, MCP etc do not have this issue.

Good question. There's a timestamp fingerprint that shows the rewrite happens inside Google's server, not before the request reaches it.

The client doesn't build the MIME: create_draft takes plain fields (body, subject), and Google's server assembles the message. Fetch a wrapped draft raw and compare:

  • MIME boundary, generated by Google's server: ----=_Part_41210_236293551.1791017778859. The last part is a millisecond timestamp: 1791017778859.
  • Rewritten link: …&ust=1791104178859000&sa=E. The ust is in microseconds.

ust is a 24h expiry, so: 1791017778859 ms + 86,400,000 ms (24h) = 1791104178859 ms = 1791104178859000 µs, exactly the ust value, to the millisecond. I checked three separate drafts and all three match the same way. So the wrapper is generated by the same process and clock that builds the message on Google's side. If the client, or anything between it and Google, had rewritten the body before sending, its timestamp couldn't line up with Google's MIME-build time like that.

You can check your own: fetch a wrapped draft with get_draft (format RAW), take the boundary's trailing number, add 86400000, and compare with ust/1000.

As for other platforms not having the problem: as far as I can tell, they don't use Google's MCP server.

ehn · 8 days ago

Got a reply from Google Workspace Support:

Our engineering team has reviewed the detailed documentation you provided and confirmed that this is a known issue within the Gmail MCP backend. Currently, the server is incorrectly applying display-time safe-redirect rewriting during draft creation on the API write path. Because these rewritten links lack the required security signatures, recipients are met with a "Redirect Notice" page instead of the intended destination. Our product engineers are actively working on a fix to ensure the MCP server stores URLs verbatim. In the meantime, to prevent this from disrupting your outbound email workflow, we recommend using one of the following workarounds: Option 1: Use the standard Gmail API for messages with links Instead of using the MCP create_draft tool, you can programmatically send emails containing links via the standard Gmail API (users.messages.send or users.drafts.create) by passing a raw RFC 2822 formatted message. The standard API endpoints bypass this MCP-specific rewriting behavior. Option 2: Add links via the Gmail Web UI If manual intervention is possible, you can use the MCP server to generate text-only drafts, and then have your users manually insert the necessary URLs using the standard Gmail web interface before sending. Links added through the standard web UI will not be altered.
rudi3k · 7 days ago

Reproduced on 2026-10-07 with the claude.ai Gmail connector (claude.ai chat, desktop app), not Claude Code CLI. A few findings that might help narrow this down:

  1. send_message: I sent a mail with a plain-text body only (to, subject, body). Reading the sent message back via get_message (RAW), both the text/plain part and a text/html part (which I never supplied) contain the URLs wrapped as https://www.google.com/url?q=<original>&source=gmail&ust=...&sa=E. Bare domains like example.org were also turned into wrapped http:// links. So the rewrite is already present in the stored/sent message, not just in the draft view.
  1. create_draft: the same happens with (a) body + htmlBody with explicit <a href="..."> anchors and (b) htmlBody only. In both cases the href targets and the plain-text part come back wrapped via get_draft (RAW). The htmlBody workaround suggested in #91287 therefore did not help in my case.
  1. mailto: links and plain email addresses were not rewritten, only http(s) URLs and bare domains.
  1. A draft typed manually in the Gmail web UI (same account) kept clean links, as did one I edited by hand afterwards. So this looks specific to the connector's draft/send path, not to Gmail itself or the account settings.

Impact: recipients receive redirect links that look like tracking links, the original URL is hard to read, and I had to verify and repair every outgoing mail manually. That defeats the purpose of using the connector in an agentic workflow.

Requested behavior: store and send the body verbatim (as a direct Gmail API call does), or at least make the rewriting opt-in / provide a parameter to disable it. If the wrapping is intentional, please document it in the tool descriptions.

rudi3k · 7 days ago

Workaround: skip the connector and call the Gmail API directly

Because the rewrite seems to happen in the connector's draft/send path, calling the plain Gmail REST API avoids it. I tested this on 2026-10-07: a mail with https://example.com/path?x=1&y=2 and a bare example.org arrived with unmodified links, in both the text/plain and text/html parts.

How to set it up:

  1. In Google Cloud Console, create a project and enable the Gmail API.
  2. Configure the OAuth consent screen (user type External, status Testing, add your account as a test user). Note: refresh tokens of apps in Testing expire after about 7 days.
  3. Create an OAuth client of type Desktop app.
  4. Sign in once via the loopback flow (PKCE) with the minimal scope https://www.googleapis.com/auth/gmail.compose, and keep the client ID/secret/refresh token in a password manager (I use 1Password and read them with op read).

How to call it:

  • Build the message with Python's email.message.EmailMessage (plain text part plus an optional text/html part with explicit <a href> links), base64url-encode it, and send it as {"raw": "..."}.
  • POST https://gmail.googleapis.com/gmail/v1/users/me/drafts creates a draft, POST .../users/me/messages/send sends it directly.
  • A Send as address works as the From header.

Caveat: with only gmail.compose, drafts.get works but messages.get returns 403, so a sent message cannot be read back with that scope.

I wrapped this in a small stdlib-only script (draft/send, --cc/--bcc/--attach, --dry-run). ~Happy to share it if useful.~ -> https://gist.github.com/rudi3k/98f8debcc5e387b7365eb4908eece9c2

This only works around the problem on the user's own machine. The connector itself should still store and send bodies verbatim, or make the rewriting opt-in.