How I built an AI-active Gmail inbox with real context + personalization (without Google’s AI)
I’ve been really interested in making AI actually useful in email — not “generic smart replies,” but an inbox where the right messages reliably turn into drafts that sound like me, reflect reality, and include the context I’d pull manually if I had time.
The catch: the context I need rarely lives inside Gmail.
It lives in:
- HubSpot (who is this person, what’s the account history, are they VIP, what did we promise?)
- Stripe (are they a customer, what plan, what happened with billing?)
- Postgres (internal source of truth: flags, entitlements, state)
- This repo (docs, runbooks, decisions, roadmaps, patterns)
So I built an AI-active Gmail inbox: Gmail stays the event source, but the agent runs inside a GitHub repo with MCP tools that can pull real context and draft replies that are personalized, accurate, and safe.
I did this without relying on Google’s AI. Gmail is plumbing (labels + push notifications). The intelligence and guardrails are mine.
Three non-negotiable constraints guided the build:
- No polling: I want push-driven events, not a cron job hammering APIs.
- No auto-send: drafts only; I approve every message.
- No inbox-only context: the agent must be able to query the systems that actually matter.
What I wanted was a workflow where Claude Code runs inside a GitHub repo (so it can read everything I’ve written and shipped), connects to MCP tools (so it can pull live customer context), drafts a reply in Gmail, and then pings me for approval. No surprises. No polling. No hallucinated promises.
We actually looked at building this with our Fastmail MCP first. I love Fastmail, but their API didn't give us a clean event trigger we could hook into without polling constantly. I hate polling. It feels messy and wasteful.
Gmail, however, has a push notification system that talks to Google Cloud Pub/Sub. That’s the hook.
Here's the war story of how I built a real-time, event-driven pipeline that turns "new important email" into "draft reply ready," with real context + personalization — and the mistakes I had to fix along the way.
