fix(email): support a delegated-mailbox alias distinct from the delegated Workspace account
Real-world case found during setup: the sending address ([email protected]) is an alias of an existing Workspace user, not its own paid seat (a deliberate cost-saving choice). Domain-wide delegation authorizes a real Workspace ACCOUNT, not an arbitrary alias string, so using the alias directly as the delegated 'sub' claim would have been wrong. Added GOOGLE_DELEGATED_USER (the account that actually owns the alias and was granted delegation) as an optional override, falling back to EMAIL_FROM_ADDRESS unchanged when the sending address is itself a primary account. EMAIL_FROM_ADDRESS remains the visible From: header in both cases. Documented in docs/RUNBOOK_GOOGLE_WORKSPACE_EMAIL.md with a concrete example.
This commit is contained in:
@@ -1,6 +1,16 @@
|
||||
// Phase 5C §2 — the Google Workspace adapter. Sends via the Gmail API
|
||||
// (users.messages.send), authenticated as a Google Cloud service account using Workspace
|
||||
// domain-wide delegation to impersonate a dedicated sending mailbox (EMAIL_FROM_ADDRESS).
|
||||
// domain-wide delegation to impersonate a Workspace user.
|
||||
//
|
||||
// GOOGLE_DELEGATED_USER vs. EMAIL_FROM_ADDRESS — two different things, deliberately kept
|
||||
// separate: domain-wide delegation authorizes the service account to act as one real Workspace
|
||||
// USER ACCOUNT (the "sub" claim below) — if the sending address is an ALIAS of a real account
|
||||
// rather than its own paid seat (a deliberate cost-saving choice, not a mistake), the delegated
|
||||
// user must be the ALIAS'S OWNER (the real account it belongs to), not the alias string itself.
|
||||
// EMAIL_FROM_ADDRESS is only ever the visible From: header — Gmail lets any account send as its
|
||||
// own verified aliases, so this can safely be the alias while GOOGLE_DELEGATED_USER is the real
|
||||
// account underneath it. If the sending address IS a primary account already,
|
||||
// GOOGLE_DELEGATED_USER can be left unset and this falls back to EMAIL_FROM_ADDRESS.
|
||||
//
|
||||
// WHY this mechanism, not SMTP or a human login: Google's own guidance for a backend
|
||||
// application sending mail as a specific Workspace address is a service account + domain-wide
|
||||
@@ -42,8 +52,8 @@ function loadServiceAccount() {
|
||||
// implements.
|
||||
async function getAccessToken() {
|
||||
const sa = loadServiceAccount();
|
||||
const impersonate = process.env.EMAIL_FROM_ADDRESS;
|
||||
if (!impersonate) throw configError('EMAIL_FROM_ADDRESS is not set (required as the delegated-user "sub" claim)');
|
||||
const impersonate = process.env.GOOGLE_DELEGATED_USER || process.env.EMAIL_FROM_ADDRESS;
|
||||
if (!impersonate) throw configError('Set GOOGLE_DELEGATED_USER (or EMAIL_FROM_ADDRESS if the sending address is itself a primary account) — required as the delegated-user "sub" claim');
|
||||
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const header = Buffer.from(JSON.stringify({ alg: 'RS256', typ: 'JWT' })).toString('base64url');
|
||||
|
||||
Reference in New Issue
Block a user