# Gmail outreach reference

How Trinity separates Gmail OAuth, mailbox readiness, aliases, draft creation, sends, replies, ingestion, and approvals.

Status: implemented
Version: latest
Review: source-backed

## Gmail role

Gmail is the outreach and reply rail. Trinity treats OAuth, account mailbox connection, project alias selection, draft creation, approved send execution, inbox ingestion, labels, attachments, and replies as separate governed stages.

The current architecture is deliberately not a single global Gmail account. Trinity has one platform Google OAuth app, each account connects its own mailbox, and each project selects the account-owned sending alias it may use. Project secrets do not ask users for Gmail OAuth client secrets, mailbox tokens, or refresh tokens.

| Stage | Record or module | Gate |
| --- | --- | --- |
| Platform OAuth app | Fly/env Google OAuth client settings | Deployment-level app configuration, never project secrets |
| Account OAuth/mailbox | `GoogleOAuthController`, `GmailMailbox`, `TokenStore` | Connected account, required scopes, vault-backed token refs |
| Alias readiness | `SendingAlias` | Active alias, account ownership, send cap, owner/team policy |
| Project binding | `ProjectGmailSetting` | Project chooses an account-owned mailbox/alias and fails closed if missing |
| Draft creation | `GmailClient.users.drafts.create` through `GmailAdapter` | Project scope, alias readiness, ToolRouter, safety review where needed |
| Approved send/reply | `GmailClient.users.drafts.send` or `users.messages.send` | `LIVE_OUTREACH`, project alias, suppression, approval, idempotency |
| Thread/list/label work | `GmailClient` thread and label endpoints | Account/mailbox token, project/account scope, ToolRouter policy |
| Ingestion | `GmailPollWorker`, `ThreadIngestor`, threads/messages | Content quarantine and source metadata |
| Attachments | `EmailAttachment` and storage refs | Metadata first; body release requires human review |

## Token and project boundary

| Boundary | Stored in Postgres | Stored in credential vault |
| --- | --- | --- |
| OAuth connection | Provider subject, email, scopes, status, token secret refs, expiry | Access token and refresh token values |
| Gmail mailbox | Account id, OAuth connection id, email, provider subject, history id, status | No token values |
| Sending alias | Account id, mailbox id, alias email, caps, status | No token values |
| Project Gmail setting | Account id, project id, mailbox id, alias id, send mode, ingestion mode | No token values |
| ToolRouter/Gmail result | Draft id, message id, thread id, alias id, mailbox id, project setting id | No token values |

Access tokens are resolved by `TokenStore.access_token_for_mailbox/3`. Expired access tokens refresh server-side using the stored refresh-token ref and update only safe OAuth metadata. Legacy local `file://` token refs remain readable for local/dev continuity, but configured environments use the credential vault.

## Required Gmail scopes

Trinity needs enough Gmail API authority to do the work an approved operator can do: create drafts, send approved mail, read and ingest relevant threads, modify thread labels, and preserve reply context. The scopes are requested deliberately by the Google OAuth flow and are documented here because Google classifies several Gmail scopes as sensitive or restricted.

| Scope | Why Trinity needs it |
| --- | --- |
| `https://www.googleapis.com/auth/gmail.compose` | Create and manage Gmail drafts for human review. |
| `https://www.googleapis.com/auth/gmail.send` | Send approved direct messages or approved existing drafts. |
| `https://www.googleapis.com/auth/gmail.modify` | Read, compose, send, and modify mailbox state without requesting full-delete `mail.google.com` authority. |
| `https://www.googleapis.com/auth/gmail.readonly` | Read messages/settings needed for ingestion, reply matching, and source refs. |
| `https://www.googleapis.com/auth/gmail.labels` | See and edit labels used for thread state and workflow tracking. |
| `https://www.googleapis.com/auth/userinfo.email` | Bind the OAuth identity to the connected mailbox email. |
| `https://www.googleapis.com/auth/userinfo.profile` | Store safe account profile metadata for connection display. |

Google recommends using the narrowest scopes that support the application. Trinity intentionally does not request `https://mail.google.com/`, which grants broader mailbox authority including permanent deletion behavior. Because Trinity stores token-backed access on the server, production Google app review may require OAuth verification and restricted-scope security assessment depending on the final consent-screen status and scope classification.

## Gmail API calls currently wired

| Operation | Gmail endpoint | Trinity path |
| --- | --- | --- |
| Create draft | `users.drafts.create` | `GmailClient.create_draft/2` through ToolRouter/GmailAdapter |
| Send existing draft | `users.drafts.send` | `GmailClient.send_email/2` with `gmail_draft_id` |
| Send composed message | `users.messages.send` | `GmailClient.send_email/2` without a draft id |
| List threads | `users.threads.list` | `GmailClient.list_threads/2` |
| Get thread | `users.threads.get` | `GmailClient.get_thread/2` |
| Modify labels | `users.threads.modify` | `GmailClient.modify_labels/2` |

## Outreach safety

Hermes may draft or propose replies, but live sends require provider readiness, content safety, approval, idempotency, and ToolRouter execution. Inbound email and attachments remain quarantine-aware so indirect prompt injection cannot enter Hermes context before human release.

Project-scoped Gmail execution fails closed when the project has no active Gmail setting. This prevents Hermes or a user action from accidentally using another account or project mailbox.

## Primary source links

- [Gmail API scopes](https://developers.google.com/workspace/gmail/api/auth/scopes)
- [Gmail drafts guide](https://developers.google.com/workspace/gmail/api/guides/drafts)
- [Gmail sending guide](https://developers.google.com/workspace/gmail/api/guides/sending)
- [Gmail drafts.create reference](https://developers.google.com/workspace/gmail/api/reference/rest/v1/users.drafts/create)
- [Gmail drafts.send reference](https://developers.google.com/workspace/gmail/api/reference/rest/v1/users.drafts/send)
- [Gmail messages.send reference](https://developers.google.com/workspace/gmail/api/reference/rest/v1/users.messages/send)
- [Gmail threads.modify reference](https://developers.google.com/workspace/gmail/api/reference/rest/v1/users.threads/modify)
- [Security and governance](/docs/security-governance)


Source paths:
- `lib/autonomous_agency/email.ex`
- `lib/autonomous_agency/google/oauth.ex`
- `lib/autonomous_agency/google/token_store.ex`
- `lib/autonomous_agency/email/gmail_client.ex`
- `lib/autonomous_agency/email/gmail_mailbox.ex`
- `lib/autonomous_agency/email/sending_alias.ex`
- `lib/autonomous_agency/email/project_gmail_setting.ex`
- `lib/autonomous_agency/email/email_draft.ex`
- `lib/autonomous_agency/email/email_message.ex`
- `lib/autonomous_agency/email/email_attachment.ex`
- `lib/autonomous_agency/tools/gmail_adapter.ex`
- `lib/autonomous_agency/workers/gmail_send_worker.ex`
- `lib/autonomous_agency/workers/gmail_poll_worker.ex`
- `priv/repo/migrations/20260629185000_create_project_gmail_settings.exs`
