Files
warmbly/resources/gmail.md
T
Máté Mészáros (Laptop) ed35ab2dbc Realtime Updates
2026-01-30 15:32:58 +01:00

154 lines
3.6 KiB
Markdown

# Gmail API Integration
Warmbly uses the Gmail API for Google Workspace and Gmail accounts, providing efficient incremental sync via the History API.
## Overview
The Gmail API offers advantages over IMAP:
- Incremental sync via History API
- Native label support
- Better rate limits
- Push notifications via Pub/Sub
## Authentication
### OAuth2 Flow
1. User initiates connection from frontend
2. Backend redirects to Google OAuth consent screen
3. User grants access with required scopes
4. Google redirects back with authorization code
5. Backend exchanges code for access/refresh tokens
6. Tokens stored encrypted in database
### Required Scopes
```
https://www.googleapis.com/auth/gmail.readonly # Read emails
https://www.googleapis.com/auth/gmail.send # Send emails
https://www.googleapis.com/auth/gmail.modify # Modify labels
https://mail.google.com/ # Full access (warmup)
```
### Token Refresh
Access tokens expire after 1 hour. The backend automatically refreshes using the stored refresh token.
## History API
The History API enables incremental synchronization by tracking changes since the last sync.
### Initial Sync
1. List all message IDs with `messages.list`
2. Batch fetch message metadata
3. Store the current `historyId`
### Incremental Sync
1. Call `history.list` with stored `historyId`
2. Process changes:
- `messagesAdded` - new messages
- `messagesDeleted` - deleted messages
- `labelsAdded` / `labelsRemoved` - label changes
3. Update stored `historyId`
### Example Response
```json
{
"history": [
{
"id": "700123",
"messagesAdded": [
{
"message": {
"id": "18a2b3c4d5e6",
"threadId": "18a2b3c4d5e6",
"labelIds": ["INBOX", "UNREAD"]
}
}
],
"labelsRemoved": [
{
"message": {"id": "18a2b3c4d5e6"},
"labelIds": ["UNREAD"]
}
]
}
],
"historyId": "700124",
"nextPageToken": "..."
}
```
## Sending Emails
### MIME Structure
Emails are sent as base64url-encoded MIME messages.
```
From: sender@example.com
To: recipient@example.com
Subject: Hello
Content-Type: multipart/alternative; boundary="boundary"
--boundary
Content-Type: text/plain; charset="UTF-8"
Plain text body
--boundary
Content-Type: text/html; charset="UTF-8"
<html><body>HTML body</body></html>
--boundary--
```
### Threading
To reply in a thread:
- Set `threadId` in the request
- Include `In-Reply-To` and `References` headers
## Labels
Gmail uses labels instead of folders. System labels have special IDs.
| Label | ID | Description |
|-------|-----|-------------|
| Inbox | INBOX | Primary inbox |
| Sent | SENT | Sent messages |
| Drafts | DRAFT | Draft messages |
| Trash | TRASH | Deleted messages |
| Spam | SPAM | Spam folder |
| Starred | STARRED | Starred messages |
| Unread | UNREAD | Unread flag |
## Rate Limits
Gmail API has per-user and per-project quotas:
| Quota | Limit |
|-------|-------|
| Queries per day | 1,000,000,000 |
| Queries per user per second | 250 |
| Batch requests | 100 requests per batch |
## Error Handling
| HTTP Status | Meaning | Action |
|-------------|---------|--------|
| 401 | Token expired | Refresh token |
| 403 | Rate limited | Exponential backoff |
| 404 | Message not found | Skip, may be deleted |
| 410 | History expired | Full resync required |
| 429 | Too many requests | Backoff and retry |
## Code References
- Gmail client: `internal/email/gmail.go`
- OAuth2 handling: `github.com/meszmate/google-go`
- Google API library: `google.golang.org/api/gmail/v1`