Skip to main content
Regex Guide

How to Validate Email
with Regex

The practical pattern, what each part does, what it can't catch, and how to test it in your browser.

6 min read·Updated May 2026

How to validate email with regex: use /^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$/ for format checking, understand what each part enforces, and always follow up with a confirmation email — because regex can only verify structure, not whether the mailbox actually exists.

The Practical Email Regex

This pattern covers the vast majority of real email addresses you'll encounter:

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

Breaking It Down

^
Start anchor
The pattern must match from the very start of the string — prevents a garbage prefix before a valid email.
[a-zA-Z0-9._%+\-]+
Local part (before @)
Letters, digits, dots, underscores, percent signs, plus signs and hyphens. The + means one or more characters are required.
@
At sign
Literal @ — required separator between local part and domain.
[a-zA-Z0-9.\-]+
Domain name
Letters, digits, dots and hyphens. Covers subdomains (mail.example.com) and internationalized domains when used with the u flag.
\.
Literal dot
Escaped dot before the TLD. Without the backslash, . would match any character.
[a-zA-Z]{2,}
Top-level domain
Two or more letters — covers .com, .io, .museum, .photography. No digit TLDs (none exist yet in common use).
$
End anchor
Pattern must match to the end of the string — prevents a valid email followed by garbage characters.

JavaScript Implementation

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

function isValidEmail(email) {
  return emailRegex.test(email.trim());
}

// Examples
isValidEmail('user@example.com')       // true
isValidEmail('user+tag@sub.domain.io')  // true
isValidEmail('notanemail')              // false
isValidEmail('@nodomain.com')           // false
isValidEmail('user@')                   // false

Python Implementation

import re

EMAIL_REGEX = re.compile(r'^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$')

def is_valid_email(email: str) -> bool:
    return bool(EMAIL_REGEX.match(email.strip()))

What This Pattern Won't Catch

Regex validates format only. It cannot:

Domain existence
example.typo.com passes the pattern even if the domain doesn't exist.
Mailbox existence
nobody@gmail.com passes even if the inbox doesn't exist.
Ownership
Anyone can type someone else's email address.
Deliverability
An address can be structurally valid but have a full inbox or disabled account.

The rule: use regex to catch obvious typos at form submission time (missing @, no TLD), but always send a confirmation email before treating an address as verified.

Valid Addresses This Pattern Rejects

The pattern is intentionally practical rather than RFC 5322 compliant. It rejects a small set of technically valid but rarely seen addresses:

These represent less than 0.01% of real-world addresses. Rejecting them is an acceptable tradeoff for a readable, maintainable pattern.

Test the Pattern in Your Browser

Paste the regex and your test addresses into the free regex tester — runs locally, no upload.

Open Regex Tester →

Related