Supabase "email rate limit exceeded": the fix
Supabase's built-in email sender is for testing and allows only a few emails an hour. How custom SMTP raises the limit, and other ways to send sign-in codes.
You call signInWithOtp a few times while testing and get email rate limit exceeded. Nothing is broken. Supabase’s built-in email sender is a test service with a very small hourly limit, and production apps are expected to bring their own SMTP.
Why it happens
Supabase sends auth emails (sign-up confirmations, magic links, email OTP codes, password resets) through a built-in sender unless you configure your own. That sender:
- allows only a few emails an hour per project (2 an hour at the time of writing),
- is meant for development, not real users,
- may only deliver to addresses on your project team.
Every auth email type counts against the same limit, so two test sign-ins can use it up.
The fix: custom SMTP
- Pick an email provider: Amazon SES, ZeptoMail, Resend, Brevo, Postmark or SendGrid all work.
- Verify your sending domain with them (they give you DKIM and SPF records to add to DNS).
- In Supabase open Authentication, Emails, SMTP Settings, turn on custom SMTP, and enter the host, port, user and password from the provider.
- Open Authentication, Rate Limits and set the email limit you need.
Your emails now go through your provider, with your domain as the sender, and you pay that provider per email.
Sending a 6-digit code instead of a link
Supabase’s signInWithOtp sends a magic link by default. To send a code, edit the Magic Link email template to include {{ .Token }}, then verify the code the user types:
await supabase.auth.signInWithOtp({ email: "ananya@example.in" });
// later, with the code the user typed
const { data, error } = await supabase.auth.verifyOtp({
email: "ananya@example.in",
token: "482913",
type: "email",
});
Other ways to send sign-in codes
If you would rather not run SMTP, deliverability and templates yourself:
- Use an email OTP API that makes, sends and checks the code. SignOps Email OTP is two calls, send and verify, with 500 codes free to try and 1,000 a month on Starter. You verify the code on your server, then sign the user in to Supabase from there.
- Skip email for returning users. A passkey or a push approval on a phone they already use sends no email at all.
Sources: Supabase: send emails with custom SMTP, Supabase: passwordless email logins, SendLayer: Supabase custom SMTP guide.