Regex for email addresses in JavaScript

A pattern worth using, what it deliberately does not catch, and why the RFC-complete version is the wrong goal.

The pattern

const EMAIL = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

EMAIL.test('ada@example.com');            // true
EMAIL.test('first.last+tag@sub.co.uk');   // true
EMAIL.test('not an email');               // false
EMAIL.test('missing@domain');             // false
EMAIL.test('@example.com');               // false

In words: some characters, an @, some characters, a dot, some characters — where “some characters” excludes spaces and further @ signs. That is all.

It looks too simple to be a real answer. It is the right answer, and the rest of this page is about why.

What it catches

  • A missing @ — the most common paste error.
  • A missing domain dot, so user@localhost is rejected.
  • A whole sentence pasted into the wrong field.
  • Leading or trailing whitespace, thanks to the anchors.
  • Two @ signs.

What it deliberately misses

  • ada@exampel.com — a typo in the domain. No regex can catch this.
  • ada@example.invalid — a well-formed address at a domain that does not exist.
  • ada@example.com where the mailbox was deleted last year.
  • Some genuinely exotic valid addresses, such as quoted local parts. Nobody has one.

Notice that the first three — the ones that actually cause failed deliveries — are all invisible to any regex, however sophisticated. That is the argument in one line.

Why not the RFC-complete pattern

RFC 5322 permits comments inside addresses, quoted local parts with spaces, bracketed IP-literal domains, and folding whitespace. A regex implementing it faithfully runs to roughly 6,000 characters. Having written it, you would have:

  • Something nobody on the team can modify or review with any confidence.
  • A pattern that accepts "a b"(comment)@[192.168.0.1], which no mail provider will take.
  • A pattern that still rejects internationalised addresses under RFC 6531 — 用户@例子.广告 — which are real and increasing.
  • Very possibly a ReDoS vector, since the widely-copied versions nest quantifiers and the input is attacker-supplied by definition.

You would have traded readability and safety for correctness against a specification that does not describe what you actually care about.

A slightly stricter version

If you want to reject a few more malformed inputs — no consecutive dots, no leading or trailing dot in the local part, a TLD of at least two characters:

const EMAIL_STRICT =
  /^[A-Za-z0-9._%+-]+@[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*\.[A-Za-z]{2,}$/;

This is roughly what most frameworks ship. It is fine, with one thing to be aware of: it is ASCII-only, so it rejects internationalised addresses outright. If your users are global, prefer the loose version.

Paste either into the regex tester to see it broken down piece by piece — both are in the pattern library with example addresses that pass and fail.

Use the platform first

<input
  type="email"
  name="email"
  required
  autocomplete="email"
  inputmode="email"
/>

type="email" gives you a browser-native check, an appropriate mobile keyboard, autofill, and accessible error messaging for free. The HTML specification defines its check as a deliberately loose regex — almost exactly the loose pattern above — chosen for the same reasons set out here.

Add your own pattern only where you need a custom message or a stricter rule, and always re-validate on the server. Client-side validation is a usability feature; it is not a security control.

A validation strategy that works

  1. Loose regex, on input. Catch the obvious mistakes while the user is still looking at the field.
  2. Suggest corrections for likely typos. gmial.com → did you mean gmail.com? Comparing the domain against a list of common providers catches far more real errors than any amount of regex tightening.
  3. Optionally check the domain has an MX record server-side. Cheap, and rejects fully fictional domains.
  4. Send a confirmation email. This is the actual validation. Everything above it is a convenience.

The same pattern elsewhere

// JavaScript
const EMAIL = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

# Python
import re
EMAIL = re.compile(r"^[^\s@]+@[^\s@]+\.[^\s@]+$")

// Java — note the doubled backslashes
Pattern EMAIL = Pattern.compile("^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$");

// Go
var email = regexp.MustCompile(`^[^\s@]+@[^\s@]+\.[^\s@]+$`)

This pattern uses no lookaround, no backreferences and no nested quantifiers, so it works identically in all four — including Go’s RE2, which rejects the features that many “complete” email regexes depend on.

Frequently asked questions

What is the best regex for validating an email address?

A deliberately loose one: /^[^\s@]+@[^\s@]+\.[^\s@]+$/. It catches the mistakes people actually make — a missing @, a typo, a pasted sentence — without rejecting valid addresses it does not recognise. Tightening it beyond this trades a small gain in rejected typos for a real risk of rejecting real customers.

Why not use a fully RFC 5322 compliant regex?

Because it is around 6,000 characters, unmaintainable, and still wrong: it accepts addresses no mail server will deliver to, and it does not accept internationalised addresses. It solves a problem you do not have. The question you actually need answered is "will mail reach this address", and no regex can answer that.

How do I actually verify an email address?

Send an email to it with a confirmation link. That is the only method that establishes both that the address exists and that the person entering it can receive mail there. Everything before that step — regex, DNS MX lookup, disposable-domain lists — is about catching typos early, not about verification.

Should I use type="email" instead?

Use it as well. The browser gives you a free first pass, a sensible mobile keyboard, and accessible error messaging. Its own check is roughly as loose as the pattern above, which is a deliberate choice by the HTML specification for the same reasons. Always re-check server-side: client-side validation is a usability feature, not a security control.

Do I need to worry about ReDoS in an email regex?

Yes, if your pattern nests quantifiers. Several widely-copied "RFC compliant" email regexes contain constructs like (a+)+ that take exponential time on a crafted input, and the input here is by definition attacker-supplied. The loose pattern above has no nesting and cannot backtrack pathologically.

Found a mistake on this page? Tell me — a page that is confidently wrong is worse than no page.