Developer reference · email validation

Build email validation that works for modern addresses

If your signup form still expects most legitimate addresses to end in .com, .net, or .info, this guide can help bring it up to date.

It explains why newer gTLDs are normal, why [a-z]{2,4} causes avoidable mistakes, where HTML5 helps, where regex stops, and what practical validation looks like in 2026.

Interactive Email Sandbox

Paste an address and compare common validation approaches.

Native HTML5 validation is intentionally lightweight. The pragmatic regex below is stricter about obvious mistakes. Neither one proves delivery. That comes later.

Presets include valid newer gTLDs, plus-addressing, subdomains, and one obviously broken local part.

Local part 0

Waiting for input.

Domain 0

Waiting for input.

TLD 0

Waiting for input.

Common failure modes

Common validation habits can still block legitimate users.

Many validators were written for an older internet and simply need a more current rule set.

Outdated TLD length assumptions

[a-z]{2,4} treats .photography like a syntax error, even though it is a perfectly valid modern TLD.

Blocking common mailbox workflows

Rejecting +, -, or dots in the local part breaks aliases, filters, and security-minded users who compartmentalize mail.

Syntax checks are not deliverability checks

Even a perfect parser cannot prove the mailbox exists, accepts mail, or belongs to the person typing it.

Common pitfalls
  • Hard-coding .com|.net|.org instead of allowing the broader range of TLDs now in use.
  • Blocking user+tag@domain.com even though plus-addressing is a normal and useful workflow.
  • Using a giant “RFC compliant” regex that is difficult to review, maintain, or reason about safely.
Helpful standards notes
  • RFC 1035 allows DNS labels up to 63 octets.
  • RFC 5233 formalizes subaddressing like user+tag@domain.com.
  • RFC 6530/6531 extend email beyond ASCII to support internationalized addresses.
Helpful practices
  • Use HTML5 validation for immediate UX feedback, not canonical truth.
  • Normalize safely on the server: trim, lowercase the domain only, and convert IDNs to Punycode.
  • Verify actual reachability with DNS checks and confirmation mail.
A brief history of gTLD expansion

Why older regex assumptions no longer match the modern domain space.

New gTLDs were not a fad. They were a policy shift, a DNS rollout, and a clear signal that validators needed to evolve.

The short version

June 2011: ICANN approved the New gTLD Program.
Late 2013 / early 2014: new delegations started landing in the root DNS.
Today: 1,200+ generic TLDs are actively used, including .email, .solutions, .engineering, and .photography.
Practical takeaway:

If your validation rule still assumes the domain space ends around .museum, it is probably time for a refresh.

The familiar [a-z]{2,4} bug

Developers copied TLD-length caps from old blog posts and baked them into validation logic. That assumption was always brittle, and it became actively wrong once long branded and descriptive TLDs arrived.

RFC 1035 permits DNS labels up to 63 octets. Real modern TLDs like .cancerresearch (14 characters) and .northwesternmutual (19 characters) are both far longer than the old {2,4} assumption.

The same era also produced validators that rejected perfectly normal plus-addressing such as user+tag@domain.com, and sometimes even disallowed dots or hyphens in the local part. That breaks aliases, filtering workflows, and mailbox organization patterns that many users rely on every day.

Then there are IDNs and EAI: internationalized domains can appear as Punycode such as xn--bcher-kva.example, and RFC 6530 / RFC 6531 allow non-ASCII email addresses in systems that support Email Address Internationalization. ASCII-only regex is still common, but it does not reflect the full range of real-world email usage.

Regex & standards

Use practical patterns that are easy to review and maintain.

The platform already gives you a lightweight browser validator. Production systems usually want a pragmatic regex on top, not an oversized pattern that is difficult to maintain and reason about.

The HTML5 / WHATWG type="email" pattern

The living-standard regex is intentionally simplified. It is there to catch obvious input errors and provide consistent browser UX, not to implement every edge case from RFC 5322.

Spec snippet as commonly quoted
/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@<a>a-zA-Z0-9</a>?(?:\.<a>a-zA-Z0-9</a>?)*$/

Yes, that weird <a> markup artifact is exactly how this snippet gets mangled when copied through HTML. The actual point is simple: browsers intentionally use a much smaller, more maintainable rule than full RFC 5322 because full RFC 5322 is not a humane UX strategy.

Be careful with oversized “RFC 5322 compliant” regexes.

The oversized pattern floating around the internet is hard to review, hard to maintain, and can introduce catastrophic backtracking and ReDoS risk into your signup form. Smaller, reviewable rules are usually the safer choice.

Pragmatic rule set for production

  • Allow alphanumerics and common local-part specials: !#$%&'*+/=?^_`{|}~-.
  • Allow dots in the local part only between non-dot atoms, which blocks leading, trailing, and consecutive dots.
  • Allow domain labels up to 63 characters each.
  • Require a final TLD label of at least 2 alphabetic characters, using the RFC label ceiling of 63 rather than a fake cap like {2,4} or {2,6}.
That last bullet matters.

“At least 2 alphabetic characters” is a clear product rule. “At most 4” is usually a leftover assumption that no longer fits the current domain landscape.

HTML5

Use the platform for fast feedback.
<input
  type="email"
  name="email"
  autocomplete="email"
  inputmode="email"
  required
/>

JavaScript

Reasonable, readable, reviewable.
const EMAIL_RE =
  /^[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\.)+[A-Za-z]{2,63}$/;

Python

Compiled once, reused everywhere.
import re

EMAIL_RE = re.compile(
    r"^[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+)*@"
    r"(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\.)+[A-Za-z]{2,63}$"
)

Go

Readable RE2, no drama.
var emailRE = regexp.MustCompile(
    "^[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\\\.[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+)*@" +
        "(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\\\\.)+[A-Za-z]{2,63}$",
)

Ruby

Short enough to survive a code review.
EMAIL_RE =
  /\A[A-Za-z0-9!#$%&'*+\/=?^_`{|}~-]+(?:\.[A-Za-z0-9!#$%&'*+\/=?^_`{|}~-]+)*@(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\.)+[A-Za-z]{2,63}\z/
The 4-layer hierarchy

Regex is only the first layer; deliverability comes later.

Effective validation pipelines stack inexpensive checks first and stronger confirmation later.

1

Structural checks (client / regex)

Use HTML5 type="email" and a pragmatic regex to catch missing @, broken domains, and obvious typos. This is UX polish and typo-catching, not proof of existence.

2

Sanitization & normalization (server)

Trim whitespace, lowercase the domain only, preserve local-part case semantics, and convert IDNs to Punycode before deeper checks. Clean input first so every downstream step is evaluating the same canonical form.

3

Domain & DNS verification

Check for MX records and fall back to A / AAAA per RFC 5321 section 5.1. If the domain does not resolve or has no mail target, the address cannot receive mail no matter how pretty the regex result looked.

4

Real-world delivery

The definitive test is still a double opt-in, magic link, or confirmation token sent to the mailbox. The user clicking the link beats every theoretical parser on earth.

Avoid live-pinging remote mail servers during signup.

SMTP VRFY / RCPT TO probing may sound appealing, but greylisting and tarpits can return temporary 450 / 451 errors, catch-all domains may accept everything, and large providers may treat your IP like a harvesting bot. It is usually a poor trade compared with confirmation email and normal deliverability monitoring.