← back to Rentv 2026
docs/CRE_PR_EMAIL_SETUP.md
45 lines
# CRE PR Intelligence — Email Provider Setup (Gmail)
The email layer is an abstract provider interface (`src/pr/services/email-providers.js`)
with two implementations: **Gmail** (REST + OAuth2 refresh token) and **Mock** (active
automatically whenever Gmail is unconfigured — drafts are stored in memory, nothing can
send). Another provider (O365, SMTP/IMAP) can be added by implementing the same five
methods: `createDraft`, `send`, `listThreads`, `getThread`, `configured`.
## Behavior guarantees (enforced in code, not convention)
- Outreach drafts become **provider drafts** — never sent automatically.
- `send` requires `confirm:true` from an explicit admin click, re-checks the
suppression list at send time, and is audit-logged.
- Inbound sync associates replies by provider thread id → headers → recipient.
- Originals are preserved verbatim (`body_preserved`, `raw_headers`).
- Bounce/opt-out language in replies auto-flags status and writes `pr_suppression`.
- No tracking pixels — none exist anywhere in the letter renderer.
## Gmail configuration (env only — never in source control)
1. Google Cloud Console → create/select a project → enable the **Gmail API**.
2. OAuth consent screen: internal (Workspace) or external+test-user with the sending
account.
3. Credentials → **OAuth client ID** (Desktop app) → note client id + secret.
4. Mint a refresh token for the sending mailbox with scopes:
`https://www.googleapis.com/auth/gmail.compose https://www.googleapis.com/auth/gmail.readonly`
(gmail.compose covers draft creation + sending drafts; readonly covers thread sync).
The standard OAuth playground or a one-time local consent flow both work.
5. Set the environment (see `.env.example`):
```
PR_GMAIL_CLIENT_ID=…
PR_GMAIL_CLIENT_SECRET=…
PR_GMAIL_REFRESH_TOKEN=…
PR_GMAIL_USER=press@yourdomain.com
```
6. Restart the app + worker. Settings → Email provider should show **Gmail connected**.
## Verifying without sending
Create a draft from the Letter Builder → *Provider draft*. Check the Gmail account's
Drafts folder: the message sits there un-sent. The Send button in the Inbox is the only
path that transmits, and only with the confirm dialog.
## Token expiry note
Google "Testing"-mode OAuth apps expire refresh tokens after ~7 days — publish the app
(or keep it internal to a Workspace) for a durable token. If sync starts failing with
`invalid_grant`, re-mint the refresh token.