Skip to main content
The platform mails verification and password-reset links through Resend. Two senders, picked at boot:
  • DevStderrEmailSender prints mail bodies (including the magic link) to stderr. No keys needed.
  • ProductionResendEmailSender, used automatically when both RESEND_API_KEY and HEXGATE_EMAIL_FROM are set.

Production config

The from-address must live on a verified domain in your Resend account — see Resend → Domains. HEXGATE_DASHBOARD_URL controls the host inside the link the user clicks; misconfiguring it sends users to localhost.

What gets sent

Both link routes are pre-mounted on the dashboard and consume the token via the FastAPI-Users /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 (only RESEND_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.