send.webforms.toRead the docs →

Email validation regex tester

Five email regexes people copy into real forms, run against addresses real people have and typos real people make. The matrix shows where each pattern turns away a valid address and where it lets a broken one through. Add your own regex and addresses, then copy the pattern you settle on for JavaScript, Python or PHP. Everything runs in your browser.

HTML spec (input type=email)

WHATWG HTML Standard, valid email address

/^[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])?)*$/

What browsers check for <input type="email">. The spec calls it "a willful violation" of RFC 5322: looser before the @, stricter about the domain, and no quoted strings.

Every pattern against every address

  • Rejects a real address
  • Lets a bad one through
  • As expected
Address and expected verdict
jane.doe@example.comAcceptRFC validA plain address. A pattern that fails this is broken.pass, as expectedpass, as expectedpass, as expectedpass, as expectedpass, as expected
jane+invoices@example.comAcceptRFC validPlus addressing (RFC 5233). People use it to sort their mail, and rejecting it turns away careful users.pass, as expectedpass, as expectedpass, as expectedpass, as expectedpass, as expected
jane@mail.example.co.ukAcceptRFC validSubdomains and a two-part country suffix.pass, as expectedpass, as expectedpass, as expectedpass, as expectedpass, as expected
jane@studio.photographyAcceptRFC validA long newer top-level domain. Patterns that cap the TLD at four letters fail here.pass, as expectedpass, as expectedpass, as expectedpass, as expectedpass, as expected
jane@example.xn--p1aiAcceptRFC validThe .рф domain in its ASCII form. Top-level domains can contain digits and hyphens.pass, as expectedpass, as expectedfail, rejects a real addressfail, rejects a real addresspass, as expected
o'brien@example.ieAcceptRFC validAn apostrophe is a permitted character, and a common one in Irish surnames.pass, as expectedpass, as expectedfail, rejects a real addresspass, as expectedpass, as expected
mary-jane@my-studio.comAcceptRFC validHyphens on both sides of the @.pass, as expectedpass, as expectedpass, as expectedpass, as expectedpass, as expected
12345@example.comAcceptRFC validA local part made only of digits is fine.pass, as expectedpass, as expectedpass, as expectedpass, as expectedpass, as expected
Jane.Doe@Example.COMAcceptRFC validCapitals. Domains ignore case, so a pattern should too.pass, as expectedpass, as expectedpass, as expectedpass, as expectedpass, as expected
jane@bücher.deAcceptValid as punycodeAn internationalised domain. The spec's regex is ASCII-only, but browsers may convert the domain to punycode (xn--bcher-kva.de) before checking.fail, rejects a real addresspass, as expectedfail, rejects a real addressfail, rejects a real addressfail, rejects a real address
"jane doe"@example.comYour callRFC validA quoted local part may contain a space under RFC 5321 and 5322. The HTML spec rejects quoting on purpose, and real addresses like this are rare.fail, no expected verdictfail, no expected verdictfail, no expected verdictfail, no expected verdictfail, no expected verdict
jane@[192.0.2.1]Your callRFC validAn IP address literal, valid under RFC 5321. The HTML spec rejects it, and it is almost never what a person means to type.fail, no expected verdictpass, no expected verdictfail, no expected verdictpass, no expected verdictpass, no expected verdict
josé@example.comYour callSMTPUTF8 onlyA non-ASCII local part works only where both mail systems support SMTPUTF8 (RFC 6531). The HTML spec rejects it.fail, no expected verdictpass, no expected verdictfail, no expected verdictpass, no expected verdictfail, no expected verdict
jane..doe@example.comRejectRFC invalidTwo dots in a row are not allowed unless the local part is quoted. The HTML spec accepts it anyway.pass, lets a bad address throughpass, lets a bad address throughpass, lets a bad address throughfail, as expectedfail, as expected
.jane@example.comRejectRFC invalidA local part cannot start with a dot.pass, lets a bad address throughpass, lets a bad address throughpass, lets a bad address throughfail, as expectedfail, as expected
jane.@example.comRejectRFC invalidNor end with one.pass, lets a bad address throughpass, lets a bad address throughpass, lets a bad address throughfail, as expectedfail, as expected
jane@exampleRejectValid syntax onlyValid syntax, and the HTML spec accepts it, which suits intranet hosts. Internet mail needs a fully qualified domain (RFC 5321), so on a public form it is a typo.pass, lets a bad address throughfail, as expectedfail, as expectedfail, as expectedfail, as expected
jane doe@example.comRejectRFC invalidAn unquoted space is never valid.fail, as expectedfail, as expectedfail, as expectedfail, as expectedfail, as expected
jane@example.com.RejectRFC invalidA trailing dot is DNS notation, not part of an email address.fail, as expectedpass, lets a bad address throughfail, as expectedfail, as expectedfail, as expected
jane@-example.comRejectRFC invalidA domain label cannot start with a hyphen.fail, as expectedpass, lets a bad address throughpass, lets a bad address throughpass, lets a bad address throughfail, as expected
jane@example..comRejectRFC invalidTwo dots leave an empty label in the domain.fail, as expectedpass, lets a bad address throughpass, lets a bad address throughfail, as expectedfail, as expected
jane.example.comRejectRFC invalidNo @ at all.fail, as expectedfail, as expectedfail, as expectedfail, as expectedfail, as expected
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa@example.comRejectRFC invalid65 characters before the @. RFC 5321 allows 64, and none of these patterns count.pass, lets a bad address throughpass, lets a bad address throughpass, lets a bad address throughpass, lets a bad address throughpass, lets a bad address through
Mistakes on the built-in set1 lost
5 let in
0 lost
7 let in
3 lost
6 let in
2 lost
2 let in
1 lost
1 let in

One per line, up to 50. They join the matrix with no expected verdict, so the call is yours.

Copy it: HTML spec (input type=email)

Pick a column or tab above to change the pattern. The same regex gives the same answers in all three languages.

email.js
// HTML spec (input type=email)
const EMAIL_RE = /^[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])?)*$/;

function looksLikeEmail(value) {
  return EMAIL_RE.test(value.trim());
}

What a regex can tell you, and what it cannot

A regex checks shape. It can confirm one @, a local part made of permitted characters and a domain that looks like a hostname. It cannot tell you the mailbox exists. jane@exampel.com passes every pattern on this page, and so does an address that was closed last year. The only proof that an address works is a message that arrives, which is why sign-ups that matter send a confirmation link.

Length is the other blind spot. RFC 5321 caps the part before the @ at 64 octets and the whole path at 256 including its angle brackets, which leaves 254 for the address. None of these patterns count, so put maxlength="254" on the field and check the local part on the server if it matters to you.

Why the HTML spec pattern is a sensible default

The pattern the HTML standard defines for <input type="email"> is the one the browser already checks, so using it on the server as well means the two never disagree. The standard calls it "a willful violation of RFC 5322", which it describes as too strict before the @, too vague after it, and too lax about comments, whitespace and quoted strings to be of practical use in a form.

In the matrix its mistakes are nearly all on the forgiving side. It accepts dots RFC 5322 forbids, as in jane..doe@, and a domain with no dot at all, which suits intranets. It refuses quoted local parts and IP literals, which almost nobody types. The one real address its bare regex refuses is an internationalised domain such as bücher.de, and the standard lets browsers convert that to punycode before checking. If you need stricter rules than this, add them as separate checks with their own error messages rather than one longer regex.

Two alternatives hold up well in the matrix. The RFC 5322 pattern makes fewer mistakes on this set, but it runs to nearly 500 characters that nobody on your team will review, and it accepts quoted and IP-literal addresses that your mail provider or CRM may refuse. The minimal pattern rejects no real address at all and leaves the rest to a confirmation email, which is a fair choice when losing a sign-up costs more than a bounce.

Over-strict patterns lose real customers

A pattern that lets a typo through costs you a bounced email. A pattern that rejects a real address costs you the person, and you never find out, because the form simply refuses to submit. That asymmetry is the whole case for erring loose.

The victims are predictable. Apostrophes, as in o'brien@, are permitted characters that the classic [a-zA-Z0-9._%+-] class leaves out. Plus addressing, as in jane+invoices@, belongs to the people most careful about their inbox. A pattern ending in [a-zA-Z]{2,4} rejects .photography and every other long top-level domain, and one that insists on letters rejects internationalised domains in their ASCII form, like xn--p1ai. Top-level domains are added over time, so a regex is the wrong place to keep a list of them.

Validate again on the server

Browser validation is a convenience for the person typing. Anything can post to your form's endpoint without running it: a script, a bot, a form with novalidate, or form.submit() called from JavaScript, which skips validation altogether. So check again where the data lands: trim whitespace, cap the length at 254, test the same pattern, and lowercase only the domain, since RFC 5321 lets the part before the @ be case-sensitive. Then, if the address matters, send a confirmation.

If your form posts to WebForms, an email field is stored exactly as it was submitted. WebForms does not refuse a submission because an address looks unusual, so the check in your form is the one that applies. The spam filter does look at the domain: known disposable providers can add to the spam score or be blocked outright, and the disposable email checker runs that kind of check in your browser.

The _replyto field is stricter, because its value becomes the Reply-To header on your notification. It has to be a single valid address, and if it is not, it is ignored: the notification goes out without a Reply-To rather than the submission failing. On paid plans the autoresponder writes back to _replyto when it is present, otherwise to a field named email, or failing that the first value that looks like an address.

To show errors inline rather than in the browser's bubble, start from the JavaScript validation form. For phone numbers, postcodes and other fields, build the attribute with the input pattern generator.

Sources