Page stub. Full content lives in the
README — Outbound email.
- Dev —
StderrEmailSenderprints mail bodies (including the magic link) to stderr. No keys needed. - Production —
ResendEmailSender, used automatically when bothRESEND_API_KEYandHEXGATE_EMAIL_FROMare set.
Production config
HEXGATE_DASHBOARD_URL
controls the host inside the link the user clicks; misconfiguring it
sends users to localhost.
What gets sent
| Endpoint | Body link | |
|---|---|---|
POST /v1/auth/register | (none — verification is decoupled) | — |
POST /v1/auth/request-verify-token | ”Verify your Hexgate account” | {dash}/verify-email/{token} |
POST /v1/auth/forgot-password | ”Reset your Hexgate password” | {dash}/reset-password/{token} |
/v1/auth/verify and /v1/auth/reset-password
endpoints, respectively.
Failure handling
Provider failures (network, 5xx, invalid from-address) are logged at ERROR level but never 5xx the calling endpoint — the user gets a successful submit, the operator sees the log line, and the user can click “Resend email” on the verification banner. Same shape for password reset. Partial config (onlyRESEND_API_KEY set, no HEXGATE_EMAIL_FROM or
vice versa) is treated as dev mode and keeps StderrEmailSender —
better to surface “stderr sender active” at startup than to silently
have every send rejected by Resend at delivery time.
Testing
platform/api/tests/test_mailer.py covers the Resend sender in
isolation by patching resend.Emails.send. The auth-flow tests in
test_auth.py use a list-capturing sender via the outbox fixture so
they read the would-have-been-mailed token directly — no Resend in the
test loop.