Article
Supabase confirmation emails not arriving: the 2-per-hour limit and the custom SMTP fix
Published on
You tested signup a dozen times and the confirmation email always arrived. The app goes live, the first real users sign up, and the emails never come. Or they do for the first two people and then the app shows "email rate limit exceeded". Password resets go missing the same way.
Nothing is broken in your code. The project is still sending through the email service Supabase includes for testing, and that service is built to stop exactly here.
What the built-in email service does
Supabase's documentation is explicit about it:
- It only delivers to addresses in your project's team. Anyone else is refused. That is why it worked every time you tested with your own address.
- It sends 2 messages per hour, and Supabase says that number can change without notice.
- It has no delivery or uptime guarantee and is meant for trying out Auth, testing templates and demos, not for production.
So an app on the default service can confirm its builder and nobody else.
The error messages that point here
Depending on the call and the version, the app or the Auth logs show one of these:
email_address_not_authorized: "Email sending is not allowed for this address as your project is using the default SMTP service." The user is not on your team.over_email_send_rate_limit, often surfaced as "email rate limit exceeded": the hourly email limit is spent.- A 429 status on the signup or reset request: a rate limit was hit.
AI-built apps often swallow these errors and show a cheerful "check your inbox" anyway, so also look at the Auth logs in the Supabase dashboard, not only at the screen.
The fix: send through your own SMTP provider
Supabase Auth works with any email service that speaks SMTP. Its docs name Resend, AWS SES, Postmark, Twilio SendGrid, ZeptoMail and Brevo. The steps are the same with any of them:
- Create an account with the provider and add your domain. The provider gives you DNS records (SPF, DKIM, sometimes a return-path CNAME) to add where your domain's DNS lives. Wait until the provider shows the domain as verified.
- Get the SMTP details: host, port, username and password (often an API key used as the password).
- Enter them in Supabase: Authentication settings, SMTP, enable custom
SMTP. Set the sender to an address on the domain you just verified, such as
no-reply@example.com, and a sender name users will recognise. - Send a real test: sign up with an address outside your team, ideally on Gmail and on Outlook, and check that the email arrives and the link works.
Once custom SMTP is saved, Supabase sends to every address, but still applies a starting limit of 30 emails per hour. If you expect more signups than that, raise it on the Rate Limits page under Authentication. Supabase also waits 60 seconds before letting the same user request another confirmation, magic link or reset, so a user who taps "resend" twice will hit that and not the hourly limit.
Arrives, but in spam
Custom SMTP fixes delivery; landing in the inbox depends on the domain. The usual reasons a confirmation email goes to spam:
- The sender is a Gmail or Outlook address, or a domain you have not verified with the provider. Send from your own domain.
- SPF or DKIM records are missing or wrong. The provider's dashboard shows whether they pass. If the domain already sends mail from another service, merge the SPF records into one; two separate SPF records break both.
- No DMARC record. Gmail and Yahoo expect one from bulk senders; a basic
p=nonerecord at_dmarc.example.comis the minimum. - The template still looks like a default. A clear subject, your product name and a single obvious link help more than you would expect.
Lovable Cloud projects
If the app runs on Lovable Cloud rather than on a Supabase project you own, the auth email settings are not in a Supabase dashboard you can open. Look in Lovable under the Cloud section, Users, and Lovable's documentation on sending branded emails from your own domain. The principle is the same: production email has to go out from your own, verified domain.
Turning off confirmation is not the fix
The quick workaround the AI may suggest is switching off "Confirm email" so users get in without the email. It makes the symptom go away, but anyone can then sign up with any address, including someone else's, and password resets still need email. Use it while testing if you must, not in production.
When the email arrives but the link goes nowhere
If the email now arrives and the link sends users to localhost:3000 or to
the preview, that is a different setting: see Supabase login redirects to
localhost after deploy. And
if users confirm, log in and then hit permission errors on their first save,
the next stop is the "new row violates row-level security policy"
error.
Email is one of several things that only fail once real users arrive; the others are in why an app works in preview but not in production. If you would rather have someone check the whole path from signup to payment before launch, that is our vibe code rescue audit: 450 EUR, 48 working hours, a written report of what is broken and what each fix costs, with the fee deducted if you continue into the rescue (1,500-6,000 EUR, fixed scope).