Validating an email address with a regular expression sounds like a one-line problem, but it is one of the most deceptively deep topics in everyday programming. The format is governed by decades of layered standards, every framework ships its own opinion, and modern browsers quietly disagree with the specifications they claim to follow. This guide walks through the patterns developers actually reach for, explains where each one comes from, and points to the authoritative sources behind them.
The patterns below were selected with three priorities in mind: readability, complexity, and relevance to the underlying RFC standards. None of them is "the one correct regex" — that does not exist — but together they cover the range of trade-offs you will face in real projects.
Before You Reach for a Regex
A regular expression can only tell you whether a string is shaped like an email address. It cannot tell you whether the mailbox exists, whether the domain accepts mail, or whether a human will ever read it. The only reliable proof of deliverability is to send a confirmation message and have the recipient act on it — a point made explicitly in the Perl community's long-standing FAQ on the subject.
A second caution: the formal grammar is far more permissive than most people expect. The official syntax for the local part (everything before the @) allows quoted strings, comments, and a long list of special characters that virtually no real-world provider supports. As a result, a regex that is technically correct against the standard will happily accept addresses that no mail server on earth will deliver to. For most applications, a deliberately looser-but-saner pattern is the better engineering choice.
If you want to read the relevant standards directly:
- RFC 5322 — Internet Message Format (the current message-format standard): https://www.rfc-editor.org/rfc/rfc5322
- RFC 5321 — SMTP (defines the actual transport rules and mailbox semantics): https://www.rfc-editor.org/rfc/rfc5321
- RFC 3696 — Application Techniques for Checking and Transformation of Names (a readable summary of what is and isn't a valid address, by John Klensin): https://www.rfc-editor.org/rfc/rfc3696
Tools for Testing Your Patterns
Before deploying any of these expressions, test them against a representative sample of addresses — including the awkward edge cases. Several free, browser-based tools let you experiment interactively, highlight matches, and explain each token of your pattern:
- regex101 — multi-flavor tester with a live explanation pane: https://regex101.com/
- RegExr — visual editor with a community pattern library: https://regexr.com/
- Regex Tester — quick, no-frills matching: https://www.regextester.com/
For ready-made, peer-reviewed patterns, the community library RegexLib hosts thousands of user-contributed expressions, each with a description and notes on its intended scope: https://regexlib.com/. Quality varies, so always read the description and test before adopting one.
General-Purpose Patterns
These are the everyday workhorses. They are intentionally simpler than the formal grammar, trading completeness for clarity and predictability.
A minimal, readable pattern
This expression handles the overwhelming majority of addresses in active use today. It accepts the common local-part characters and a dotted domain, but it does not support the bracketed IP-address form (e.g. user@[192.168.0.1]):
^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$
A case-folded variant
The pattern below matches only lowercase characters, so you must normalize the input — typically by lowercasing the whole string — before you validate it. (Note that the local part of an address is technically case-sensitive per the SMTP standard, but in practice every major provider treats it case-insensitively, so lowercasing for storage and comparison is safe and common.)
^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,6})$
This one is stricter about structure: it requires a final dotted top-level domain of two to six letters. A consequence is that it rejects bare-domain addresses that have no dot after the @, such as nathan@localhost or addresses that point straight at a top-level domain. Whether that is a feature or a bug depends entirely on your use case.
A more permissive, RFC-flavored pattern
This expression admits the broader set of special characters that the standards permit in the local part (! # $ % & ' * + - / = ? ^ _ \ { | } ~), while still keeping the domain conservative. The\b` word boundaries make it suitable for finding addresses embedded in larger text rather than validating a single field:
/\b[!#$%&'*+\-/=?^_`{|}~a-zA-Z0-9][!#$%&'*+\-/=?^_`{|}~a-zA-Z0-9.]*[!#$%&'*+\-/=?^_`{|}~a-zA-Z0-9]@[a-zA-Z0-9\-][a-zA-Z0-9\-.]+[a-zA-Z0-9\-]\b/g
Like the others in this section, it still requires a dotted domain and therefore will not match an address whose domain is a bare top-level label.
Standards-Compliant Patterns
If you genuinely need to honor the formal grammar, the regex grows dramatically — which is itself a strong argument against this approach for most projects.
A short, RFC-oriented expression
The following pattern is widely circulated as an RFC-aligned validator. It covers the standard local-part character set and a multi-label domain. It is best understood as a close approximation of the grammar rather than a literal, exhaustive implementation of it:
/(?:[a-z0-9!#$%&'*+/=?^_{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])/g
Notice that this version also handles the bracketed IP-literal domain form that the simpler patterns above omit.
The "monster" regex
There is a famous, enormous regular expression that aims for genuine grammar-level compliance. It was not written by hand — it was generated by stitching together a set of smaller sub-expressions that map directly onto the productions in the original message-format grammar. The well-known generator is the Perl module Mail::RFC822::Address by Paul Warren, which validates addresses against the RFC 822 grammar using regular expressions instead of a recursive-descent parser, making it fast enough for short-lived scripts:
- Module on CPAN: https://metacpan.org/pod/Mail::RFC822::Address
- Author's project page: https://pdw.ex-parrot.com/Mail-RFC822-Address.html
A widely cited, language-portable rendering of this RFC 822 approach (along with an extensive conformance test suite) was published by Cal Henderson: https://code.iamcal.com/php/rfc822/. It is instructive to study, but its sheer size and its acceptance of addresses no real server would route are exactly why most teams choose a simpler pattern.
A short history of the relevant RFCs
The standard has been revised several times, and each new document supersedes the previous one:
| Document | Year | Status |
|---|---|---|
| RFC 822 | 1982 | Obsoleted by RFC 2822 |
| RFC 2822 | 2001 | Obsoleted by RFC 5322 |
| RFC 5322 | 2008 | Current Internet Message Format |
Separately, RFC 6531 and RFC 6532 extend the rules to allow internationalized (non-ASCII) addresses, such as Unicode characters in the local part: https://www.rfc-editor.org/rfc/rfc6531 and https://www.rfc-editor.org/rfc/rfc6532. When a pattern is described as "RFC-2822 compliant," remember that the current authority is RFC 5322 — and that no single regex captures every nuance of these documents in practice.
Environment-Specific Patterns
Many platforms ship a default email pattern. Reusing the one your framework already provides keeps your behavior consistent with the rest of the ecosystem.
JavaScript- and Perl-compatible
The pattern below is compatible with both JavaScript and Perl regex engines and is a practical balance of strictness and tolerance:
/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/
This closely mirrors the expression that the WHATWG HTML Standard defines for the <input type="email"> control (see the HTML5 section below).
ASP.NET
This is the pattern historically used by the RegularExpressionValidator control in ASP.NET Web Forms. If you build on that stack, matching it keeps client- and server-side validation in agreement:
\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*
Microsoft's reference for the control: https://learn.microsoft.com/en-us/dotnet/api/system.web.ui.webcontrols.regularexpressionvalidator.
HTML5 / WHATWG
The pattern the browser itself applies to <input type="email"> is defined in the living HTML Standard maintained by WHATWG. A simplified form looks like this:
[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*
The specification is candid that this definition is a deliberate "willful violation" of RFC 5322: the committee judged the formal grammar to be at once too strict before the @, too vague after it, and too permissive overall (it allows comments, whitespace, and quoted strings that confuse users) to be useful for a web form. You can read the exact normative text and the precise reference regex on the spec page: https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address. Mozilla's developer reference covers the same control and its pattern attribute: https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input/email.
Internationalized (German) example
To accept addresses containing German umlauts (ä ö ü Ä Ö Ü) in either the local part or the domain, a pattern like the following can be used. It is a useful illustration of how to widen the character classes for a specific locale — though for full international support you should follow the RFC 6531/6532 path and, ideally, work with normalized Unicode:
/([-a-z0-9öäüÖÄÜ.]+)@((?:[-a-z0-9öäüÖÄÜ.]+\.)+)([a-zA-Z]{2,4})/gi
Why Browsers and the Standards Disagree
Email validators exist to match the strict-yet-inclusive rules laid down in the RFCs. In recent years, though, browser vendors have increasingly set those rules aside and defined "valid email" on their own terms. The HTML5 email input is the clearest example: by design, browsers accept only a reduced, practical subset of the formats the standards allow.
The result is a usability paradox. An address that is perfectly legal under RFC 5322 — for instance one using internationalized characters permitted by RFC 6532, like exampleś@example.com — may be flagged as invalid by a browser that follows only the WHATWG grammar. Users who type a technically valid address can find themselves blocked, while the validation gives no clear explanation. This divergence between the formal standards and the de-facto browser behavior is worth keeping in mind whenever you rely on built-in form validation.
Recommendation
For the vast majority of applications, a short, readable pattern (such as the WHATWG-aligned expression in the HTML5 section) is the right default. It rejects the obvious mistakes — missing @, missing domain dot, stray whitespace — without dragging in the unwieldy complexity of full grammar compliance, and it matches what browsers already enforce. Reserve the "monster" RFC patterns for the rare cases that truly require them.
Whatever pattern you choose, treat regex as a format check only. To confirm that an address can actually receive mail, verify the domain's MX records and, ultimately, send a confirmation email. No regular expression can do that for you.