# Gmail Mailbox Connector — Setup Guide

## Prerequisites

- [ ] Google Cloud project with Gmail API enabled
- [ ] OAuth2 client ID and client secret (from Google Cloud Console → APIs & Services → Credentials)
- [ ] OAuth2 refresh token obtained via the consent flow (the mailbox owner must authorize the app)
- [ ] Gmail label created for tenant isolation (format: `TENANT/{TenantName}`)
- [ ] The `[gmail]` extra installed: `uv add entr-adapter-core[gmail]`

## Configuration

Add these settings to your adapter's `config.py` (Pydantic settings model) and `.env`:

| Env Var | Type | Required | Example | Description |
|---------|------|----------|---------|-------------|
| `GMAIL_CLIENT_ID` | str | Yes | `123456.apps.googleusercontent.com` | OAuth2 client ID from Google Cloud Console |
| `GMAIL_CLIENT_SECRET` | str | Yes | `GOCSPX-abc123` | OAuth2 client secret from Google Cloud Console |
| `GMAIL_REFRESH_TOKEN` | str | Yes | `1//0abc-def` | Long-lived refresh token from OAuth2 consent flow |
| `TENANT_NAME` | str | Yes | `Acme` | Tenant identifier, maps to Gmail label `TENANT/{TENANT_NAME}` |

**In `config.py`:**

```python
from pydantic_settings import BaseSettings
from entr_adapter_core.config import CoreSettings

class Settings(CoreSettings):
    TENANT_NAME: str
    GMAIL_CLIENT_ID: str
    GMAIL_CLIENT_SECRET: str
    GMAIL_REFRESH_TOKEN: str
```

**In `.env`:**

```env
TENANT_NAME=Acme
GMAIL_CLIENT_ID=123456789.apps.googleusercontent.com
GMAIL_CLIENT_SECRET=GOCSPX-your-secret-here
GMAIL_REFRESH_TOKEN=1//0your-refresh-token
```

### Using GmailConnectorConfig (alternative)

Instead of exposing settings as env vars, you can use the built-in Pydantic config model:

```python
from entr_adapter_core.connectors.gmail import GmailConnectorConfig

gmail_config = GmailConnectorConfig(
    tenant_name=settings.TENANT_NAME,
    gmail_client_id=settings.GMAIL_CLIENT_ID,
    gmail_client_secret=settings.GMAIL_CLIENT_SECRET,
    gmail_refresh_token=settings.GMAIL_REFRESH_TOKEN,
    # Optional:
    label_override="CUSTOM/Label",  # Override default TENANT/{tenant_name}
    max_results_per_page=100,       # Default: 500
)
```

## Registration

Wire the Gmail connector as a retrieval handler in your adapter's `main.py`:

```python
from entr_adapter_core.app import create_adapter_app
from entr_adapter_core.connectors.gmail import EntrMailboxRetrievalHandler
from app.config import Settings, get_settings
from app.handlers.my_handler import MyHandler

settings = get_settings()

# Create the retrieval handler
gmail_retriever = EntrMailboxRetrievalHandler(settings)

# Register with your process handler
handlers = {
    "my-adapter": MyHandler(
        settings=settings,
        retrieval_handler=gmail_retriever,
    ),
}

app = create_adapter_app(handlers=handlers, settings=settings)
```

## Verification

**1. Check connector initialization (startup logs):**

```
INFO  Initialized EntrMailboxRetrievalHandler for tenant: Acme
```

**2. Trigger a list_documents call via the API:**

```bash
curl -X POST http://localhost:8096/list_documents \
  -H "Content-Type: application/json" \
  -d '{"adapter_identifier": "my-adapter", "source_identifier": "gmail", "date_from": "2026-01-01"}'
```

**3. Expected success response:**

```json
{"status": "success", "message": "Found 5 emails for tenant 'TENANT/Acme'.", "documents": [...]}
```

**4. Common failure modes:**

| Error | Cause | Fix |
|-------|-------|-----|
| `OAuth token refresh failed` | Invalid or expired refresh token | Re-run the OAuth2 consent flow to get a new refresh token |
| `Gmail label 'TENANT/Acme' not found` | Label doesn't exist in Gmail | Create the label in Gmail: Settings → Labels → Create |
| `Could not list Gmail labels` | Gmail API not enabled or insufficient scopes | Enable Gmail API in Google Cloud Console |
| `ImportError: The Gmail connector requires the 'httpx' package` | Missing extra | Run `uv add entr-adapter-core[gmail]` |

## Common Pitfalls

1. **Token expiry**: Refresh tokens can be revoked if the Google Cloud project's OAuth consent screen is in "testing" mode and the token is >7 days old. Move to "production" status to get persistent tokens.
2. **Label case sensitivity**: Gmail labels are case-sensitive. `TENANT/Acme` is different from `TENANT/acme`.
3. **Rate limits**: Gmail API allows ~100 requests per minute per user. For high-volume mailboxes, reduce `max_results_per_page` and increase polling interval.
4. **Large attachments**: Gmail's raw format includes base64-encoded attachments. Emails with large attachments can be >25MB. Ensure adequate memory.
5. **Shared mailboxes**: The refresh token must be granted by the mailbox owner. For shared mailboxes, use a service account with domain-wide delegation.

## Client Onboarding Template

Send this checklist to the client's IT team before integration:

- [ ] **Google Workspace admin access** — needed to enable Gmail API and create OAuth credentials
- [ ] **Dedicated Gmail account or shared mailbox** — which email address will ENTR monitor?
- [ ] **Gmail label created** — create label `TENANT/{ClientName}` in the monitored mailbox
- [ ] **OAuth2 consent** — the mailbox owner must authorize the ENTR application (one-time)
- [ ] **Allowed sender domains** — which email domains should be processed? (for filtering)
- [ ] **Gmail API enabled** — in Google Cloud Console → APIs & Services → Library → Gmail API
- [ ] **OAuth2 credentials** — create OAuth2 client ID (Desktop app type) and share client ID + secret
- [ ] **Label naming convention** — confirm the label format (`TENANT/{ClientName}`)
