mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-10-27 06:15:15 +00:00
Fixes connector docs. - **`authorization.url` examples.** They now show the URL the API actually returns (`/v3/connections/auth/redirect?state=…`), not provider URLs. - **Broken examples:** - TS `connectors.create` examples were missing commas. - Python dicts now use the SDK's snake_case keys. - `connector.createdAt` → `connector.system.createdAt`. - The list default `limit` is 10. - **Pending connectors.** They are visible through get (`pending_authorization`), just not in list. - **Gmail:** - It needs the Max plan. - Nothing syncs until labels are picked. - The watch covers the selected labels, not just INBOX. - `from` filters use `contains`. - **Smaller fixes:** - The OAuth redirect-URI troubleshooting. - Notion property metadata keys. - Picker error codes. Checked against the current API and the published SDKs (TS 5.0.1, Python 5.0.0). Legacy v3/v4 docs are unchanged apart from factual fixes. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
387 lines
13 KiB
Text
387 lines
13 KiB
Text
---
|
|
title: "Gmail connector"
|
|
sidebarTitle: "Gmail"
|
|
description: "Sync email threads from Gmail with real-time Pub/Sub webhooks and incremental sync"
|
|
icon: "/icons/hugeicons/mail-01.svg"
|
|
---
|
|
|
|
Connect Gmail to automatically sync email threads into your supermemory knowledge base. Supports real-time updates via Google Cloud Pub/Sub webhooks and incremental synchronization.
|
|
|
|
<Note>
|
|
**Max Plan Required:** The Gmail connector is available on Max plan and above.
|
|
</Note>
|
|
|
|
## Quick setup
|
|
|
|
### 1. Create Gmail Connector
|
|
|
|
<Tabs>
|
|
<Tab title="TypeScript">
|
|
```typescript
|
|
import { Supermemory } from "supermemory"
|
|
|
|
const supermemory = new Supermemory({ apiKey: process.env.SUPERMEMORY_API_KEY })
|
|
|
|
const connector = await supermemory.connectors.create("user-123", {
|
|
provider: "gmail",
|
|
redirectUrl: "https://yourapp.com/auth/gmail/callback",
|
|
documentLimit: 5000,
|
|
})
|
|
|
|
// Send the user to Google to authorize
|
|
if (connector.authorization) window.location.href = connector.authorization.url
|
|
console.log("Auth URL expires at:", connector.authorization?.expiresAt)
|
|
```
|
|
</Tab>
|
|
<Tab title="Python">
|
|
```python
|
|
from supermemory import Supermemory
|
|
import os
|
|
|
|
client = Supermemory(api_key=os.environ.get("SUPERMEMORY_API_KEY"))
|
|
|
|
connector = client.connectors.create(
|
|
"user-123",
|
|
request={
|
|
"provider": "gmail",
|
|
"redirect_url": "https://yourapp.com/auth/gmail/callback",
|
|
"document_limit": 5000,
|
|
},
|
|
)
|
|
|
|
# Send the user to Google to authorize
|
|
print(f"Redirect to: {connector.authorization.url}")
|
|
print(f"Auth URL expires at: {connector.authorization.expires_at}")
|
|
```
|
|
</Tab>
|
|
<Tab title="cURL">
|
|
```bash
|
|
curl -X POST "https://api.supermemory.ai/ns/user-123/connectors" \
|
|
-H "Authorization: Bearer $SUPERMEMORY_API_KEY" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"provider": "gmail",
|
|
"redirectUrl": "https://yourapp.com/auth/gmail/callback",
|
|
"documentLimit": 5000
|
|
}'
|
|
|
|
# Response: {
|
|
# "id": "PTzGiUYei7pgzg5buzZHgA",
|
|
# "authorization": {
|
|
# "url": "https://api.supermemory.ai/v3/connections/auth/redirect?state=...",
|
|
# "expiresAt": "2024-01-15T11:30:00.000Z"
|
|
# }
|
|
# }
|
|
```
|
|
</Tab>
|
|
</Tabs>
|
|
|
|
### 2. Handle OAuth callback
|
|
|
|
Send the user to `authorization.url` before `authorization.expiresAt`. After the user grants permissions, Supermemory sends them to a hosted label picker; once they choose labels, they return to your `redirectUrl` and the initial sync begins. Nothing syncs until at least one label is selected. A pending OAuth connector is not returned by list until the user finishes authorization; get returns it with `system.status: "pending_authorization"`.
|
|
|
|
To change the labels later, read the connector with `include: "picker"` and send the user to `picker.url`, or set label ids directly with `connectors.update(namespace, id, { selection: { labels: ["INBOX"] } })`. See [Managing Connector Selection](/connectors/managing-resources).
|
|
|
|
### 3. Check Connector Status
|
|
|
|
<Tabs>
|
|
<Tab title="TypeScript">
|
|
```typescript
|
|
// Get connector details with recent sync runs
|
|
const connector = await supermemory.connectors.get("user-123", "PTzGiUYei7pgzg5buzZHgA", {
|
|
include: "syncs",
|
|
})
|
|
|
|
console.log("Connected email:", connector.account)
|
|
console.log("Last sync:", connector.latestRun?.system.status)
|
|
console.log("Threads synced:", connector.documentCount)
|
|
|
|
// List synced email threads in the namespace
|
|
const docs = await supermemory.list("user-123", "documents")
|
|
|
|
console.log(`Synced ${docs.pagination.totalItems} email threads`)
|
|
```
|
|
</Tab>
|
|
<Tab title="Python">
|
|
```python
|
|
# Get connector details with recent sync runs
|
|
connector = client.connectors.get("user-123", "PTzGiUYei7pgzg5buzZHgA", include=["syncs"])
|
|
|
|
print(f"Connected email: {connector.account}")
|
|
print(f"Last sync: {connector.latest_run.system.status if connector.latest_run else 'never'}")
|
|
print(f"Threads synced: {connector.document_count}")
|
|
|
|
# List synced email threads in the namespace
|
|
docs = client.list("user-123", "documents")
|
|
|
|
print(f"Synced {docs.pagination.total_items} email threads")
|
|
```
|
|
</Tab>
|
|
<Tab title="cURL">
|
|
```bash
|
|
# Get connector details with recent sync runs
|
|
curl "https://api.supermemory.ai/ns/user-123/connectors/PTzGiUYei7pgzg5buzZHgA?include=syncs" \
|
|
-H "Authorization: Bearer $SUPERMEMORY_API_KEY"
|
|
|
|
# List synced email threads in the namespace
|
|
curl -X POST "https://api.supermemory.ai/ns/user-123/list/documents" \
|
|
-H "Authorization: Bearer $SUPERMEMORY_API_KEY" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{}'
|
|
```
|
|
</Tab>
|
|
</Tabs>
|
|
|
|
<Note>
|
|
There is no per-connector document list in v5. `supermemory.list(namespace, "documents")` returns every document in the namespace.
|
|
</Note>
|
|
|
|
## What gets synced
|
|
|
|
### Email threads
|
|
|
|
Gmail threads (conversations) are synced as individual documents with all messages included:
|
|
|
|
- **Thread content** converted to structured markdown
|
|
- **All messages** within each thread preserved in order
|
|
- **Message metadata**: subject, from, to, cc, bcc, date
|
|
- **HTML content** converted to clean markdown
|
|
- **Attachment metadata**: filename, mime type, size (attachments are referenced, not stored)
|
|
|
|
### Document metadata
|
|
|
|
Each synced thread includes searchable metadata:
|
|
|
|
| Field | Description |
|
|
|-------|-------------|
|
|
| `type` | Always `gmail_thread` |
|
|
| `subject` | Email subject line |
|
|
| `threadId` | Gmail thread ID |
|
|
| `from` | Sender, as the raw `From` header (for example `Team <team@company.com>`) |
|
|
| `to` | Recipient addresses, comma-separated |
|
|
| `date` | Date of first message |
|
|
| `messageCount` | Number of messages in thread |
|
|
| `attachmentCount` | Number of attachments (if any) |
|
|
| `attachmentNames` | List of attachment filenames |
|
|
|
|
You can filter searches using these metadata fields:
|
|
|
|
```typescript
|
|
const results = await supermemory.search("user-123", {
|
|
query: "project update",
|
|
filter: {
|
|
operator: "and",
|
|
operands: [
|
|
{ field: "type", operator: "eq", value: "gmail_thread" },
|
|
{ field: "from", operator: "contains", value: "team@company.com" },
|
|
],
|
|
},
|
|
searchMode: "chunks",
|
|
})
|
|
```
|
|
|
|
## Connector Management
|
|
|
|
### List All Connectors
|
|
|
|
<Tabs>
|
|
<Tab title="TypeScript">
|
|
```typescript
|
|
// List all connectors in a namespace
|
|
const { connectors } = await supermemory.connectors.list("user-123")
|
|
|
|
connectors.forEach(connector => {
|
|
console.log(`Provider: ${connector.provider}`)
|
|
console.log(`ID: ${connector.id}`)
|
|
console.log(`Account: ${connector.account}`)
|
|
console.log(`Created: ${connector.system.createdAt}`)
|
|
console.log(`Document limit: ${connector.documentLimit}`)
|
|
console.log("---")
|
|
})
|
|
```
|
|
</Tab>
|
|
<Tab title="Python">
|
|
```python
|
|
# List all connectors in a namespace
|
|
connectors = client.connectors.list("user-123").connectors
|
|
|
|
for connector in connectors:
|
|
print(f"Provider: {connector.provider}")
|
|
print(f"ID: {connector.id}")
|
|
print(f"Account: {connector.account}")
|
|
print(f"Created: {connector.system.created_at}")
|
|
print(f"Document limit: {connector.document_limit}")
|
|
print("---")
|
|
```
|
|
</Tab>
|
|
<Tab title="cURL">
|
|
```bash
|
|
# List all connectors in a namespace
|
|
curl "https://api.supermemory.ai/ns/user-123/connectors" \
|
|
-H "Authorization: Bearer $SUPERMEMORY_API_KEY"
|
|
```
|
|
</Tab>
|
|
</Tabs>
|
|
|
|
### Delete Connector
|
|
|
|
<Tabs>
|
|
<Tab title="TypeScript">
|
|
```typescript
|
|
// Delete the connector and its imported documents (default)
|
|
await supermemory.connectors.delete("user-123", "PTzGiUYei7pgzg5buzZHgA")
|
|
|
|
// Delete the connector but keep the imported documents
|
|
await supermemory.connectors.delete("user-123", "PTzGiUYei7pgzg5buzZHgA", {
|
|
deleteDocuments: false,
|
|
})
|
|
```
|
|
</Tab>
|
|
<Tab title="Python">
|
|
```python
|
|
# Delete the connector and its imported documents (default)
|
|
client.connectors.delete("user-123", "PTzGiUYei7pgzg5buzZHgA")
|
|
|
|
# Delete the connector but keep the imported documents
|
|
client.connectors.delete("user-123", "PTzGiUYei7pgzg5buzZHgA", delete_documents=False)
|
|
```
|
|
</Tab>
|
|
<Tab title="cURL">
|
|
```bash
|
|
# Delete the connector and its imported documents (default)
|
|
curl -X DELETE "https://api.supermemory.ai/ns/user-123/connectors/PTzGiUYei7pgzg5buzZHgA" \
|
|
-H "Authorization: Bearer $SUPERMEMORY_API_KEY"
|
|
|
|
# Delete the connector but keep the imported documents
|
|
curl -X DELETE "https://api.supermemory.ai/ns/user-123/connectors/PTzGiUYei7pgzg5buzZHgA?deleteDocuments=false" \
|
|
-H "Authorization: Bearer $SUPERMEMORY_API_KEY"
|
|
```
|
|
</Tab>
|
|
</Tabs>
|
|
|
|
<Note>
|
|
Deleting a connector will:
|
|
- Stop all future syncs from Gmail
|
|
- Remove the OAuth authorization
|
|
- Delete the synced documents unless you pass `deleteDocuments: false`
|
|
</Note>
|
|
|
|
### Manual sync
|
|
|
|
Trigger a manual synchronization. The call returns `409` while a sync for that connector is already running.
|
|
|
|
<Tabs>
|
|
<Tab title="TypeScript">
|
|
```typescript
|
|
const run = await supermemory.connectors.sync("user-123", "PTzGiUYei7pgzg5buzZHgA")
|
|
|
|
console.log(run.status)
|
|
// Output: queued
|
|
```
|
|
</Tab>
|
|
<Tab title="Python">
|
|
```python
|
|
run = client.connectors.sync("user-123", "PTzGiUYei7pgzg5buzZHgA")
|
|
|
|
print(run.status)
|
|
# Output: queued
|
|
```
|
|
</Tab>
|
|
<Tab title="cURL">
|
|
```bash
|
|
curl -X POST "https://api.supermemory.ai/ns/user-123/connectors/PTzGiUYei7pgzg5buzZHgA/sync" \
|
|
-H "Authorization: Bearer $SUPERMEMORY_API_KEY"
|
|
|
|
# Response: {"id": "PTzGiUYei7pgzg5buzZHgA", "status": "queued"}
|
|
```
|
|
</Tab>
|
|
</Tabs>
|
|
|
|
## Sync mechanism
|
|
|
|
Gmail connector supports multiple sync methods:
|
|
|
|
| Feature | Behavior |
|
|
|---------|----------|
|
|
| **Real-time sync** | Via Google Cloud Pub/Sub webhooks (7-day expiry, auto-renewed) |
|
|
| **Scheduled sync** | Every 4 hours |
|
|
| **Manual sync** | On-demand via API |
|
|
| **Incremental sync** | Uses Gmail `historyId` to fetch only changed threads |
|
|
|
|
### How real-time sync works
|
|
|
|
1. After labels are selected, supermemory registers a Gmail API "watch" subscription when Pub/Sub is configured
|
|
2. Gmail sends notifications to a Google Cloud Pub/Sub topic when emails change
|
|
3. supermemory receives these notifications and fetches updated threads
|
|
4. Watch subscriptions expire after 7 days and are automatically renewed
|
|
|
|
<Note>
|
|
Real-time sync monitors the selected labels, including labels outside **INBOX**. If multiple connectors use the same mailbox, its watch covers their combined label selections.
|
|
</Note>
|
|
|
|
## Permissions & scopes
|
|
|
|
The Gmail connector requests the following OAuth scopes:
|
|
|
|
| Scope | Purpose |
|
|
|-------|---------|
|
|
| `gmail.readonly` | Read-only access to Gmail messages and threads |
|
|
| `userinfo.email` | Access to user's email address for connector identification |
|
|
|
|
<Warning>
|
|
**Read-only Access:** The Gmail connector only reads emails. It cannot send, delete, or modify any emails in the user's account.
|
|
</Warning>
|
|
|
|
## Limitations
|
|
|
|
<Warning>
|
|
**Important Limitations:**
|
|
- **Plan requirement**: Requires Max Plan or above
|
|
- **INBOX only** for real-time sync: Only INBOX label triggers real-time updates; other labels sync via scheduled sync
|
|
- **Watch expiration**: Gmail watch subscriptions expire after 7 days (automatically renewed by supermemory)
|
|
- **Document limit**: Default limit is 10,000 threads per connector (configurable via `documentLimit` parameter)
|
|
- **Attachments**: Attachment metadata is stored, but attachment content is not downloaded
|
|
- **Rate limits**: Gmail API rate limits may affect sync speed for accounts with many emails
|
|
</Warning>
|
|
|
|
## Troubleshooting
|
|
|
|
### OAuth fails or missing refresh token
|
|
|
|
If OAuth fails or the connector stops syncing:
|
|
|
|
1. Delete the existing connector
|
|
2. Create a new connector
|
|
3. Ensure the user completes the full OAuth flow with consent
|
|
|
|
```typescript
|
|
// Re-create the connector to get fresh tokens
|
|
await supermemory.connectors.delete("user-123", "PTzGiUYei7pgzg5buzZHgA", {
|
|
deleteDocuments: false,
|
|
})
|
|
|
|
const next = await supermemory.connectors.create("user-123", {
|
|
provider: "gmail",
|
|
redirectUrl: "https://yourapp.com/auth/gmail/callback"
|
|
})
|
|
|
|
// User must re-authenticate
|
|
if (next.authorization) window.location.href = next.authorization.url
|
|
```
|
|
|
|
### Emails not syncing in real-time
|
|
|
|
If real-time sync isn't working:
|
|
|
|
- Scheduled sync (every 4 hours) and manual sync still work
|
|
- Real-time sync requires supermemory's Pub/Sub infrastructure
|
|
- Check if the connector was created recently (watch registration happens on creation)
|
|
- Trigger a manual sync to verify the connector is working
|
|
|
|
### Permission denied errors
|
|
|
|
If you see permission errors:
|
|
|
|
- Ensure the user granted the required Gmail scopes during OAuth
|
|
- Verify your organization has Max Plan or above access
|
|
- Check if the user revoked app access in their Google Account settings
|