Supabase Email Confirmation Not Sending Troubleshooting
technology

Supabase Email Confirmation Not Sending Troubleshooting

Email confirmations not sending from Supabase? Learn the exact causes and fixes for SMTP, template, and configuration issues in 10 minutes.

2026-01-28
10 min read
Supabase Email Confirmation Not Sending Troubleshooting

Supabase Email Confirmation Not Sending Troubleshooting#

Supabase Email Confirmation Not Sending Troubleshooting Guide#

Email confirmation not sending is one of the most common issues developers face when implementing Supabase authentication in Next.js applications. You set up email/password auth, users sign up, but the confirmation email never arrives. This guide covers every possible cause and provides tested solutions that work in production.

This article is part of our comprehensive Supabase Authentication & Authorization Patterns guide.

Why Supabase Email Confirmations Fail#

There are 5 main reasons why confirmation emails don't send:

  1. Development Mode Limitations - Supabase free tier has email rate limits
  2. SMTP Not Configured - Default email service is unreliable
  3. Email Template Issues - Broken confirmation links or template errors
  4. Domain/DNS Problems - SPF/DKIM records not configured
  5. User Already Confirmed - Email was already verified

Quick Diagnostic Checklist#

Before diving into fixes, run through this checklist:

## Check Supabase logs
## Go to: Dashboard > Logs > Auth Logs
## Look for: "email_confirmation_sent" or error messages

## Check user status in database
SELECT email, email_confirmed_at, confirmation_token 
FROM auth.users 
WHERE email = 'user@example.com';

## Verify SMTP settings
## Go to: Dashboard > Authentication > Email Templates
## Check: SMTP settings are configured

The default Supabase email service is unreliable. Use a custom SMTP provider:

Step 1: Choose an SMTP Provider#

Best options for production:

  • SendGrid - 100 emails/day free, reliable
  • Resend - Modern API, great DX
  • AWS SES - Cheapest for high volume
  • Mailgun - Good deliverability

Step 2: Configure SMTP in Supabase#

// 1. Go to Supabase Dashboard > Project Settings > Auth
// 2. Scroll to "SMTP Settings"
// 3. Enable "Enable Custom SMTP"

// Example SendGrid Configuration:
Host: smtp.sendgrid.net
Port: 587
Username: apikey
Password: YOUR_SENDGRID_API_KEY
Sender email: noreply@iloveblog.blog
Sender name: Your App Name

Step 3: Verify SMTP Connection#

// Test email sending from Supabase Dashboard
// Go to: Authentication > Email Templates
// Click: "Send test email"
// Check: Email arrives in inbox (not spam)

Step 4: Update Environment Variables#

## .env.local
NEXT_PUBLIC_SUPABASE_URL=your-project-url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key

## For custom email templates
SMTP_HOST=smtp.sendgrid.net
SMTP_PORT=587
SMTP_USER=apikey
SMTP_PASS=your-api-key

Solution 2: Fix Email Template Configuration#

Check Confirmation URL#

The confirmation link must point to your application:

// Supabase Dashboard > Authentication > URL Configuration
// Site URL: https://iloveblog.blog
// Redirect URLs: https://iloveblog.blog/auth/callback

// Email template should use: {{ .ConfirmationURL }}
// NOT: {{ .SiteURL }}/auth/confirm?token={{ .Token }}

Update Email Template#

<!-- Go to: Dashboard > Authentication > Email Templates > Confirm signup -->
<h2>Confirm your signup</h2>
<p>Follow this link to confirm your account:</p>
<p><a href="{{ .ConfirmationURL }}">Confirm your email</a></p>
<p>Or copy and paste this URL into your browser:</p>
<p>{{ .ConfirmationURL }}</p>

Handle Confirmation in Next.js#

// app/auth/callback/route.ts
import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs'
import { cookies } from 'next/headers'
import { NextResponse } from 'next/server'

export async function GET(request: Request) {
  const requestUrl = new URL(request.url)
  const token_hash = requestUrl.searchParams.get('token_hash')
  const type = requestUrl.searchParams.get('type')
  const next = requestUrl.searchParams.get('next') ?? '/'

  if (token_hash && type) {
    const supabase = createRouteHandlerClient({ cookies })

    const { error } = await supabase.auth.verifyOtp({
      type: type as any,
      token_hash,
    })

    if (!error) {
      return NextResponse.redirect(new URL(next, request.url))
    }
  }

  // Return error page
  return NextResponse.redirect(new URL('/auth/error', request.url))
}

Solution 3: Configure DNS Records (Production)#

For production, configure SPF and DKIM records:

SPF Record#

## Add TXT record to your domain:
Type: TXT
Name: @
Value: v=spf1 include:sendgrid.net ~all

## For SendGrid, check their documentation for exact value

DKIM Record#

## SendGrid provides DKIM records in their dashboard
## Add 3 CNAME records they provide
## Example:
Type: CNAME
Name: s1._domainkey
Value: s1.domainkey.u12345.wl.sendgrid.net

Verify DNS Configuration#

## Check SPF record
nslookup -type=TXT iloveblog.blog

## Check DKIM record
nslookup -type=CNAME s1._domainkey.iloveblog.blog

## Test email deliverability
## Use: mail-tester.com

Solution 4: Handle Rate Limits#

Supabase has email rate limits on free tier:

// Implement retry logic for email sending
async function sendConfirmationEmail(email: string) {
  const supabase = createClient()
  
  try {
    const { error } = await supabase.auth.signUp({
      email,
      password: 'user-password',
      options: {
        emailRedirectTo: `${window.location.origin}/auth/callback`,
      },
    })

    if (error) {
      // Check if rate limit error
      if (error.message.includes('rate limit')) {
        // Wait and retry
        await new Promise(resolve => setTimeout(resolve, 5000))
        return sendConfirmationEmail(email)
      }
      throw error
    }

    return { success: true }
  } catch (error) {
    console.error('Email send failed:', error)
    return { success: false, error }
  }
}

Solution 5: Resend Confirmation Email#

Allow users to resend confirmation:

// app/api/resend-confirmation/route.ts
import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs'
import { cookies } from 'next/headers'
import { NextResponse } from 'next/server'

export async function POST(request: Request) {
  const { email } = await request.json()
  const supabase = createRouteHandlerClient({ cookies })

  const { error } = await supabase.auth.resend({
    type: 'signup',
    email,
    options: {
      emailRedirectTo: `${process.env.NEXT_PUBLIC_SITE_URL}/auth/callback`,
    },
  })

  if (error) {
    return NextResponse.json({ error: error.message }, { status: 400 })
  }

  return NextResponse.json({ message: 'Confirmation email sent' })
}

Frontend Component#

'use client'

import { useState } from 'react'

export function ResendConfirmation({ email }: { email: string }) {
  const [loading, setLoading] = useState(false)
  const [message, setMessage] = useState('')

  async function handleResend() {
    setLoading(true)
    
    const response = await fetch('/api/resend-confirmation', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ email }),
    })

    const data = await response.json()
    setMessage(data.message || data.error)
    setLoading(false)
  }

  return (
    <div>
      <p>Didn't receive the email?</p>
      <button onClick={handleResend} disabled={loading}>
        {loading ? 'Sending...' : 'Resend confirmation email'}
      </button>
      {message && <p>{message}</p>}
    </div>
  )
}

Common Mistakes#

  • Mistake #1: Not checking spam folder - Always check spam/junk folders first

  • Mistake #2: Using default Supabase email - Configure custom SMTP for reliability

  • Mistake #3: Wrong redirect URL - Ensure Site URL matches your domain exactly

  • Mistake #4: Missing DNS records - SPF/DKIM required for production

  • Mistake #5: Not handling errors - Always show user-friendly error messages

FAQ#

Why do emails work in development but not production?#

Production requires proper DNS configuration (SPF/DKIM records) and a verified sender domain. Development mode uses Supabase's default email service which is less strict.

How long does it take for confirmation emails to arrive?#

With proper SMTP configuration, emails should arrive within 1-2 minutes. If using default Supabase email, it can take 5-10 minutes or fail entirely.

Can I disable email confirmation?#

Yes, but not recommended for production. Go to Dashboard > Authentication > Settings > Enable email confirmations (toggle off). This creates security risks.

What if users never receive the email?#

Implement a "resend confirmation" feature and provide alternative verification methods (phone, social auth). Always check spam folders first.

How do I test email sending locally?#

Use a service like Mailtrap or MailHog for local testing. Configure SMTP to point to these services during development.

Conclusion#

Email confirmation issues in Supabase are usually caused by SMTP configuration, template problems, or DNS settings. The most reliable solution is configuring custom SMTP with a provider like SendGrid or Resend, along with proper DNS records for production.

Follow the solutions above in order: configure SMTP first, then fix templates, add DNS records, and implement resend functionality. Test thoroughly in development before deploying to production.

Monitor your email deliverability using services like mail-tester.com and always provide users with a way to resend confirmation emails if needed.

Frequently Asked Questions

|

Have more questions? Contact us