Files
lettabot/docs/gmail-pubsub.md
Sarah Wooders 22770e6e88 Initial commit - LettaBot multi-channel AI assistant
Co-authored-by: Cameron Pfiffer <cameron@pfiffer.org>
Co-authored-by: Caren Thomas <carenthomas@gmail.com>
Co-authored-by: Charles Packer <packercharles@gmail.com>
Co-authored-by: Sarah Wooders <sarahwooders@gmail.com>
2026-01-28 18:02:51 -08:00

274 lines
7.9 KiB
Markdown

# Gmail Pub/Sub Integration
Receive email notifications and have your Letta agent process them automatically.
## Overview
```
┌─────────────┐ ┌──────────────┐ ┌─────────────────┐ ┌─────────────┐
│ Gmail │───▶│ Google Cloud │───▶│ LettaBot │───▶│ Letta │
│ Inbox │ │ Pub/Sub │ │ Webhook Server │ │ Agent │
└─────────────┘ └──────────────┘ └─────────────────┘ └──────┬──────┘
┌─────────────┐
│ Telegram │
└─────────────┘
```
When a new email arrives:
1. Gmail sends a notification to Google Cloud Pub/Sub
2. Pub/Sub pushes the notification to LettaBot's webhook
3. LettaBot fetches the email details via Gmail API
4. The email is sent to your Letta agent for processing
5. The agent's response is delivered to you on Telegram
## Prerequisites
- Google Cloud account with billing enabled
- Gmail account you want to monitor
- LettaBot running with a public URL (for Pub/Sub push)
- `gcloud` CLI installed ([install guide](https://cloud.google.com/sdk/docs/install))
## Setup Guide
### Step 1: Create a Google Cloud Project
1. Go to [Google Cloud Console](https://console.cloud.google.com/)
2. Create a new project or select an existing one
3. Note your **Project ID** (you'll need it later)
### Step 2: Enable Required APIs
```bash
# Set your project
gcloud config set project YOUR_PROJECT_ID
# Enable Gmail and Pub/Sub APIs
gcloud services enable gmail.googleapis.com pubsub.googleapis.com
```
### Step 3: Create OAuth2 Credentials
1. Go to [APIs & Services > Credentials](https://console.cloud.google.com/apis/credentials)
2. Click **Create Credentials** > **OAuth client ID**
3. Select **Desktop app** as the application type
4. Name it "LettaBot Gmail"
5. Download the JSON file
6. Note the **Client ID** and **Client Secret**
### Step 4: Get a Refresh Token
You need to authorize LettaBot to access your Gmail. Use this script:
```bash
# Install the Google auth library
npm install googleapis
# Run this script to get a refresh token
node -e "
const { google } = require('googleapis');
const readline = require('readline');
const oauth2Client = new google.auth.OAuth2(
'YOUR_CLIENT_ID',
'YOUR_CLIENT_SECRET',
'urn:ietf:wg:oauth:2.0:oob'
);
const authUrl = oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: ['https://www.googleapis.com/auth/gmail.readonly'],
});
console.log('Authorize this app by visiting:', authUrl);
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
rl.question('Enter the code: ', async (code) => {
const { tokens } = await oauth2Client.getToken(code);
console.log('Refresh Token:', tokens.refresh_token);
rl.close();
});
"
```
Save the **Refresh Token** - you'll need it for configuration.
### Step 5: Create Pub/Sub Topic and Subscription
```bash
# Create a topic for Gmail notifications
gcloud pubsub topics create lettabot-gmail
# Grant Gmail permission to publish to the topic
gcloud pubsub topics add-iam-policy-binding lettabot-gmail \
--member="serviceAccount:gmail-api-push@system.gserviceaccount.com" \
--role="roles/pubsub.publisher"
```
### Step 6: Configure LettaBot
Add these to your `.env` file:
```bash
# Enable Gmail integration
GMAIL_ENABLED=true
# Webhook server port (must be accessible from internet)
GMAIL_WEBHOOK_PORT=8788
# Shared secret for validating Pub/Sub requests (generate a random string)
GMAIL_WEBHOOK_TOKEN=your_random_secret_here
# OAuth2 credentials from Step 3
GMAIL_CLIENT_ID=your_client_id.apps.googleusercontent.com
GMAIL_CLIENT_SECRET=your_client_secret
# Refresh token from Step 4
GMAIL_REFRESH_TOKEN=your_refresh_token
# Your Telegram user ID (to receive email notifications)
# Find this by messaging @userinfobot on Telegram
GMAIL_TELEGRAM_USER=123456789
```
### Step 7: Expose Webhook to Internet
LettaBot's webhook server needs to be accessible from the internet for Pub/Sub to push notifications.
**Option A: Using Tailscale Funnel (recommended)**
```bash
tailscale funnel 8788
```
**Option B: Using ngrok**
```bash
ngrok http 8788
```
**Option C: Using Cloudflare Tunnel**
```bash
cloudflared tunnel --url http://localhost:8788
```
Note your public URL (e.g., `https://your-domain.ts.net` or `https://abc123.ngrok.io`).
### Step 8: Create Pub/Sub Push Subscription
```bash
# Replace with your actual public URL and token
gcloud pubsub subscriptions create lettabot-gmail-push \
--topic=lettabot-gmail \
--push-endpoint="https://YOUR_PUBLIC_URL/webhooks/gmail?token=YOUR_WEBHOOK_TOKEN" \
--ack-deadline=60
```
### Step 9: Start Gmail Watch
You need to tell Gmail to send notifications to your Pub/Sub topic. This watch expires after 7 days and needs to be renewed.
**Using the Gmail API directly:**
```bash
curl -X POST \
'https://gmail.googleapis.com/gmail/v1/users/me/watch' \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H 'Content-Type: application/json' \
-d '{
"topicName": "projects/YOUR_PROJECT_ID/topics/lettabot-gmail",
"labelIds": ["INBOX"]
}'
```
**Using a helper script:**
```javascript
// watch-gmail.js
const { google } = require('googleapis');
const oauth2Client = new google.auth.OAuth2(
process.env.GMAIL_CLIENT_ID,
process.env.GMAIL_CLIENT_SECRET
);
oauth2Client.setCredentials({ refresh_token: process.env.GMAIL_REFRESH_TOKEN });
const gmail = google.gmail({ version: 'v1', auth: oauth2Client });
async function startWatch() {
const res = await gmail.users.watch({
userId: 'me',
requestBody: {
topicName: 'projects/YOUR_PROJECT_ID/topics/lettabot-gmail',
labelIds: ['INBOX'],
},
});
console.log('Watch started:', res.data);
console.log('Expires:', new Date(parseInt(res.data.expiration)));
}
startWatch();
```
### Step 10: Start LettaBot
```bash
cd /path/to/lettabot
npm run dev
```
You should see:
```
Starting LettaBot...
Bot started as @your_bot
Gmail webhook enabled on port 8788
Gmail webhook server listening on port 8788
```
## Testing
1. Send a test email to your Gmail account
2. Check LettaBot logs for the notification
3. You should receive a Telegram message with the agent's summary
## Troubleshooting
### "Invalid token" error
- Make sure `GMAIL_WEBHOOK_TOKEN` matches the `?token=` in your Pub/Sub subscription
### No notifications received
- Verify your public URL is accessible: `curl https://YOUR_URL/health`
- Check Pub/Sub subscription for errors in Google Cloud Console
- Make sure Gmail watch is active (re-run the watch command)
### "User not authorized" error
- Ensure you granted `roles/pubsub.publisher` to `gmail-api-push@system.gserviceaccount.com`
### Watch expired
- Gmail watches expire after 7 days
- Set up a cron job to renew: `0 0 * * * node watch-gmail.js`
## Cleanup
To disable Gmail integration:
```bash
# Stop the watch
curl -X POST \
'https://gmail.googleapis.com/gmail/v1/users/me/stop' \
-H "Authorization: Bearer $(gcloud auth print-access-token)"
# Delete Pub/Sub resources
gcloud pubsub subscriptions delete lettabot-gmail-push
gcloud pubsub topics delete lettabot-gmail
# Remove from .env
# GMAIL_ENABLED=false
```
## Security Considerations
- Keep your `GMAIL_WEBHOOK_TOKEN` secret
- The refresh token grants read access to your Gmail - store it securely
- Consider using a service account for production deployments
- LettaBot only reads emails, it cannot send or modify them