Which emails the app sends, the three mailers (SMTP, Resend, log only), and how email works locally.
Last updated
Two systems send email:
- Supabase Auth sends sign-in emails: confirmation, password reset, email change, magic link. Configure them in Supabase. See Email sign-in.
- The app sends everything else through
@repo/mailers(packages/mailers).
What the app sends
| Sent from | Template | |
|---|---|---|
| Team invitation | account-invitations-dispatcher.service.ts | invite.email.tsx |
| One-time code for a sensitive action (delete an account or team, transfer ownership) | packages/otp | otp.email.tsx |
| Confirmation after a personal account is deleted | delete-personal-account.service.ts | account-delete.email.tsx |
| Contact form message, to you | (marketing)/contact | Inline HTML in the server action |
| Showcase submission, to you | (marketing)/showcase | Inline HTML in the server action |
The templates are React Email components in packages/email-templates/src/emails/, with their text in packages/email-templates/src/locales/en/. The developer tool (http://localhost:3010, started by pnpm dev) has an emails page for previewing them.
Pick a mailer
MAILER_PROVIDER chooses how the app's emails go out:
| Value | Sends with | Needs |
|---|---|---|
nodemailer (default) | Any SMTP server | EMAIL_HOST, EMAIL_PORT, EMAIL_USER, EMAIL_PASSWORD, EMAIL_TLS (TLS stays on unless set to false). Node.js runtime only |
resend | Resend's HTTP API | RESEND_API_KEY |
log | Nothing. Logs the recipient's domain and the subject | Nothing |
Every email the app sends uses EMAIL_SENDER as the from address, for example "Your product <hello@yourdomain.com>". The contact form and showcase form need CONTACT_EMAIL, the address that receives them.
log is for places where email must not reach real inboxes, such as the live demo. It logs only the domain, not the full address, so logs do not collect what visitors typed.
Locally
apps/web/.env.development sets MAILER_PROVIDER=nodemailer and points it at the local Supabase stack's mail server on port 54325. Supabase Auth's local emails go to the same inbox. Open Mailpit at http://localhost:54324 to read everything that was sent.
How do you raise Supabase's auth email rate limit?
Set up custom SMTP for your Supabase project, then raise the limit on its Rate Limits page. Supabase lets you change that limit only once auth emails go through custom SMTP (or a Send Email hook), not its built-in sender.
As of October 2026, the built-in sender is for testing only: it delivers just to members of your Supabase organisation's team, at 2 emails an hour. Confirmation, password reset and magic link emails to anyone else fail until you add your own SMTP server.
- Pick a sending service that offers SMTP. Resend does, and Supabase's guide lists others.
- In the Supabase dashboard, open the project's Authentication settings, turn on custom SMTP, and enter the host, port, user, password and sender address.
- Save. Supabase now sends to every address, starting at a low limit of 30 emails an hour.
- Open Authentication > Rate Limits and raise the limit on emails sent to what your sign-ups need. The Management API sets the same value as
rate_limit_email_sent.
Locally none of this applies: apps/web/supabase/config.toml sets email_sent = 1000 under [auth.rate_limit], and Mailpit catches everything. Supabase's custom SMTP guide and rate limits page have the current numbers.
Add another provider
Add the name to packages/mailers/core/src/provider-enum.ts and register a factory for it in packages/mailers/core/src/registry.ts that returns an object with sendEmail(). The log mailer in that file is a short example.