Quick answer
Use /^[\w.+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/ for client-side checks. It catches typos and rejects anything obviously not an email, but it will not (and should not) try to validate the full RFC 5322 grammar. Pair it with a confirmation email for ground truth.
Email regex is the canonical example of a problem where "good enough" beats "perfectly correct". RFC 5322 allows quoted local parts, comments, and IP-literal domains. No real signup form needs that. Here is the pattern most teams actually ship.
// Practical email validation, two patterns
const looksLikeEmail = /^[\w.+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/;
function isValidEmail(input) {
if (!looksLikeEmail.test(input)) return false;
// Reject the most common typos in TLDs
if (/\.(con|cmo|comm)$/i.test(input)) return false;
return true;
}
isValidEmail('sergey+stripe@regios.org'); // true
isValidEmail('not-an-email'); // false
isValidEmail('user@domain.con'); // false (typo)
The pattern, explained piece by piece
Break it down:
^anchor to start of input[\w.+-]+one or more word characters, dots, plus signs, or hyphens (the local part)@a literal at-sign[A-Za-z0-9.-]+one or more letters, digits, dots, or hyphens (the domain)\.a literal period before the TLD[A-Za-z]{2,}at least two letters for the TLD (covers io, com, museum, technology)$anchor to end of input
This rejects "user@", "@domain.com", "user@domain", and "user @domain.com". It accepts plus-addressing (sergey+stripe@regios.org) and dotted local parts (first.last@company.com), which most users expect.
Why not the full RFC 5322 regex
The official grammar allows things no real signup form should accept. Quoted local parts ("user with spaces"@example.com), IP-literal domains (user@[192.168.1.1]), comments inside addresses (user(work)@example.com). The fully compliant regex is over 6,000 characters long and famously broken in many published versions.
What you actually want is a syntactic sniff test, plus a confirmation email loop. The regex catches typos at the input field. The confirmation email proves the address routes to a real human. Trying to make the regex do both is how you end up rejecting legitimate +-addressed Gmail users on a Tuesday morning.
What to do for the 1% the regex misses
Three known gaps in the simple pattern:
- Internationalized domains (IDN). Punycode-encoded TLDs like .xn--3e0b707e pass the regex; the human-readable form 한국 does not. If your audience is global, lowercase and Punycode-normalize the input before testing.
- New TLDs that are exactly two characters. The pattern accepts them. Good. But beware that some operators reject TLDs they do not recognize, this is a server-side concern, not a regex one.
- Dotted local parts that start or end with a dot. The regex allows .user@x.com, which is technically invalid. If you care, add
(?<!^\.)(?<!\.\.)-style guards or strip surrounding dots before validating.
Common mistakes in published email regex
You will see three failure modes on Stack Overflow:
- Hard-coded TLD list. Patterns that allow only com|org|net|edu|gov|mil|info were already wrong in 2008. Today there are over 1,500 TLDs in DNS root.
- Using
\wfor the domain.\wincludes underscores, which are not valid in domain labels. Stick to[A-Za-z0-9.-]for that segment. - Forgetting anchors. Without
^and$, not-an-email-but-has@something.com-extra will passtest(). Always anchor.
If you are pasting a regex from a forum, run it against a list of 30 weird-but-valid emails (plus-addressed, dotted, all-numeric local part, single-letter TLD attempt) before shipping.
Validation in different languages
Same intent, different syntax:
- JavaScript:
/^[\w.+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/.test(email) - Python:
re.fullmatch(r"[\w.+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}", email) - PHP:
preg_match('/^[\w.+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/', $email) - Go:
regexp.MustCompile("^[\\w.+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$").MatchString(email)
Languages that do not support possessive quantifiers do not need them here. Languages that lack lookbehind do not need it either. The pattern is portable, which is part of why it has aged well.
When to use a library instead
For server-side validation, prefer a library that has been battle-tested: validator.js in Node, email-validator in Python, EmailValidator in C#. These do the regex sniff plus DNS-aware checks (MX record present, domain exists) that you do not want to maintain by hand.
Use the regex above for client-side feedback (instant red border on a typo) and let the library or the confirmation email handle the rest. That split, fast feedback at the input, ground truth at the back end, is what every mature signup form does.