Details below are from Firebase’s documentation on 23 October 2026. Check it for current limits. For the basics, what Firebase sends and how to test it, start with Test Firebase Authentication emails.
The email never arrives
Nothing asked for it. createUserWithEmailAndPassword creates the account and sends no email. Your sign-up code has to call sendEmailVerification for the new user. If it doesn’t, the account sits unverified and the tester waits for nothing.
The address has no account. With email enumeration protection, on by default for projects created on or after 15 September 2023, sendPasswordResetEmail sends only when the address belongs to an account, and returns no error when it doesn’t. A reset test with an address that never signed up passes in your app and receives nothing. Sign up first, then reset.
A daily limit ran out. On the free Spark plan, Firebase sends 5 email-link sign-ins a day, 150 password resets and 1,000 verification emails. Passwordless sign-in stops after the fifth test of the day. Add billing (Blaze) for staging, or test email-link sign-in sparingly.
It’s in spam. By default the emails come from noreply@ your project’s firebaseapp.com address, which some inboxes distrust. Set up your own domain in the console’s email templates. A Proxy Mail QA address receives them either way, so you can tell “not sent” from “sent to spam”.
You’re using the emulator. The Auth emulator doesn’t send email: it prints each verification, reset and sign-in link in the terminal where it runs and in the Emulator Suite’s Logs tab, and offers them on a REST endpoint for tests. Test against a real staging project before launch.
Sign-up fails
auth/email-already-in-use: the address has an account. Enumeration protection doesn’t hide this one. Use a fresh address for every run.- Too many sign-ups: Firebase allows 100 new accounts an hour from one IP address. A test suite running from one CI machine can pass that. You can schedule a temporary increase in the Firebase console.
- Password rules: with a password policy switched on, a weak password fails with
auth/password-does-not-meet-requirements. Make sure your form says why. - Bot protection: reCAPTCHA protection or App Check enforcement on Authentication can turn away automated browsers. For App Check, give your test runs a debug token.
Sign-in fails with auth/invalid-credential
With enumeration protection, a wrong password and an unknown address give the same error (INVALID_LOGIN_CREDENTIALS, which the web SDK reports as auth/invalid-credential). Tests that expect auth/user-not-found or auth/wrong-password start failing, and so do apps that show a different message for each. Check for the single error instead.
The link was clicked, but the app still says “verify your email”
The User object your app holds keeps the emailVerified value it had when the person signed in. After they click the link in another tab, call user.reload(), and user.getIdToken(true) if your security rules or backend read the email_verified claim. Until then, the app and your rules still see an unverified user.
The link fails
auth/invalid-action-codeorauth/expired-action-code: the link was used already or has expired. Request a new email and use the newest one.auth/unauthorized-continue-uri: the continue URL your code passes isn’t on an authorized domain. Add each environment under Authentication, Settings, Authorized domains. Preview deployments get new domains, so each one needs adding, or use a fixed staging domain.- It goes to localhost: the continue URL comes from your code. Build it from an environment setting rather than a hard-coded
http://localhost. More in why emails link to localhost.
Email-link sign-in asks for the email again
Email-link sign-in finishes in the browser that asked for the link: your app stores the address there (usually in localStorage) and reads it back when the link opens. Open the link on another device or browser, and Firebase’s own guidance is to ask for the address again, to prevent session fixation. That’s expected. Testers should open the link where they started. In a mobile app, the link also has to open the app, which works differently since Dynamic Links shut down: see Firebase email-link sign-in for mobile apps.
Check them all in one pass
- Create a fresh Proxy Mail QA address for each scenario: new user, password reset (on an address you’ve signed up), email-link sign-in.
- Go through the flow in your app. The link appears on the address’s row within seconds, or never, which tells you nothing was sent.
- Look at the row: a link to localhost is flagged, and the inbox shows each email’s sender and checks.
checkEmailwithexpectHostfails a test whose link leads anywhere but your site. - Open the link in the same browser, then check your app shows the user as verified without signing out and in again.
Built with Antigravity or another AI tool? Problems in vibe-coded sign-up and login covers what generated apps usually get wrong on top of these.