emailverifier.dev
Posts

Email Validation Regex: What It Can and Cannot Check

| 5 min read | Usama Ejaz
An ivory at-sign sits inside a lime square-cornered syntax gate on a black developer grid.

Use an email regex to reject obviously malformed input, not to declare an address valid. For a normal ASCII signup form, the browser’s WHATWG pattern is a reasonable format gate. Run a maintained validator on the server, then check routing and mailbox evidence separately.

The distinction matters because there is no single regex that answers all three questions: “does this resemble an address?”, “can this domain receive mail?”, and “does this person control the inbox?” Regex answers only the first.

Start with the regex the browser actually uses

The current WHATWG HTML Standard defines the practical syntax behind <input type="email"> and publishes this JavaScript-compatible pattern:

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

If your product accepts conventional ASCII mailbox names, this is a better starting point than inventing ^[^@]+@[^@]+$ and slowly turning it into punctuation archaeology (I have other hobbies).

Still, do not paste the pattern into a server and call the result “valid.” The HTML standard deliberately uses a form-oriented grammar rather than reproducing the full message-address grammar in RFC 5322.

I ran the official pattern against ten edge cases

This is the exact Node.js test I ran:

const cases = [
  'alice@example.com',
  'alice+trial@example.com',
  'alice@example',
  '.alice@example.com',
  'alice..ops@example.com',
  '"alice ops"@example.com',
  'alice@-example.com',
  'alice@example..com',
  'علي@example.com',
  'alice@مثال.إختبار',
];

for (const email of cases) {
  console.log(`${htmlEmail.test(email) ? 'PASS' : 'FAIL'}  ${email}`);
}

The output was:

PASS  alice@example.com
PASS  alice+trial@example.com
PASS  alice@example
PASS  .alice@example.com
PASS  alice..ops@example.com
FAIL  "alice ops"@example.com
FAIL  alice@-example.com
FAIL  alice@example..com
FAIL  علي@example.com
FAIL  alice@مثال.إختبار

The ordinary address and plus tag pass, as expected. The other results expose the boundary of the pattern.

Why do leading and repeated dots pass?

WHATWG’s local-part rule accepts one or more permitted characters or dots. It does not require every dot to sit between two non-dot atoms.

SMTP is stricter here. RFC 5321 section 4.1.2 defines an unquoted dot-string as an atom followed by zero or more dot-and-atom pairs. Under that grammar, .alice@example.com and alice..ops@example.com are not valid unquoted mailboxes.

So should you bolt two more lookaheads onto the browser regex? I would not. Use a maintained server-side email validator that implements the syntax policy you intend to support. OWASP recommends well-tested libraries over custom strict regexes, partly because home-grown patterns reject legitimate formats and drift between identity flows.

Why does a domain without a dot pass?

alice@example matches the HTML grammar because an email domain can contain one label. Requiring at least one dot may be a product policy, but it is not a universal email-syntax rule.

Requiring .com-shaped text would still tell you nothing about DNS. A syntactically neat domain may not exist, may publish a null MX record, or may have no usable mail route. Let the DNS stage answer the routing question.

The null MX and no-MX guide covers those states without turning an empty DNS answer into a made-up mailbox verdict.

Quoted and Unicode addresses force a product decision

The quoted address in the test fails the HTML pattern even though RFC 5322 and RFC 5321 permit a quoted local part. RFC 5321 also advises receiving systems to avoid mailboxes that require quoted strings because interoperability suffers.

That gives a consumer SaaS product a defensible choice: reject quoted local parts with a clear format message if the rest of its stack cannot handle them. What is not defensible is claiming the RFC says they can never be addresses.

The two Unicode cases are a different boundary. RFC 6531 extends mailbox syntax to non-ASCII characters when SMTPUTF8 is supported. Browsers may also convert an internationalized domain to Punycode for validation, while a copied ASCII regex run directly on the raw Unicode value will reject it.

Decide explicitly whether your product supports internationalized local parts and domains. The SMTPUTF8 signup guide owns that implementation path, so I will not smuggle half of it into a regex.

Put syntax in the right place in the signup flow

I would keep six states separate:

  1. The browser catches an obvious format problem for fast feedback.
  2. The server repeats format validation with the same documented acceptance policy.
  3. Normalization preserves the local part and canonicalizes the domain according to your storage model.
  4. DNS and provider checks evaluate whether the domain can receive mail and whether it carries a relevant risk signal.
  5. Mailbox verification returns deliverable, risky, undeliverable, or unknown without forcing uncertainty into a boolean.
  6. Email confirmation proves current inbox access when the action requires it.

Client validation cannot be the security boundary because callers can skip the form and submit directly to your endpoint. Server validation also needs one policy across signup, login, password reset, email change, and account linking. Otherwise the same address can create an account and later fail recovery.

The storage step deserves its own rule too. Lowercase the domain, preserve the local part, and keep collision detection separate from delivery. The email case-sensitivity guide provides a concrete database model.

Where email verification begins

A regex result is a confirmed format pass or failure under one syntax policy. It is not evidence that the domain has mail routing, the recipient exists, or the submitter owns the inbox.

After the server accepts the format, the emailverifier.dev API can evaluate the complete address and return separate status, action, signals, and suggestion fields. Keep confirmed failures, risk signals, and unknown results distinct in your application.

The deeper validation, verification, and confirmation guide maps each layer to the question it can honestly answer.

Use regex for shape. Use the network for evidence. Use confirmation for access.

Continue reading