Tutorial
Building a Gmail to AI Assistant Pipeline with Pub/Sub and Webhooks
Set up real-time Gmail notifications that route through an AI assistant to filter noise, extract insights, and only alert you when it matters.
Tired of email noise? In this tutorial, we’ll build a pipeline that watches your Gmail inbox in real-time, routes emails through an AI assistant, and only notifies you about what actually matters. Newsletters get summarized, receipts get ignored, and urgent emails get flagged immediately.
Key Takeaways
- Gmail’s Push Notifications API with Google Pub/Sub enables real-time email monitoring without polling
- The
gogCLI simplifies Gmail watch setup and webhook forwarding - Cloudflare Tunnels provide free, instant HTTPS endpoints for local webhook receivers
- AI filtering can categorize emails and extract insights before they reach you
- The entire pipeline runs locally with minimal cloud infrastructure
Architecture Overview
Here’s what we’re building:
Gmail Inbox
↓ (new email arrives)
Google Pub/Sub
↓ (push notification)
Cloudflare Tunnel (public HTTPS)
↓
gog CLI (local webhook server)
↓ (forwards to your app)
Your Webhook Handler
↓
AI Processing (classify, summarize, extract)
↓
Notification (only if important)
Prerequisites
Before we start, you’ll need:
- A Google Cloud project with billing enabled
gcloudCLI installed and authenticated- Node.js 18+ (for the webhook handler)
- A Gmail account to monitor
1. Install the Required Tools
First, install gog (a Gmail CLI) and cloudflared:
# Install gog via Homebrew
brew install gogcli
# Install cloudflared
brew install cloudflared
2. Set Up Google Cloud Pub/Sub
Gmail’s push notifications work through Google Pub/Sub. Let’s set up the infrastructure:
# Authenticate with Google Cloud
gcloud auth login
gcloud config set project YOUR_PROJECT_ID
# Enable required APIs
gcloud services enable gmail.googleapis.com pubsub.googleapis.com
# Create a Pub/Sub topic for Gmail notifications
gcloud pubsub topics create gmail-watch
# Allow Gmail to publish to your topic
gcloud pubsub topics add-iam-policy-binding gmail-watch \
--member=serviceAccount:gmail-api-push@system.gserviceaccount.com \
--role=roles/pubsub.publisher
3. Configure OAuth Credentials
You’ll need OAuth credentials for gog to access Gmail:
- Go to Google Cloud Console → APIs & Credentials
- Click Create Credentials → OAuth client ID
- Select Desktop app as the application type
- Download the JSON credentials file and save it somewhere accessible (e.g.,
credentials.jsonin your project directory) - Configure
gogwith your credentials:
gog auth credentials /path/to/credentials.json
gog auth login --account your@gmail.com
4. Start the Cloudflare Tunnel
Pub/Sub needs a public HTTPS endpoint to push notifications. Cloudflare Tunnels provide this for free:
# Start a tunnel pointing to your local webhook server (port 8788)
cloudflared tunnel --url http://127.0.0.1:8788
You’ll see output like:
Your quick Tunnel has been created! Visit it at:
https://random-words-here.trycloudflare.com
Save this URL — you’ll need it for the Pub/Sub subscription.
Note: Free Cloudflare tunnel URLs change on restart. For production, consider a named tunnel with a stable subdomain.
5. Create the Pub/Sub Subscription
Now create a push subscription that sends notifications to your tunnel:
TUNNEL_URL="https://your-tunnel-url.trycloudflare.com"
SHARED_TOKEN="your-secret-token-here"
gcloud pubsub subscriptions create gmail-watch-push \
--topic gmail-watch \
--push-endpoint "${TUNNEL_URL}/?token=${SHARED_TOKEN}"
6. Start the Gmail Watch
With gog, starting a Gmail watch is simple:
# Start watching your inbox
gog gmail watch start \
--account your@gmail.com \
--label INBOX \
--topic projects/YOUR_PROJECT_ID/topics/gmail-watch
This tells Gmail to send notifications to your Pub/Sub topic whenever new emails arrive.
7. Run the Webhook Server
Now let’s run gog’s built-in webhook server to receive and forward notifications:
gog gmail watch serve \
--account your@gmail.com \
--bind 127.0.0.1 \
--port 8788 \
--path / \
--token "$SHARED_TOKEN" \
--hook-url http://127.0.0.1:3000/api/gmail \
--hook-token "your-app-secret" \
--include-body \
--max-bytes 20000
Key flags:
--token: Validates incoming Pub/Sub requests--hook-url: Where to forward processed emails--include-body: Include email body content (not just metadata)--max-bytes: Limit body size to avoid huge payloads
8. Build the AI Webhook Handler
Now for the fun part — the AI-powered webhook handler. Here’s a Next.js API route example:
// app/api/gmail/route.ts
const anthropic = new Anthropic();
interface EmailPayload {
from: string;
subject: string;
body: string;
snippet: string;
}
// Verify the webhook token
const authHeader = req.headers.get('authorization');
if (authHeader !== `Bearer ${process.env.GMAIL_HOOK_TOKEN}`) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
const payload: EmailPayload = await req.json();
// Use AI to classify and process the email
const analysis = await analyzeEmail(payload);
if (analysis.action === 'notify') {
await sendNotification(analysis.summary);
} else if (analysis.action === 'capture') {
await saveInsights(analysis.insights);
}
// 'ignore' action = do nothing
return NextResponse.json({ ok: true });
}
async function analyzeEmail(email: EmailPayload) {
const response = await anthropic.messages.create({
model: 'claude-sonnet-4-5-20250514',
max_tokens: 500,
messages: [{
role: 'user',
content: `Analyze this email and respond with JSON:
From: ${email.from}
Subject: ${email.subject}
Body: ${email.body?.slice(0, 2000) || email.snippet}
Respond with:
{
"action": "notify" | "capture" | "ignore",
"category": "urgent" | "newsletter" | "transactional" | "personal" | "spam",
"summary": "one-line summary if action is notify",
"insights": ["key insight 1", "key insight 2"] // if newsletter worth capturing
}
Rules:
- "notify" for urgent, personal, or time-sensitive emails
- "capture" for newsletters with valuable content
- "ignore" for receipts, shipping updates, marketing spam`
}]
});
const text = response.content[0].type === 'text' ? response.content[0].text : '';
return JSON.parse(text);
}
async function sendNotification(message: string) {
// Integrate with your preferred notification service
// e.g., Pushover, ntfy, Telegram, SMS, etc.
console.log('📬 Notification:', message);
}
async function saveInsights(insights: string[]) {
// Save to database, file, or note-taking app
console.log('💡 Captured insights:', insights);
}
9. Environment Variables
Set up your environment:
# .env.local
GMAIL_HOOK_TOKEN=your-app-secret
ANTHROPIC_API_KEY=your-anthropic-key
10. Testing the Pipeline
Send yourself a test email and watch the logs:
# In terminal 1: Cloudflare tunnel
cloudflared tunnel --url http://127.0.0.1:8788
# In terminal 2: gog webhook server
gog gmail watch serve --account your@gmail.com ...
# In terminal 3: Your Next.js app
npm run dev
When an email arrives, you should see:
- Pub/Sub pushes to your tunnel
gogfetches the email content- Your webhook receives the payload
- AI analyzes and categorizes
- Notification (or silence) based on importance
Customizing the AI Behavior
The real power is in customizing the AI prompt. Here are some ideas:
Strict Newsletter Filter
Only capture newsletters about: software development, AI/ML, startups, productivity.
Ignore: marketing, sales pitches, promotional content.
Smart Summarization
For captured newsletters, extract:
- Main argument or thesis
- Actionable takeaways
- Links worth saving
Priority Detection
Mark as urgent if:
- From a known VIP contact
- Contains words like "urgent", "ASAP", "deadline"
- Is a reply to your recent email
- Security-related (password reset, login alerts)
Production Considerations
Before running this in production:
-
Stable Tunnel URL: Use a named Cloudflare tunnel or alternative (ngrok with reserved domain, Tailscale Funnel)
-
Error Handling: Add retry logic and dead-letter queues for failed webhook processing
-
Rate Limiting: Gmail has API quotas — batch process during high-volume periods
-
Token Refresh:
goghandles OAuth token refresh, but monitor for auth failures -
Cost Management: Each AI call costs money — consider caching or batching for high-volume inboxes
Conclusion
You’ve now built an AI-powered email pipeline that:
- Monitors Gmail in real-time via Pub/Sub
- Filters out noise automatically
- Extracts insights from valuable content
- Only notifies you when it matters
The same pattern works for other use cases:
- Slack message filtering
- GitHub notification triage
- RSS feed summarization
- Any webhook-driven data source
Key Takeaways:
- Gmail Pub/Sub + webhooks = real-time without polling
gogCLI simplifies the Gmail integration- Cloudflare Tunnels provide instant public endpoints
- AI classification turns noise into signal
- The whole stack runs locally with minimal infrastructure
Experiment with different AI prompts to tune the filtering to your workflow. The goal is inbox zero without the manual triage.