Use ^[A-Za-z0-9]+([._%+-][A-Za-z0-9]+)*@([A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?\.)+[A-Za-z]{2,}$ as your syntax filter. It covers the vast majority of consumer addresses, but it proves only format, never deliverability. Trim the input, lowercase the domain, test the pattern in your own engine, then send a confirmation email.
TL;DR:
- The practical pattern permits dots, underscores, percent signs, plus signs, and hyphens between alphanumeric runs, while requiring valid domain labels and a two letter suffix.
- Do not encode the full RFC grammar: quoted local parts and comments can confuse forms and storage, while rare formats often lack provider support.
- Check the 64 character local part and 254 character total limits in code, and convert internationalized domains to punycode before matching.
- Anchor the pattern and avoid multiline mode, since multiline anchors can accept pasted text containing line breaks; test behavior in the engine you deploy.
- Use a one time, expiring confirmation link to prove inbox control; SMTP probes can produce false negatives and raise rate limit, privacy, and legal concerns.
Table of Contents
- Which regex pattern should you use for email validation?
- How do you use the pattern in JavaScript, Python and C#?
- Which edge cases should your regex allow or reject?
- How should you handle input before and after matching?
- When is regex not enough to validate an email?
- Why do we prefer pragmatic validation plus a confirmation email?
- Test these patterns in our free Regex Tester
- FAQ
- Sources
Which regex pattern should you use for email validation?
Two patterns cover most needs. The first is a minimal sanity check, the second is the stricter real-world default.
- Minimal:
^\S+@\S+\.\S+$accepts anything with no spaces, an@, and a dot after it. It is fine for a quick client-side hint, but it lets througha@b.cand@@.x. - Practical: the pattern from the opening paragraph enforces single dots in the local part, valid domain labels, and a TLD of at least two letters.
The practical pattern follows the same spirit as a data-backed analysis of real-world addresses, which recommends ASCII alphanumerics plus single dots and dashes. Here is how it breaks down:
- Local part: letters and digits, with
.,_,%,+or-allowed only between alphanumeric runs, so no leading, trailing or doubled dots. - Domain labels: each label starts and ends with a letter or digit, and hyphens appear only inside.
- TLD: two or more letters. Cap it with an upper bound if you need one.
Pro Tip: Do not chase full RFC 5322 compliance. It is widely discouraged because it allows rare formats that most mail providers do not support, and it adds complexity and risk.
How do you use the pattern in JavaScript, Python and C#?
In JavaScript, a literal keeps escaping simple:
const emailRe = /^[A-Za-z0-9]+([._%+-][A-Za-z0-9]+)*@([A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?\.)+[A-Za-z]{2,}$/;
emailRe.test(input.trim());
With the constructor, every backslash must be doubled: new RegExp("...\\.)+[A-Za-z]{2,}$"). Forgetting that turns \. into a bare . that matches any character.
In Python, compile once and reuse:
import re
EMAIL_RE = re.compile(r"^[A-Za-z0-9]+([._%+-][A-Za-z0-9]+)*@([A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?\.)+[A-Za-z]{2,}$")
EMAIL_RE.fullmatch(value.strip())
For C#, prefer System.Net.Mail.MailAddress when you need robust parsing, and keep a regex for quick checks where you only want a cheap filter before heavier work.
Engines differ in subtle ways around Unicode and flags, so test in the engine you ship rather than assuming a pattern behaves identically everywhere. Common gotchas:
- Anchoring: without
^and$,hello a@b.com goodbyepasses. - Multiline flags: with
mset, anchors match at each line break, so a pasted value with a newline can slip through. - Literal slashes: inside a JavaScript literal, escape any
/as\/. - Escaped backslashes: double them in string-based constructors, or use raw strings in Python.
Pro Tip: Paste the pattern into a live JavaScript regex tester with a list of good and bad addresses before it reaches production.
Which edge cases should your regex allow or reject?
Our default pattern deliberately omits some RFC-legal forms. Decide per product whether you need them.
- Plus addressing:
user+test@example.comis common and already supported, because+is in the separator class. If you strip tags for deduplication, do it after validation. Restrictive patterns that omit legitimate characters break real user accounts. - Quoted local parts and comments:
"john doe"@example.comis legal under RFC 5322, but it confuses forms, logs and storage, so rejecting it is usually the right call. - Unicode and IDN: either accept ASCII only, or convert the domain to punycode before matching and sending.
- Domain literals:
user@[192.168.0.1]is valid in theory and almost never wanted. - Length limits: check the local part (64 characters) and the total (254 characters) in code, not in the regex.
Most real mail providers do not support quoted local parts or exotic RFC 5322 forms, so validating against the full specification is discouraged.
If your engine supports lookahead, you can add (?=.{1,254}$) at the start, but a plain length check is easier to read and test.
How should you handle input before and after matching?
Clean the value first, then match. The HTML Standard's email input state strips newlines and trims leading and trailing ASCII whitespace before validating, so mirroring that avoids false negatives from pasted text.
- Trim and normalize: strip surrounding whitespace, then lowercase the domain for comparisons. Leave the local part as typed, since it can be case-sensitive in theory.
- Match the browser: when your backend uses the same rules as the browser, you avoid mismatches between client acceptance and server rejection.
- Know your engine: PCRE, JavaScript and .NET differ on recursion, balancing groups and Unicode, so test where the code runs.
- Watch performance: keep the pattern anchored and avoid nested quantifiers that can backtrack catastrophically on long hostile input.
- Write unit tests: cover typical addresses, plus tags, double dots, missing
@, and oversized strings.
Pro Tip: Cap input length before running any regex. A 254-character ceiling removes most pathological backtracking cases.
When is regex not enough to validate an email?

Regex tells you an address looks right. It cannot tell you the mailbox exists. Deliverability depends on DNS, SMTP and whether the recipient account is real, and nobody@example.com passes every pattern here while bouncing every time.
The dependable check is a confirmation email with a token, because it proves the user controls the inbox. Practical steps:
- Send once, fire and forget: email a single-use, expiring link and mark the address verified only on click.
- Check the domain: a guide on verifying an email domain walks through DNS-level checks worth running before you trust a sender domain.
- Treat mailbox probes as optional: SMTP probes and verification services can add signal, but they bring false negatives, rate limits, and privacy and legal considerations.
Why do we prefer pragmatic validation plus a confirmation email?
Most email regexes fail by being too clever. The more of RFC 5322 you encode, the more real users you reject by accident and the harder the pattern is to maintain. We favor a short, readable filter that blocks obvious typos, followed by a confirmation email that settles the question. Treat the regex as a courtesy to the user, not a gatekeeper. It is also worth testing patterns interactively, which is why we built our free Regex Tester.
— Andreas
Test these patterns in our free Regex Tester
Paste the patterns from this article into our free Regex Tester and run your own list of good and bad addresses against them. While you work, our HTML Validator and JSON Formatter help check form markup and API payloads. You can start from our tools page.

FAQ
What is the correct email format for validation?
A valid address has a local part, an @, and a domain with at least one dot and a TLD. For form validation, use a pragmatic pattern rather than the full RFC grammar. The HTML Standard also defines how browsers sanitize and validate email inputs.
How do you check for special characters in regex?
Put the allowed characters in a character class and escape the ones with special meaning, such as \. for a literal dot. Place - at the start or end of the class so it is not read as a range. Then anchor the pattern with ^ and $.
How do you validate an email address in Flutter?
Dart supports the same regex syntax, so use RegExp(r'...') with the pattern from this article and call hasMatch on the trimmed input. Raw strings avoid double escaping. Still confirm ownership with a verification email on your backend.
How long can an email address be?
The commonly enforced limits are 64 characters for the local part and 254 characters in total. Check these with a simple length test, as long regexes make length rules hard to maintain and lookahead support varies by engine.
