Self-hosted Gmail for agents
Four surfaces: Google OAuth you own, an MCP HTTP endpoint, a stage upload for files, and Gmail itself.
Web application client, redirect https://<your-host>/oauth/callback. Publish the consent screen to In production (Testing refresh tokens die in seven days). Details in the OAuth guide.
A seat that may connect mailboxes (typically GrokBot) calls accounts_auth_start. You open the URL on your own computer and Allow. Refresh tokens land on the server as gmail-token-*.json. Each other agent gets its own bearer from /~/ and only sees mailboxes you grant.
Search, read, label, draft, send. HTTP requires Authorization: Bearer …. Account address is an argument on every mail tool; from_identity picks which verified send-as address the mail goes out as.
Agent POSTs bytes to /outbox/stage (same bearer), gets a path under the outbox root, then passes that path to send / reply / forward. Inbound, get_attachment returns a single-use download_url only the pulling seat can redeem.
/mcp |
Streamable MCP — bearer required |
|---|---|
/oauth/callback |
Google redirect — state + PKCE, no bearer |
/outbox/stage |
Upload for later attach — bearer required |
/inbox/fetch/… |
Download a pulled attachment — bearer + single-use ticket, only for the seat that pulled it |
/healthz |
Unauthenticated liveness on the app bind (deploy verifies); gateway should proxy it publicly |
/~/ |
Owner passkey dashboard — mint a bearer per agent, grant mailboxes |
/privacy · /terms |
Consent-screen URLs |
You do not need a Google account per agent. Put a catch-all on your domain (or use plus-addressing on a consumer Gmail), add each agent’s address under Send mail as, and connect the one mailbox. identities_list reads that send-as list — it is the registry, nothing else is kept. Inbound mail carries originalTo, the address the sender used; the agent dispatches on it and trusts only recipients that are real identities. Outbound, from_identity sets From, Reply-To and the alias’s own signature, and the handler refuses any address not on the list.
Setup steps for Workspace and consumer Gmail, the label scheme, and the list of things an agent cannot do by design: docs/mailroom.md.
Outbox and download roots are configurable. On a personal host, /tmp/… with 0700 self-heal on start is fine for transient staging. Tokens stay next to the service (or under a swept prod tree) — never in the agent transcript. Over HTTP each seat’s downloads land in its own folder, so one agent cannot fetch another’s files. Staged and downloaded files are deleted after 24 hours (PIGEON_MCP_FILE_TTL_HOURS).