Download Cheat sheet PDF 12 pages · syntax, editors, patterns, Unicode, performance, debugging
Patterns May 14, 2026

How to match an email address with regex (and why no regex is truly perfect)

A practical pattern that covers 99% of real emails, with honest notes on what it gets wrong.

The short answer

Here's a pattern that handles nearly every email address you'll encounter in practice:

^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$

This works in JavaScript, Python, and PCRE without modification. Open it in the explainer →

What it matches

  • alice@example.com — basic case
  • bob.smith+work@company.co.uk — dots in local, multi-part TLD, plus addressing
  • user_123@sub.domain.io — underscores, subdomains

What it rejects

  • @example.com — missing local part
  • alice@example — no TLD
  • alice@.com — empty domain label
  • plain text — no @

Token-by-token breakdown

^
Anchor to the start of the string.
[a-zA-Z0-9._%+-]+
The local part — letters, digits, dot, underscore, percent, plus, hyphen.
@
The literal at-sign.
[a-zA-Z0-9.-]+
The domain — letters, digits, dots, hyphens.
\.
A literal dot (escaped — a bare dot would match any character).
[a-zA-Z]{2,}
The TLD — at least 2 letters.
$
Anchor to the end.

Why no email regex is truly perfect

The official RFC 5321 spec for email addresses allows quoted local parts like "foo bar"@example.com, comments in parentheses, IP-literal domains like user@[192.0.2.1], and a host of edge cases nobody uses in practice. A regex that handles all of these is over 6,000 characters long and still misses cases.

The hard truth: regex can never confirm an email is real. It can only confirm the string looks like one. To actually verify the address, send a confirmation email and see if anyone clicks the link.

What this pattern is good for

  • Catching typos in form input — most "invalid email" errors are missing @ or .com
  • Filtering log lines — extracting email-shaped strings from text
  • Bulk processing — checking thousands of records for malformed entries

What this pattern is NOT good for

  • Security checks — assume malicious input can have a valid-looking email
  • Deliverability — sending to alice@example.com won't reach a real inbox
  • Internationalized addresses — Unicode local parts and IDN domains need a real library

JavaScript example

const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
function isLikelyEmail(input) {
  return emailRegex.test(input.trim());
}

Python example

import re
email_regex = re.compile(r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$")
def is_likely_email(s):
    return bool(email_regex.match(s.strip()))

The takeaway

Use this pattern to catch obvious typos. Trust the user with anything weirder. For real validation, send the email. For internationalized or unusual addresses, use a library — JavaScript's email-validator, Python's email-validator, Java's commons-validator.


Related reading


Try this pattern in the explainer

Paste any regex into the live explainer and see what each token means, with example matches in real time.

Open the regex explainer →