# Email verification best practices for sign-up flows

> Verification links or codes, when to require them, how to handle typos, resends and changed addresses, and how to protect accounts before they're confirmed.

Published 2026-11-04. Source: https://mailions.com/blog/email-verification-best-practices

You ask for an email address on the sign-up form. You can't trust it. People mistype, borrow other people's addresses, or invent one to get past the form. Verification is how you find out whether the address is real and belongs to the person typing it.

Doing it badly costs you sign-ups. Doing it carelessly opens security holes.

## Why verify at all

- **To reach people.** A password reset sent to a typo goes nowhere, and the account is stuck.
- **To protect others.** Without verification, someone can register with another person's address, and that person gets email they never asked for.
- **To protect your sender reputation.** Mail to addresses that don't exist bounces, and bounces lower your domain's standing.
- **To prevent account takeover.** If anyone can claim an address, an attacker can register the email of a future employee or customer before they do.

## Link or code?

A **link** is the simplest: the person clicks it and they're confirmed. It works best when they open the email on the same device where they signed up.

A **code** is better when the person might read the email on a phone but be signing up on a laptop. They read six digits and type them in. It avoids the link opening in the wrong browser, and it works with security tools that rewrite or pre-fetch links.

Pre-fetching deserves a note. Some mail scanners open every link in a message to check it's safe. If clicking the link alone confirms the account, a scanner can do the confirming for you. Make the link open a page with a button, and let the click on the button complete the verification. Or use a code.

Our post on [sending OTP emails](/blog/send-otp-email) covers code generation, expiry and attempt limits.

## When to require it

You have three options, from lightest to strictest:

1. **Verify before the account works at all.** Safest, but adds friction before the person sees any value.
2. **Let them in with limits, verify for full access.** A good compromise. They can look around but can't invite people, publish or pay until verified.
3. **Verify later.** Only suitable when the email isn't used for anything important.

For anything that sends mail on someone's behalf, or involves money, choose the first or second.

## Handle typos kindly

A confirmation email to `gmial.com` will never arrive. Help people before they submit:

- Check the format, but don't write a clever regex. The only true test is whether mail gets delivered.
- Suggest a fix for obvious domain typos ("Did you mean gmail.com?").
- Show the address on the "check your inbox" page with an "Edit" link, so a typo can be fixed without starting over.

## Resends

People click resend quickly. Give them a button, but:

- Limit it to about once a minute and a few times an hour, per account and per IP address.
- Invalidate the old token or code when a new one goes out.
- Say where it went ("We sent an email to a***@example.com").
- After a few attempts, suggest checking spam and offer a way to contact you.

## Never confirm an account exists

On sign-in and reset pages, treat known and unknown addresses the same, so your site can't be used to check who has an account. Sign-up is the one place where you can't hide it, since "that email is already registered" is useful. Add a rate limit there so it can't be used to scan lists.

## Don't let unverified accounts hold the address

Imagine an attacker registers `victim@company.com`, doesn't verify, and sets a password. Later the real person signs in with a social login that matches that email, and the two accounts merge. The attacker now has access. Protect against it:

- Don't merge accounts automatically on email match unless the email on both sides is verified.
- Don't let an unverified account block the real owner from registering. Let the verified registration win.

## Changing an email address

Treat a change as a new verification. Send a link or code to the *new* address and only switch after it's confirmed. Also send a notice to the *old* address, so a hijacked session can't silently redirect the account. Keep the old address as the sign-in until the new one is confirmed.

## Make the email itself reliable

- Send from an authenticated domain with SPF, DKIM and DMARC. [What is DMARC](/blog/what-is-dmarc) explains the third.
- Use a recognisable sender name and a short, specific subject: "Confirm your email address".
- Include a plain text part.
- Don't pack it with promotion.
- Set a reasonable expiry, such as 24 hours for a link or 10 minutes for a code.

## Test it

You'll send many verification emails while building. Use throwaway addresses instead of real ones. Mailions's [public temporary inboxes](/temp) need no sign-up, and free ones delete messages after 30 minutes. Anyone who knows an address can read it, so don't use it for anything real.

## Summary

Verify before trust, use codes when links are risky, rate limit everything, keep unverified accounts powerless, and re-verify on change. If you want to send verification email from your own domain, see the [API guide](/help/sending-api) or [contact us](/contact).

## Frequently asked questions

### Should I use a verification link or a code?

Links are easiest on the same device; codes work better inside apps and when someone signs up on a computer but reads email on a phone. Many products include both in one email. Either way, make it short-lived and single-use.

### How long should an email verification link stay valid?

Commonly about 24 hours for confirming a new account, and much shorter, around 15 to 60 minutes, for password resets and sign-in codes. An expired link should explain what happened and offer to send a new one.

### Why is my verification email not arriving?

Check spam first, then that the address was typed correctly. On the sending side, confirm SPF, DKIM and DMARC pass, look for a bounce in the send log, and make sure the email goes out immediately rather than behind bulk mail.
