Email Delivery¶
Audience: Operators configuring LMS email delivery and support engineers diagnosing missing transactional email.
Scope: Provider selection, environment setup, production readiness, local testing, and troubleshooting. Architecture and event ownership live in Email System.
Delivery Modes¶
The LMS selects one delivery driver at process startup:
RESEND_API_KEYpresent: Resend.- Otherwise,
SMTP_HOSTpresent: SMTP. - Otherwise, when
NODE_ENVis notproduction: console. - Otherwise: startup/send configuration fails with
EmailNotConfiguredError.
Resend always takes precedence over SMTP. Restart or redeploy the LMS after changing email environment variables because the selected client is cached in-process.
Environment Variables¶
| Variable | Required | Purpose |
|---|---|---|
EMAIL_FROM |
Yes for external delivery | Sender mailbox, using a provider-authorized domain |
RESEND_API_KEY |
For Resend | Resend API credential |
SMTP_HOST |
For SMTP | SMTP server hostname |
SMTP_PORT |
For SMTP when required by server | SMTP port |
SMTP_USER |
For authenticated SMTP | SMTP username |
SMTP_PASSWORD |
For authenticated SMTP | SMTP password |
APP_BASE_DOMAIN |
Yes | Base host used for tenant routing and links |
These values are server-only. Never prefix them with NEXT_PUBLIC_, log credentials, or commit .env.local.
Resend Setup¶
- Add and verify the sending domain in the Resend account.
- Publish the DNS records Resend requests and wait for verification.
- Create an API key for the intended deployment environment.
- Set
EMAIL_FROMto a mailbox on the verified domain. - Set
RESEND_API_KEYand redeploy. - Trigger a transactional flow on the correct tenant host.
- Confirm an
email/sentstructured log, then use itsmessageIdin the Resend dashboard.
An API key and sender domain must belong to the same Resend account. A generic or unverified sender domain is rejected even when the key itself is valid.
SMTP Setup¶
- Leave
RESEND_API_KEYunset; otherwise Resend wins provider selection. - Set
SMTP_HOSTand the server's required port and credentials. - Set
EMAIL_FROMto an address the SMTP server permits. - Restart or redeploy the LMS.
- Trigger a transactional flow and inspect
email/sentoremail/failed.
TLS and relay behavior are controlled by the SMTP service configuration. Validate production requirements with the selected service before launch.
Local Development¶
For token-flow development, leave RESEND_API_KEY and SMTP_HOST unset. The non-production console driver logs:
- the full recipient address;
- subject and tags;
- links extracted from the rendered HTML and plaintext.
This output is intentionally more sensitive than normal structured email logs. Use it only in a local development environment and do not paste token links into tickets or shared logs.
To test rendered mail in a local inbox UI, use a local SMTP service such as Mailpit and configure SMTP_HOST/SMTP_PORT while leaving RESEND_API_KEY unset.
Production Readiness Checklist¶
EMAIL_FROMis authorized by the selected provider.- At least one external provider is configured; production cannot fall back to console.
- Resend and SMTP credentials are environment-specific and stored as secrets.
- Tenant auth links use the expected public host and HTTPS.
- Sign-up verification, forgot password, resend verification, magic link, email change, and admin invitation/reset flows have been smoke-tested.
- Invitation links resolve to
/invite/\[token\]. email/sentandemail/failedlogs are collected without exposing recipient addresses or tokens.- DNS authentication required by the provider is active.
Provider webhooks, bounce suppression, unsubscribe handling, and dedicated deliverability alerts are not implemented. Track those gaps in T-026 Email Platform Roadmap.
Troubleshooting¶
The UI says success, but no message arrives¶
Account-discovery flows deliberately use enumeration-safe responses. A successful response means the request was accepted, not that an account was found or a provider accepted a message.
Check in order:
- Tenant host: submit on the tenant host that owns the account. Unknown, suspended, apex, or different-tenant hosts may not be eligible.
- Account eligibility: the normalized address must match the tenant user. Forgot-password mail also requires a local password; OAuth-only users use their OAuth provider.
- Rate limit: repeated auth requests may be refused before delivery.
- Selected driver: a non-empty
RESEND_API_KEYoverrides SMTP and console. - Sender authorization: confirm
EMAIL_FROMis accepted by the selected provider. - Structured logs: find
email/sentoremail/failed. - Provider state: when
email/sentincludes amessageId, inspect that ID in the provider dashboard. - Inbox behavior: check spam/quarantine and provider-level suppression.
There is no email log¶
- Confirm the request reached an implemented email event.
- Confirm tenant and user eligibility.
- Check rate-limit logs.
- Check for an earlier action error.
The LMS does not write email_events records yet, so database inspection cannot currently prove whether a send was attempted.
EmailNotConfiguredError in production¶
Neither RESEND_API_KEY nor SMTP_HOST is configured. Set one provider and EMAIL_FROM, then redeploy. Production intentionally has no console fallback.
Resend rejects the sender¶
Confirm the exact domain in EMAIL_FROM is verified in the same Resend account as the active API key. After correcting environment values, redeploy before retesting.
SMTP is not selected¶
Unset RESEND_API_KEY, restart the process, and verify SMTP_HOST is non-empty. Provider selection is cached.
Logging And Data Handling¶
Normal send logs contain only the recipient domain, not the full address. They may include the subject, event tags, provider-neutral failure detail, and provider message ID. Keep subjects free of secrets and personal data.
The console driver is the exception: it logs full recipients and token-bearing links for local testing. It is unavailable as an automatic production fallback.