Email setup
Auth Service sends e-mail with Nodemailer. E-mail is required whenever a flow that depends on it is active, and in production that is the case by default.
Configuration
SMTP_HOST=smtp.example.com
SMTP_PORT=587 # defaults to 587
SMTP_USER=user@example.com
SMTP_PASS=your-smtp-password
SMTP_FROM=Auth Service <no-reply@example.com>
MAIL_REPLY_TO=support@example.com # optional
Port 465 uses implicit TLS; every other port uses STARTTLS negotiation. Authentication is sent only when both SMTP_USER and SMTP_PASS are set; otherwise Nodemailer connects without authentication, which suits a local relay.
When SMTP is mandatory
With NODE_ENV=production (which the Compose stack forces):
REQUIRE_EMAIL_VERIFICATIONis on by default: a user cannot sign in before following the link sent to their address. The bundled Compose file and.env.exampleset it tofalse, so a Compose deployment verifies addresses only after you setREQUIRE_EMAIL_VERIFICATION=true.MAGIC_LINK_ENABLEDandEMAIL_OTP_ENABLEDadd passwordless sign-in by e-mail, for existing accounts only. Both are off by default.- If any of these three is on and
SMTP_HOSTis empty, the process refuses to start. - When
SMTP_HOSTis set, the SMTP connection is checked at startup, and a failure is fatal. Outside production it is only logged as a warning.
To run a production instance without e-mail, set REQUIRE_EMAIL_VERIFICATION=false explicitly. Without SMTP, e-mails are then dropped with a log line, which also means users cannot reset a forgotten password by themselves.
E-mails sent
| Trigger | Template |
|---|---|
| E-mail verification (sign-up, import, resend by an administrator) | verify-email.eml |
| "Forgot your password?" | reset-password.eml |
| Magic-link sign-in | magic-link.eml |
| One-time code sign-in | email-otp.eml |
| Invitation to an organization | org-invitation.eml |
| Invitation to register with an application | registration-invitation.eml |
| E-mail address change | change-email.eml |
Every template can be overridden globally with a file under <TEMPLATES_DIR>/default/emails/: see Custom templates. A per-application override (<TEMPLATES_DIR>/<appSlug>/emails/) is honoured for the e-mails that have an application context: registration-invitation, and the verification, password reset, change-email and magic-link e-mails when their link was issued for a request carrying that application's client_id.
Sending is rate limited per IP address to 5 requests per minute on the endpoints that send e-mail (MAIL_003, 429), and the credential endpoints (sign-in, sign-up, password reset, two-factor verification) to 10 per minute (RATE_001). Mailing a large user base at once, for example after a migration, should be spread over time.
Testing locally
The Compose file ships a mail catcher behind the mail profile:
docker compose --profile mail up -d
SMTP_HOST=mailpit
SMTP_PORT=1025
Every message sent by the stack then shows up in the Mailpit web interface at http://localhost:8025.
Custom templates
Override the login, register, verify-email, email-verified, select-org, two-factor, device, error and delegated billing pages (subscribe, invoices, billing-usage) per application, and the transactional emails globally, using the TEMPLATES_DIR environment variable.
Stripe integration
[object Object]