Email OTP: How One-Time Passcodes Over Email Work (and How to Send Them)

Email OTP: How One-Time Passcodes Over Email Work (and How to Send Them)

An email OTP (one-time passcode) is a short numeric code sent to a user’s inbox to confirm their identity for a single login, checkout, or verification event. The server generates a random code, stores a hash of it with an expiry timestamp, emails it, and accepts a match within a short window, typically three to ten minutes, before invalidating it. It requires no app install, which makes it a common alternative to magic link email. It is not, however, a strong authentication factor by modern standards: NIST SP 800-63B states plainly that “email SHALL NOT be used for out-of-band authentication” because the channel can be reached with just a password, intercepted in transit, or rerouted through DNS spoofing.

Generate, Send, Verify: How an Email OTP Flow Works

An email OTP is a triggered email, fired the instant a user asks to sign in, check out, or verify an address. The mechanics:

  1. The user submits their email address and requests a code.
  2. The server generates a random code using a cryptographically secure random number generator.
  3. The server stores a hash of the code, not the raw value, alongside the user ID, expiry timestamp, and an attempt counter.
  4. The server sends the code by email on the same transactional stream used for account and password reset emails.
  5. The user enters the code. The server hashes the input and compares it to the stored hash.
  6. On a match inside the expiry window, the server authenticates the user and invalidates the code immediately. On a mismatch, it increments the attempt counter and rejects.

This mirrors the token contract behind password reset links, except the “token” is a short code a human types rather than a URL parameter, which changes the math on expiry and attempt limits considerably.

Code Length, Expiry, and Rate Limits: What the Standards Recommend

A 6-digit numeric code has roughly one million possible values. OWASP’s Multifactor Authentication Cheat Sheet points out that this “very small keyspace (for example, ~1 million possibilities for a 6-digit code)” means “a database attacker can brute-force any OTP hash quickly,” and recommends teams “consider 8-digit or longer codes where usability allows.” Length alone doesn’t close the gap; it has to be paired with expiry and attempt limits. OWASP’s baseline for OTP handling: “enforce a short time-to-live (TTL),” “ensure OTPs are single use,” “apply strict attempt limits,” and “invalidate the OTP on successful verification.”

Two widely used identity platforms show what this looks like in production. Auth0’s passwordless email documentation states codes are “valid (by default) for three minutes before it expires” and allow “only three failed attempts” before a new code is required. Twilio Verify defaults to “a default period of 10 minutes” and caps verification checks at 60 requests per minute, 180 per hour, and 250 per day.

A reasonable target for most SaaS login flows: 6-8 digit codes, a 5-10 minute expiry, 3-5 failed attempts before lockout, and a per-account and per-IP cap on how many codes can be requested per hour.

Store the Hash, Not the Code

Never log or persist the raw OTP value. Hash it before it touches the database, the same principle used for password reset tokens. OWASP is candid about the limits of this for OTPs specifically: because the keyspace is so small, “hashing OTPs does not provide strong offline attack resistance in the way password hashing does.” A hash alone won’t stop an attacker who already has database access and time to brute-force a million combinations.

What hashing does provide, per OWASP, is protection against “accidental disclosure via logs, metrics, or debugging tools” and a smaller “blast radius if the database is briefly exposed during the OTP’s validity window.” Treat it as a hygiene control, not a cryptographic guarantee, and let expiry plus rate limiting do the actual security work.

Why Delivery Speed Is Part of an OTP’s Security Model

An OTP with a 5-minute expiry has already lost a meaningful share of its validity window if the email takes 60-90 seconds to arrive. Slow delivery doesn’t just annoy users; it functionally shortens the security window the code was designed to have.

This is why OTP and other transactional email needs infrastructure that treats speed as a requirement, not a nice-to-have. Postmark’s own framing of the problem: “your password resets, license keys, account confirmations, and other transactional emails are critical to your business, and it’s imperative that they arrive in your customers’ inboxes immediately,” to the point that “even a 30-second delay to Hotmail addresses gets us out of bed in the middle of the night.”

The practical fix is routing OTP sends on a dedicated transactional stream, separate from marketing email, so a bulk campaign’s reputation, or a temporary throttle, never delays a login code. It’s the same separation Coldletter’s transactional stream is built around: authentication and verification mail routed apart from lifecycle and marketing sends.

Choosing Between Email OTP, Magic Links, and SMS OTP

Email OTP, magic link email, and SMS OTP all confirm the same thing (this person controls this email address or phone number) with different tradeoffs. A magic link removes typing entirely, but works cleanly only when the user opens it on the same device where they started, and some corporate security scanners prefetch links, which can burn a single-use token before the user clicks it. An OTP code works across devices, since it can be read on a phone and typed into a laptop. SMS OTP is fast to type but depends on carrier delivery, and NIST classifies SMS/PSTN as a restricted authenticator, not a recommended default.

DimensionEmail OTPMagic LinkSMS OTP
What the user doesTypes a short codeClicks a linkTypes a short code
Typical expiry3-10 minutes10-60 minutes3-5 minutes
Works across devicesYesNo, same device/browser neededYes
NIST 800-63B treatmentNot a valid out-of-band authenticatorNot a valid out-of-band authenticator (same channel)Restricted authenticator
Main riskInbox compromise, interception, DNS reroutingSame as email OTP, plus link prefetching by scannersSIM swap, number porting, carrier interception
Deliverability requirementMust arrive in seconds, dedicated streamSame as email OTPDepends on SMS gateway/carrier route

Frequently Asked Questions

What is an email OTP?

An email OTP (one-time passcode) is a short code sent to a user’s email address to confirm their identity for a single login, checkout, or verification event. It typically expires within minutes and can only be used once.

How long should an email OTP code stay valid?

Most implementations use a 3-10 minute window. Auth0 defaults to three minutes; Twilio Verify defaults to 10 minutes and allows customization from two minutes up to 24 hours. Shorter windows reduce the time an attacker has to guess or intercept a code; longer windows reduce failed logins caused by slow email delivery.

Is email OTP secure enough for two-factor authentication?

It works for many products, but NIST SP 800-63B does not classify email as a valid out-of-band authentication channel because it can be reached with just a password, intercepted in transit, or rerouted through DNS spoofing. Treat email OTP as a verification and convenience layer rather than a phishing-resistant second factor, and pair it with a stronger method for higher-risk actions like changing account recovery details.

Should the OTP code be stored as plain text or as a hash?

Store a hash, never the raw code, following the same practice used for password reset tokens. OWASP notes that hashing a 6-digit code doesn’t stop an attacker who already has database access, since the keyspace is small enough to brute-force, so hashing should be paired with a short expiry and strict rate limits rather than relied on alone.

Why does an OTP email need to arrive faster than a newsletter?

Because the expiry clock starts the moment the code is generated, not when the email is opened. A 60-second delivery delay on a 5-minute code removes a meaningful share of the user’s window to act, and delayed transactional email is one of the most common triggers for “I never got my code” support tickets.

What’s the difference between email OTP and a magic link?

Both are single-use, time-limited credentials sent by email, but an OTP requires typing a code, which works across devices, while a magic link requires clicking a URL on the same device and browser where the flow started. Magic links remove a typing step; OTP codes are more forgiving when the user checks email on a different device than the one they’re logging in on.