A customer cannot finish signup or reset a password because the email never arrives. If the request returned HTTP 429 with over_email_send_rate_limit, Supabase Auth rejected an email-sending request before delivery completed. The same error code can describe two different limits. If you increase a setting before you identify the limit, the incident can continue.
You may only know that the email did not arrive, and you may not have a captured 429. In that case, this article is not enough to identify a rate-limit incident.
We checked each platform claim in this article against the Supabase documentation and the current Auth source on 2026-09-24. App Rescue Desk is independent and is not affiliated with Supabase.
TL;DR
over_email_send_rate_limitcan come from the project-wide email limit or the per-user frequency window.- In the current Auth source, the error message identifies the path. The error code alone does not.
- Before you change SMTP or rate limits, do three checks: capture the response, filter the Auth logs, and read the current Auth settings.
If you already captured the error, go to Confirm which layer fired.
What you see
Signup, recovery, resend, magic-link, and OTP flows can return HTTP 429 when an Auth rate limit rejects the request. Supabase documents 429 Too Many Requests for breached Auth rate limits in its error-code guide and rate-limit guide.
The email-specific code is:
over_email_send_rate_limit
The current Auth source uses two relevant messages:
email rate limit exceeded
or:
For security purposes, you can only request this after 56 seconds.
The number of seconds varies. The current Auth mail source calculates the remaining wait time for the per-user frequency check.
For API version 2024-01-01 and later, the current Auth error handler returns API errors as JSON with code and message. When an error code exists, it also sets the x-sb-error-code response header. The Auth OpenAPI definition marks rate-limit responses as HTTP 429 (Auth error handler, Auth OpenAPI).
A customer report such as “I never got the email” is weaker evidence. Delivery can fail after Auth accepts the request. Other failures that are not rate limits can also cause the same symptom.
Why the obvious fixes check the wrong layer
Custom SMTP does not identify the limit
Custom SMTP changes the delivery path and the project-wide email limit. It does not tell you whether the per-user frequency window rejected the request.
Supabase documents a built-in email limit of 2 messages per hour per project. When you use custom SMTP or the Send Email hook, the project email limit becomes configurable (rate limits).
Disabled email confirmation changes signup behavior
If you turn off Confirm Email, the symptom can stop, because signup does not wait for a confirmation email. This change does not identify the original failure.
Supabase documents that when Confirm Email is off, Auth treats the address as confirmed and does not verify ownership in the normal confirmation flow (general Auth configuration).
The error-code description is narrower than the current source
Supabase’s public error table describes over_email_send_rate_limit as too many emails sent to one address. The current Auth source also returns that code when the project-wide email limiter rejects a send.
For incident diagnosis, use the message and request context as well as the code.
One code, two limits
| Evidence | Supported interpretation | Does not prove |
|---|---|---|
429 + email rate limit exceeded |
Project-wide email limit rejected the send | Which caller used the available email budget |
429 + seconds message |
Per-user frequency window rejected the request | That raising the project-wide limit will help |
No 429; SMTP, hook, or provider error |
Delivery path needs investigation | That an Auth email rate limit fired |
| Repeated matching requests in Auth logs | The endpoint received repeated calls | That one browser or user caused every call |
Project-wide email limit
Supabase documents the built-in provider at 2 emails per hour per project. Custom SMTP starts with a low project limit that you can adjust. The Send Email hook also uses the configurable project email limit (rate limits, custom SMTP).
All email-sending Auth flows share this project-level budget.
The documentation gives the rate per hour. It does not give a fixed reset time, and this article does not give one.
Per-user frequency window
Supabase documents a default 60-second window before another signup confirmation, password reset, OTP, or magic-link request for the same user (rate limits).
The current Auth source checks this frequency before it calls the email-sending function for confirmation, recovery, and magic-link flows. The project-wide limiter runs inside the email-sending function. In those source paths, if the frequency check rejects a request, the request returns before the project-wide email limiter runs (Auth mail source).
Raising the project-wide email limit does not change this separate frequency setting.
Send Email hook requests still meet the project limiter first
The current Auth source applies the project email limiter before it enters the Send Email hook branch. Supabase’s rate-limit documentation also says the project email limit is configurable when the Send Email hook is in use (Auth mail source, rate limits).
A hook can replace SMTP delivery, but it does not remove this project-level check.
Delivery failure is a different path
Supabase’s default email service is for testing. It only sends to pre-authorized organization addresses and has no delivery SLA. Sends to other addresses fail with email_address_not_authorized. They do not fail with over_email_send_rate_limit (custom SMTP, error codes).
With custom SMTP, provider credentials, provider limits, domain configuration, or provider availability can fail independently of the Auth rate limit.
If you use the Send Email hook, examine the hook path instead of SMTP. Supabase documents that the hook replaces SMTP when you enable it (Send Email hook).
Confirm which layer fired
Use read-only checks first. Do not change a live Auth setting until the evidence shows one layer.
1. Capture the response
Open the failing request in browser DevTools.
Record:
- HTTP status
codemessagex-sb-error-code, if present- request path
- timestamp and timezone
Do not copy access tokens, cookies, passwords, or email credentials into the incident note.
A captured 429 with the code and message is stronger evidence than the customer’s inbox symptom.
2. Filter Auth logs for the same time range
Open Supabase Logs.
- Set the incident time range.
- Select
Authas the Log Type. - Set Status to
429. - Set Method to
POST. - Filter Pathname to the failing Auth endpoint.
- Examine the matching rows.
Supabase documents these filters in Logs in Studio.
The relevant email paths include:
/auth/v1/signup
/auth/v1/recover
/auth/v1/resend
/auth/v1/magiclink
/auth/v1/otp
These paths are listed in Supabase’s rate-limit documentation.
Many matching requests in a short time range are evidence of repeated calls. They do not prove that one user or one browser sent every request.
For a more detailed log analysis, you can query the project logs with ClickHouse SQL in Explorer or through the Management API (query logs with SQL).
3. Read the current Auth configuration
Read the current values before you change them.
Record:
rate_limit_email_sentsmtp_max_frequency- whether custom SMTP is enabled
- whether the Send Email hook is enabled
- the environment or project you inspected
Supabase’s Management API Auth config exposes rate_limit_email_sent, smtp_max_frequency, and SMTP configuration fields.
Do not paste smtp_pass or other secrets into a ticket or screenshot.
4. Compare the evidence
| Finding | Layer | Next read-only check |
|---|---|---|
429 + email rate limit exceeded |
Project-wide email limit | Compare Auth request volume with rate_limit_email_sent |
429 + seconds message |
Per-user frequency window | Compare the wait message with smtp_max_frequency |
| Non-429 SMTP or hook error | Delivery path | Examine the configured provider or hook logs |
| Repeated requests around the incident | Caller behavior | Trace the app, job, or automation that sends the request |
| Evidence does not match one row | Unresolved | Preserve the response and logs; do not change configuration |
Fix only the confirmed layer
If the project-wide limit fired
Record the current configuration.
Check whether the built-in sender, custom SMTP, or Send Email hook is active.
For production email delivery, Supabase recommends custom SMTP rather than the built-in service (custom SMTP).
Set the capacity from the expected traffic. Do not use the highest available value by default.
Change one setting at a time.
Run one controlled signup or recovery test.
If the per-user frequency window fired
Leave the project-wide email limit unchanged.
Show the remaining wait time in the UI.
Disable repeated submit actions during the wait.
Review the frequency setting only if the product requirement justifies a change.
If the delivery path failed
Leave rate limits unchanged unless separate evidence identifies a rate limit.
Check the active SMTP provider or Send Email hook.
Send one controlled test message.
Confirm the Auth-side result.
Then confirm delivery in the provider or hook logs.
If your app sent repeated requests
Stop the duplicate request condition first.
Trace the frontend, backend job, or automation that calls Auth.
Make sure that one user action sends one Auth request.
Show failures to the user. Do not retry silently.
Prevent the same incident
Treat Auth email limits as production configuration.
Document the project email limit and per-user frequency setting for each environment.
Add a UI cooldown for signup confirmation, recovery, OTP, and magic-link actions.
Monitor Auth 429 responses and the relevant email endpoints.
Keep SMTP or Send Email hook ownership documented.
Review the capacity before a launch that can cause a large signup or password-reset spike.
A higher project limit does not prove that the application is healthy. It only allows more email-send attempts before that limit rejects them.
When this needs a wider diagnosis
This article identifies an Auth email rate-limit path. It does not diagnose redirect failures, session failures, provider suppression, spam filtering, or every reason an email can be missing.
If email failures appear with other production symptoms, the incident may cross Auth, application code, and the delivery provider.
For this type of live failure, App Rescue Desk’s web-app bug-fixing service traces the failing request. It separates the application behavior from the Auth and provider behavior. The configuration or migration of a transactional email provider is development and infrastructure work. It is not incident restoration.
What this diagnosis settles
over_email_send_rate_limit does not identify one limit by itself. The current message, Auth logs, and Auth configuration can separate the project-wide email limit from the per-user frequency window.
A missing email without a captured 429 still needs a wider delivery investigation.
If signup or password reset still fails after these checks, send the bug fix request. We agree the scope and price with you before we change anything in production.
If the email request succeeds but the same address then reaches an existing-account state, use the Lovable “User Already Registered” signup diagnosis before deleting or recreating the Auth user.