Regex for an email address
Use ^[^\s@]+@[^\s@]+\.[^\s@]+$: one or more non-space, non-@ characters, an @, then a domain with at least one dot. It catches typos like a missing @ or a stray space. Then prove the address works by sending a confirmation email.
JavaScript ✓PCRE ✓
^Start of the stringanchor[^\s@]Any one character except a whitespace character (space, tab, line break and other Unicode spaces) and '@'character class+Repeat the class one or more times, as many as possible (greedy)quantifier@The character '@' literallyliteral[^\s@]Any one character except a whitespace character (space, tab, line break and other Unicode spaces) and '@'character class+Repeat the class one or more times, as many as possible (greedy)quantifier\.The character '.' literallyliteral[^\s@]Any one character except a whitespace character (space, tab, line break and other Unicode spaces) and '@'character class+Repeat the class one or more times, as many as possible (greedy)quantifier$End of the stringanchor
Examples
Checked at build time in JavaScript and in Python's re.
| Input | Matches? |
|---|---|
user@example.com | ✓ match |
first.last+tag@sub.example.co.uk | ✓ match |
o'brien@example.ie | ✓ match |
no-at-sign.example.com | ✗ no match |
user@localhost | ✗ no match |
two words@example.com | ✗ no match |
user@@example.com | ✗ no match |
a@b.c | ✓ match |
user@example..com | ✓ match |
user@.example.com | ✓ match |
Try your own text
One string per line: each line is tested on its own (the m flag is added here).
How it works
The full grammar in RFC 5322 allows quoted local parts ("john doe"@example.com), comments in parentheses, and IP-literal domains (user@[192.0.2.1]). A regex that covers all of it runs to thousands of characters, and it still cannot tell you whether a mailbox exists. The only real test is a message the user receives and clicks.
So the job of the regex is a sanity check: reject input that is obviously not an address, and accept everything a real mail server might take. A pattern that is too strict is worse than one that is too loose. It turns away real customers with addresses like o'brien@example.ie or user+tag@example.com.
Browsers have their own check. An <input type="email"> validates against a pattern from the HTML standard (shown below under variants). It is deliberately simpler than RFC 5322: it does not allow quoted local parts, and it accepts a domain with no dot, such as user@localhost.
Variants
/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/The pattern the HTML standard specifies for<input type="email">. ASCII only, and it acceptsuser@localhost./^[^\s@]+@[^\s@]+$/Looser still: anything with exactly one @ and no spaces. Use it when intranet hosts without a dot are valid.
Gotchas
- This pattern accepts
user@example..comanduser@.example.com. Both are invalid domains. The confirmation email catches them; the regex does not try to. - It rejects
user@localhostbecause it requires a dot after the @. That is right for a public sign-up form and wrong for an internal tool. - Do not lowercase the whole address before storing it. The domain is case-insensitive, but RFC 5321 lets the local part be case-sensitive. In practice almost no provider treats it that way, so compare case-insensitively but keep what the user typed.
- Internationalized addresses such as
用户@例子.广告are valid under RFC 6531.[^\s@]accepts them. Patterns built on[a-zA-Z0-9]do not. - Cap the length first (254 characters is the practical maximum for an address). The domain part
[^\s@]+\.[^\s@]+can match dots in many ways, so a long run of dots followed by a space takes quadratic time to reject.
Related explainers
- Regex for an http or https URLA regex that checks a string is an http or https URL, where it falls short, and why new URL() is the...
- Regex to trim leading and trailing whitespaceHow ^\s+|\s+$ with the g flag trims a string, why String.prototype.trim() is better, and the 2016 Stack...
- Regex to match or strip HTML tagsWhat <[^>]*> does to HTML, where it breaks (comments, > in attributes, scripts), and why stripping tags...