Files
Keysat 47dfd110a0 Add Gmail-DWD send path for the digest mailer (v0.1.0:76)
The box's existing service-account domain-wide-delegation grant already includes
gmail.compose, which authorizes users.messages.send — verified 2026-06-15 by a
token-mint probe and a live messages.send to grant. So CRM-originated mail can
send through the account that already powers email capture: no SMTP account, no
app password, no admin change.

- backend/email_integration/gmail_send.py: send_via_gmail() impersonates a
  domain user and POSTs users.messages.send (reuses credentials.py + the compose
  scope; mirrors compose.py's REST pattern).
- backend/digest_mailer.py: send_digest() prefers Gmail DWD when enabled, falls
  back to smtp_send otherwise. Sender = CRM_DIGEST_SENDER else first active admin.
- server.py: the admin test endpoint now routes through digest_mailer (so the
  Settings button sends via DWD on the box with zero SMTP config). Recipient
  restriction to the admin set and no-leak error handling preserved.
- test_gmail_send.py: build/send + transport routing (provider + urlopen faked).
  19/19 backend green; s9pk typechecks.

SMTP (v75) stays as the fallback transport. Send-path decision + scope finding
recorded in ROADMAP.md and AGENTS.md.
2026-06-15 20:17:27 -05:00

26 lines
1.4 KiB
TypeScript

import { VersionInfo } from '@start9labs/start-sdk'
// Digest send path via Gmail domain-wide delegation. Code-only, no schema change
// (migrations are no-ops):
// * The DWD grant on this deployment already includes the gmail.compose scope
// (verified 2026-06-15: token mint + a live messages.send both succeed), and
// gmail.compose authorizes users.messages.send. So CRM-originated mail can go
// through the existing service account — no SMTP account / app password.
// * backend/email_integration/gmail_send.py: send_via_gmail() impersonates a
// domain user and POSTs users.messages.send (mirrors compose.py's REST path).
// * backend/digest_mailer.py: send_digest() prefers Gmail DWD when enabled and
// falls back to smtp_send when not. The admin POST /api/admin/digest/test-email
// and the Settings "Send Test Digest Email" button route through it.
// * Sender for the DWD path is CRM_DIGEST_SENDER, else the first active admin.
export const v_0_1_0_76 = VersionInfo.of({
version: '0.1.0:76',
releaseNotes: {
en_US: [
'The daily-digest mailer can now send through the Gmail account the CRM already uses for email',
'capture (domain-wide delegation) — no separate SMTP account or app password needed. SMTP stays',
'available as a fallback.',
].join(' '),
},
migrations: { up: async () => {}, down: async () => {} },
})