This error occurs when your Supabase project exceeds its configured email sending rate limit. By default, the built-in email service allows only 2-4 emails per hour, while custom SMTP providers support 30+ emails per hour. Upgrading to a custom email provider or adjusting rate limits can resolve this.
Supabase Auth enforces rate limits on email sending to prevent abuse and protect service reputation. When your application attempts to send more emails than the configured limit allows within a time window, the `over_email_send_rate_limit` error is returned. This typically happens during user registration flows when multiple users sign up quickly, or when resending verification emails. The limit applies to all auth emails including sign-up confirmations, password resets, and OTP codes.
Navigate to your Supabase project dashboard and go to Settings > Auth > Email. Verify which email provider you are currently using:
- Built-in SMTP: Limited to 2-4 emails per hour (development only)
- Custom SMTP: Can handle 30+ emails per hour
If you are in production, you should be using a custom SMTP provider.
Configure a custom email service to replace the built-in provider. Popular options include:
AWS SES (Recommended for scale)
1. Sign up for AWS SES and verify your sending domain
2. Generate SMTP credentials in AWS console
3. In Supabase Settings > Auth > Email, select "Custom SMTP"
4. Enter your AWS SES SMTP endpoint and credentials
SendGrid (Easy to set up)
1. Create a SendGrid account at sendgrid.com
2. Generate an API key with mail send permissions
3. In Supabase, select Custom SMTP
4. Use smtp.sendgrid.net as host, port 587, with API key as password
Resend (Purpose-built for transactional email)
1. Sign up at resend.com
2. Generate an API key
3. Use their SMTP endpoint in Supabase custom SMTP settings
Other options: Mailgun, Postmark, Brevo, or your own mail server
After setting up custom SMTP, adjust the rate limits to match your application's needs:
1. In Supabase dashboard, go to Auth > Rate Limits
2. Find the "Email send rate limit" setting (default is 30 emails/hour for custom SMTP)
3. Increase it based on your expected user registration patterns
4. If you expect a major traffic spike, contact Supabase support at least 2 weeks in advance
Example configurations:
- Small app (< 100 users/day): Keep at 30 emails/hour
- Medium app (100-1000 users/day): Set to 100-200 emails/hour
- Large app: Request higher limits from Supabase support
Reduce pressure on email sending by adding client-side controls:
// Add cooldown between signup attempts
const lastSignupAttempt = localStorage.getItem('lastSignupAttempt');
const now = Date.now();
const cooldown = 60000; // 1 minute between attempts
if (lastSignupAttempt && now - parseInt(lastSignupAttempt) < cooldown) {
throw new Error('Please wait before trying again');
}
try {
await supabase.auth.signUp({ email, password });
localStorage.setItem('lastSignupAttempt', now.toString());
} catch (error) {
// Handle error
}Also implement exponential backoff for resend attempts:
async function resendVerificationWithBackoff(email, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
await supabase.auth.resend({ email });
return;
} catch (error) {
if (error.status === 429) {
// Wait before retrying: 2s, 4s, 8s
await new Promise(r => setTimeout(r, Math.pow(2, i + 1) * 1000));
} else {
throw error;
}
}
}
}Keep track of your email sending to prevent future rate limit issues:
1. Log email operations: Track successful sends and rate limit hits in your application logs
2. Use Supabase Analytics: Monitor authentication metrics in your project dashboard
3. Set up alerts: Create alerts when rate limit errors exceed a threshold
4. Batch operations carefully: If sending bulk invitations, space them out over time instead of sending all at once
5. Review failed attempts: Failed signups still consume rate limit quota, so validate inputs on the client before submission
Example monitoring code:
try {
await supabase.auth.signUp({ email, password });
} catch (error) {
if (error.message.includes('rate limit')) {
// Log to monitoring service
console.error('Rate limit hit', { timestamp: new Date(), email });
// Show user a friendly message
}
}For self-hosted Supabase, use the environment variable GOTRUE_RATE_LIMIT_EMAIL_SENT to configure the rate limit. The rate limit is applied per project and is shared across all authentication methods (sign-up, password reset, magic links, OTP). When testing, be aware that failed authentication attempts count against your quota even if no email is actually delivered. Set up DKIM, DMARC, and SPF records for your custom SMTP domain to improve email deliverability. Supabase's built-in email service provides no SLA and is explicitly not recommended for production use.
email_conflict_identity_not_deletable: Cannot delete identity because of email conflict
How to fix "Cannot delete identity because of email conflict" in Supabase
mfa_challenge_expired: MFA challenge has expired
How to fix "mfa_challenge_expired: MFA challenge has expired" in Supabase
conflict: Database conflict, usually related to concurrent requests
How to fix "database conflict usually related to concurrent requests" in Supabase
phone_exists: Phone number already exists
How to fix "phone_exists" in Supabase
StorageApiError: resource_already_exists
StorageApiError: Resource already exists