Resend a verification email in Firebase by calling sendEmailVerification() on the currently signed-in user object. Firebase rate-limits verification emails to a maximum of 5 per email address per hour. Before resending, check user.emailVerified to confirm the email is not already verified, and use user.reload() to refresh the auth state from the server. Always wrap the call in try/catch to handle rate limit errors gracefully.
Resending Email Verification in Firebase Auth
When a user signs up with email and password, Firebase can send a verification email to confirm their address. Sometimes users miss or delete the original email and need it resent. This tutorial shows how to resend the verification email, check the current verification status, handle rate limits, and customize the redirect URL after verification.
Prerequisites
- A Firebase project with Authentication enabled
- Email/password sign-in method enabled in Firebase Console
- Firebase JS SDK v9+ installed (npm install firebase)
- A user account that has signed up but not yet verified their email
Step-by-step guide
Check if the user's email is already verified
Check if the user's email is already verified
Before attempting to resend the verification email, check the user.emailVerified property. However, this property is cached in the client-side token and may be stale. Call user.reload() first to refresh the user's profile from the server, then check emailVerified on the refreshed user object. This prevents sending unnecessary emails to already-verified users.
1import { getAuth } from 'firebase/auth'23const auth = getAuth()45async function checkVerificationStatus() {6 const user = auth.currentUser78 if (!user) {9 console.log('No user is signed in.')10 return false11 }1213 // Refresh user data from server14 await user.reload()1516 // Re-fetch the user object after reload17 const refreshedUser = auth.currentUser1819 if (refreshedUser?.emailVerified) {20 console.log('Email is already verified.')21 return true22 }2324 console.log('Email is not yet verified.')25 return false26}Expected result: The function returns true if the email is verified or false if it still needs verification.
Resend the verification email
Resend the verification email
Call sendEmailVerification() with the current user object to resend the verification email. This function is imported from firebase/auth and takes the user as its first argument. Firebase sends the same type of verification email as the initial one. Wrap the call in try/catch to handle errors, particularly the too-many-requests error that occurs when the rate limit is exceeded.
1import { getAuth, sendEmailVerification } from 'firebase/auth'23const auth = getAuth()45async function resendVerificationEmail() {6 const user = auth.currentUser78 if (!user) {9 throw new Error('No user is signed in.')10 }1112 await user.reload()13 if (auth.currentUser?.emailVerified) {14 console.log('Email is already verified. No need to resend.')15 return16 }1718 try {19 await sendEmailVerification(user)20 console.log('Verification email sent successfully.')21 } catch (error: any) {22 if (error.code === 'auth/too-many-requests') {23 console.error('Too many requests. Please wait before trying again.')24 } else {25 console.error('Failed to send verification email:', error.message)26 }27 }28}Expected result: The verification email is sent to the user's email address, or a clear error message is logged if rate-limited.
Customize the verification email redirect URL
Customize the verification email redirect URL
Pass an actionCodeSettings object as the second argument to sendEmailVerification() to customize where the user is redirected after clicking the verification link. Set the url property to your app's URL. This is useful for directing users back to a specific page like a welcome screen or dashboard after they verify their email.
1import { getAuth, sendEmailVerification, ActionCodeSettings } from 'firebase/auth'23const auth = getAuth()45async function resendWithCustomRedirect() {6 const user = auth.currentUser7 if (!user) return89 const actionCodeSettings: ActionCodeSettings = {10 url: 'https://yourapp.com/welcome?verified=true',11 handleCodeInApp: false12 }1314 try {15 await sendEmailVerification(user, actionCodeSettings)16 console.log('Verification email sent with custom redirect.')17 } catch (error: any) {18 console.error('Error:', error.message)19 }20}Expected result: The verification email contains a link that redirects to your specified URL after the user verifies.
Add a cooldown timer to prevent rapid resend clicks
Add a cooldown timer to prevent rapid resend clicks
Since Firebase rate-limits verification emails to 5 per hour per email address, implement a client-side cooldown timer to discourage users from clicking the resend button repeatedly. Disable the button for 60 seconds after each send and show a countdown. This improves user experience and avoids hitting the rate limit.
1import { useState, useCallback } from 'react'2import { getAuth, sendEmailVerification } from 'firebase/auth'34function useResendVerification() {5 const [cooldown, setCooldown] = useState(0)6 const [status, setStatus] = useState<'idle' | 'sending' | 'sent' | 'error'>('idle')78 const resend = useCallback(async () => {9 if (cooldown > 0) return1011 const user = getAuth().currentUser12 if (!user) return1314 setStatus('sending')15 try {16 await sendEmailVerification(user)17 setStatus('sent')18 setCooldown(60)1920 const interval = setInterval(() => {21 setCooldown((prev) => {22 if (prev <= 1) {23 clearInterval(interval)24 return 025 }26 return prev - 127 })28 }, 1000)29 } catch (error: any) {30 setStatus('error')31 }32 }, [cooldown])3334 return { resend, cooldown, status }35}Expected result: The hook manages sending state and a 60-second cooldown, preventing the user from spamming the resend button.
Poll for verification completion
Poll for verification completion
After the user receives and clicks the verification link, your app needs to detect the change. Since Firebase does not push verification status changes to the client in real time, you must poll by calling user.reload() periodically. Check emailVerified after each reload and redirect the user once verified.
1import { getAuth } from 'firebase/auth'23function pollForVerification(4 onVerified: () => void,5 intervalMs: number = 3000,6 maxAttempts: number = 607) {8 const auth = getAuth()9 let attempts = 01011 const timer = setInterval(async () => {12 attempts++13 const user = auth.currentUser14 if (!user || attempts >= maxAttempts) {15 clearInterval(timer)16 return17 }1819 await user.reload()20 if (auth.currentUser?.emailVerified) {21 clearInterval(timer)22 onVerified()23 }24 }, intervalMs)2526 return () => clearInterval(timer)27}Expected result: The function polls every 3 seconds and calls the onVerified callback as soon as the user completes email verification.
Complete working example
1import { getAuth, sendEmailVerification, ActionCodeSettings, User } from 'firebase/auth'23const auth = getAuth()45export async function isEmailVerified(): Promise<boolean> {6 const user = auth.currentUser7 if (!user) return false89 await user.reload()10 return auth.currentUser?.emailVerified ?? false11}1213export async function resendVerification(14 redirectUrl?: string15): Promise<{ success: boolean; error?: string }> {16 const user = auth.currentUser17 if (!user) {18 return { success: false, error: 'No user signed in.' }19 }2021 const alreadyVerified = await isEmailVerified()22 if (alreadyVerified) {23 return { success: false, error: 'Email is already verified.' }24 }2526 const settings: ActionCodeSettings | undefined = redirectUrl27 ? { url: redirectUrl, handleCodeInApp: false }28 : undefined2930 try {31 await sendEmailVerification(user, settings)32 return { success: true }33 } catch (error: any) {34 if (error.code === 'auth/too-many-requests') {35 return { success: false, error: 'Rate limit reached. Wait a few minutes.' }36 }37 return { success: false, error: error.message }38 }39}4041export function pollForVerification(42 onVerified: () => void,43 intervalMs = 3000,44 maxAttempts = 6045): () => void {46 let attempts = 04748 const timer = setInterval(async () => {49 attempts++50 if (attempts >= maxAttempts) {51 clearInterval(timer)52 return53 }5455 const verified = await isEmailVerified()56 if (verified) {57 clearInterval(timer)58 onVerified()59 }60 }, intervalMs)6162 return () => clearInterval(timer)63}Common mistakes when resending a Verification Email in Firebase
Why it's a problem: Checking emailVerified without calling user.reload() first, causing stale verification status
How to avoid: Always call await user.reload() before reading emailVerified. The property is cached in the client-side token and does not update automatically when the user verifies on another device or tab.
Why it's a problem: Not handling the auth/too-many-requests error, leaving users confused when the resend silently fails
How to avoid: Catch the error and display a user-friendly message like 'Please wait a few minutes before requesting another verification email.' Firebase allows a maximum of 5 verification emails per hour per address.
Why it's a problem: Calling sendEmailVerification after the user's session has expired, causing an auth/requires-recent-login error
How to avoid: Ensure the user is still signed in by checking auth.currentUser before calling sendEmailVerification. If the session expired, prompt the user to sign in again.
Best practices
- Always call user.reload() before checking emailVerified to get the latest status from the server
- Implement a client-side cooldown timer (60 seconds) to prevent users from hitting the 5-per-hour rate limit
- Show clear feedback to the user: 'Verification email sent' on success, 'Please wait' on cooldown, and helpful error messages on failure
- Use actionCodeSettings to redirect users to a specific page after verification for a smoother onboarding flow
- Poll for verification completion on the waiting screen so the UI updates automatically when the user verifies
- Add the redirect URL domain to Firebase Console Authorized Domains to prevent verification link failures
- Log verification resend events for analytics to understand how many users need multiple verification emails
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I have a Firebase Auth app where users sign up with email/password. Show me how to implement a resend verification email feature using the modular SDK v9, including checking if already verified, handling rate limits, adding a cooldown timer, and polling to detect when the user completes verification.
Build a React component for Firebase email verification that shows the verification status, a Resend button with a 60-second cooldown timer, rate limit error handling, and automatic redirect when the user completes verification. Use Firebase modular SDK v9+ with TypeScript.
Frequently asked questions
How many verification emails can Firebase send per hour?
Firebase rate-limits verification emails to 5 per email address per hour. If you exceed this limit, the SDK throws an auth/too-many-requests error. You cannot increase this limit — it is a fixed Firebase restriction to prevent abuse.
Can I customize the verification email template?
Yes. Go to Firebase Console, then Authentication, then Templates. You can edit the subject line, body text, and sender name. For full HTML customization, upgrade to Identity Platform or use a custom email handler with your own SMTP service.
Does the verification link expire?
Yes. Firebase verification links expire after 3 days by default. If the user clicks an expired link, they will see an error. You can adjust the expiration period (1 hour to 30 days) via the Firebase Admin SDK's generateEmailVerificationLink method.
How do I know when the user has verified their email?
Firebase does not push verification status changes to the client. You must call user.reload() and then check emailVerified. Implement polling on the verification waiting screen, checking every 3-5 seconds until the status changes.
Can I force users to verify their email before accessing the app?
Firebase Auth does not block unverified users from signing in. You must implement this check yourself: after sign-in, check user.emailVerified and redirect unverified users to a verification screen. Also enforce this in Firestore security rules with request.auth.token.email_verified.
Can RapidDev help implement email verification flows in my Firebase app?
Yes. RapidDev can build complete email verification flows including signup, verification status checking, resend functionality, custom redirect URLs, and security rules that enforce verification before data access.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation