Free · Fast · Privacy-first

Regex for Email Validation, Test Patterns Against Real Addresses

Email validation regex is one of the most misused patterns in web development: too strict and you reject legitimate addresses, too loose and you accept garbage.

Test email regex against edge-case addresses instantly

🔒

See which parts of an address your pattern captures

Understand the tradeoffs between strict and lenient patterns

Copy a tested pattern directly into your validation code

Cost
Free forever
Sign-up
Not required
Processing
In your browser
Privacy
Files stay local
FreeNo signupWhite-label

Add this Regex Tester to your website

Drop the Regex Tester into any page — blog post, product docs, intranet, school portal — with a single line of HTML. Your visitors get the full tool, processed entirely in their browser. No backend, no uploads, no signup.

  • Files stay 100% in the visitor's browser
  • Responsive — adapts to any container width
  • Free forever, no API key needed

Embed code

<iframe
  src="https://www.fixtools.io/developer/regex-tester?embed=1"
  width="100%"
  height="780"
  frameborder="0"
  style="border:0;border-radius:16px;max-width:900px;"
  title="Regex Tester by FixTools"
  loading="lazy"
  allow="clipboard-write"
></iframe>

Attribution-friendly: a small "Powered by FixTools" link appears in the embed footer.

Building Reliable Email Validation Regex: Tradeoffs and Best Practices

Email address validation is a classic case where perfect is the enemy of good. The full RFC 5321 specification permits addresses that no real user would ever have: local parts with spaces inside quoted strings, comments in parentheses before and after the at sign, IP address domain literals enclosed in square brackets, and international characters in the domain using punycode encoding. Writing a regex that accepts every syntactically valid RFC address while rejecting all invalid strings is extremely complex and produces a pattern that is both difficult to maintain and so permissive it provides little practical filtering benefit. Most production systems deliberately use a simplified pattern that covers the 99.9% of real addresses that conform to common conventions, then rely on a confirmation email to verify deliverability, which is the only true end-to-end validation.

A practical email regex typically has three components: the local part before the at sign, the at sign separator itself, and the domain after it. The local part character class matches word characters and common punctuation including dots, hyphens, underscores, and plus signs. The domain segment matches one or more DNS-style labels separated by dots, where each label consists of word characters and hyphens. The top-level domain is constrained to two or more letters to cover both two-character country codes and longer generic TLDs. A common working pattern is ^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$. This accepts user@example.com and user+tag@sub.domain.co.uk while rejecting strings missing the at sign or a dot-separated domain.

For real-world deployment, the key design decisions are: whether to allow plus-sign subaddressing in the local part, whether to permit consecutive dots in the local part which the RFC disallows but some implementations accept, and how to handle new generic TLDs with long suffixes like .photography or .technology that existing patterns with {2,4} TLD bounds incorrectly reject. Test your final pattern against a diverse set that includes disposable address services, corporate subdomain addresses, plus-addressed Gmail and Fastmail addresses, and deliberately invalid strings before deploying to production.

Email patterns are a frequent source of ReDoS vulnerabilities because writers naturally reach for nested quantifiers when handling multi-label domains. The pattern ^([a-zA-Z0-9]+\.)+[a-zA-Z]+$ looks innocent but contains a classic backtracking trap: a long input ending with one disallowed character forces the engine to explore an exponential number of ways to assign the dot-separated labels before declaring failure. The fix is to use an unrolled-loop pattern such as ^[a-zA-Z0-9]+(\.[a-zA-Z0-9]+)*$ which has no overlap between the initial segment and the alternative. Always benchmark email patterns against pathological inputs (long strings ending in a single disallowed character) before deploying them on any path that accepts untrusted user input, especially in serverless environments where a hung function costs real money per second.

How to use this tool

💡

Paste your email validation regex into the pattern field, then paste a list of email addresses (one per line) into the test string to see which ones match and which do not.

How It Works

Step-by-step guide to regex for email validation, test patterns against real addresses:

  1. 1

    Open the Regex Tester

    Navigate to the FixTools Regex Tester. The tool opens in your browser immediately without any setup. The pattern field, flag selector, and test string area are all available on a single screen.

  2. 2

    Enter your email regex

    Paste your email validation pattern into the pattern field. If you need a starting point, use ^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$. This covers the vast majority of real-world addresses including plus-sign subaddressing and multi-label domains.

  3. 3

    Enable the g and m flags

    Enable the global flag to find all matches in the test string and the multiline flag so that each line in the test area is evaluated against the anchored pattern independently. Together these flags let you test a full list of addresses in a single paste operation.

  4. 4

    Paste test addresses

    Enter a list of email addresses one per line. Include addresses that cover common edge cases: plus-sign subaddresses, subdomain addresses like user@mail.company.co.uk, long TLDs like user@studio.photography, and intentionally invalid strings like "notanemail", "@nodomain.com", and "missing-at-sign.com".

Real-world examples

Common situations where this approach makes a real difference:

Validating a registration form email field

A frontend developer tests the pattern ^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$ against a list of 20 test addresses. The tester confirms it highlights user@example.com, first.last@company.org, and user+tag@mail.co.uk correctly, while producing no match for "notanemail", "missing@tld", and "@nodomain.com". The developer copies the confirmed pattern directly into the form library validator and adds a confirmation email step as a second-stage deliverability check after the regex pre-screen.

Filtering email addresses from a CSV export

A data engineer needs to extract valid email addresses from a CSV column that also contains phone numbers and free text in inconsistent formats. The email regex with the g flag and String.matchAll() in Node.js selectively pulls address-shaped strings from each cell. Testing a sample of 50 raw CSV rows in the browser tester first confirms the pattern correctly captures addresses and does not incorrectly match phone numbers or partial strings that share some characters with email format.

Auditing a legacy validation rule that blocks new TLDs

A product manager reports that users with .photography or .technology email addresses cannot complete registration. The developer loads the existing validation regex into the tester and tests it against user@studio.photography. The pattern uses [a-zA-Z]{2,4} for the TLD component, which caps valid TLD length at four characters. Changing the upper bound from 4 to remove the cap entirely, producing {2,}, and retesting confirms the fix accepts all long-TLD addresses without opening the pattern to obviously invalid inputs.

Building a server-side pre-screen for a bulk email sender

Before dispatching to a large mailing list, a developer applies an email regex as a fast pre-screen to reject obviously malformed addresses before they reach the SMTP delivery layer. The pattern ^[\w.%+\-]+@[\w\-]+(\.[\w\-]+)+$ is tested against a representative sample of 100 real addresses from the list. Addresses that fail the pre-screen are flagged for manual review rather than silently rejected, preserving deliverability reputation by avoiding unnecessary bounce attempts at the mail server.

When to use this guide

Use this page when you need to build, adapt, or verify a regex pattern for email address validation in a form, API, or data pipeline.

Pro tips

Get better results with these expert suggestions:

1

Use a two-stage validation strategy: regex plus confirmation email

Regex confirms that a string is shaped like an email address according to the rules encoded in the pattern. It cannot determine whether the domain has valid MX records, whether the mailbox actually exists, or whether the address accepts incoming mail. Use regex as the first gate to reject obviously malformed input at form submission time, then send a confirmation email with a verification link. This combination catches both syntax problems and non-existent addresses without requiring an overly complex pattern.

2

Allow plus-sign subaddressing unless you have a specific reason not to

Many users create inbox filters using plus-sign subaddresses like user+signup@gmail.com or user+newsletter@fastmail.com. Patterns that omit + from the local part character class will silently reject these legitimate addresses. Include + alongside letters, digits, dots, underscores, and hyphens in the local part class: [a-zA-Z0-9._%+\-]+ covers the overwhelming majority of real addresses actually in use.

3

Do not cap TLD length at three or four characters

ICANN introduced hundreds of generic TLDs after 2014, many of which are longer than four characters: .academy, .consulting, .technology, .photography, .international. Using {2,} instead of {2,4} or {2,6} in the TLD component of your pattern accepts any current or future TLD without meaningfully weakening the filter, since a string with no at sign or domain structure will still fail the earlier components of the pattern.

4

Test with internationally common email providers

Include addresses from providers that use subdomains or country-code second-level domains in your test set: user@mail.company.co.uk, contact@empresa.com.br, info@firma.de. These formats are entirely legitimate and widely used but expose patterns with overly restrictive domain component classes that incorrectly reject addresses with dots in the domain portion between the subdomain and the TLD.

FAQ

Frequently asked questions

A practical, widely-used starting pattern is ^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$. This accepts the vast majority of real email addresses in active use, including those with plus-sign subaddressing, multi-label domains like sub.company.co.uk, and long TLDs introduced after 2014. It rejects strings with no at sign, strings with no domain component, and strings with no TLD. For most web applications, this pattern combined with a follow-up confirmation email is sufficient validation to prevent both bad data and non-existent addresses.
No. Regex validates the syntax and structure of a string: it can confirm that a string contains an at sign, a local part with permitted characters, and a domain with a TLD of at least two characters. It cannot determine whether the domain has valid DNS records, whether an MX record exists for the domain, whether the specific mailbox exists on that domain, or whether the address will accept incoming mail. The only definitive email validation is sending a message and requiring the recipient to confirm receipt via a link or code. In practice, teams pair a permissive regex with a double opt-in flow: the pattern rejects strings like "notanaddress" or "foo@" at submission time, an SMTP-level handshake in a background job confirms the domain accepts mail, and the verification link confirms the human reading that mailbox actually requested the signup. Each layer catches a different failure mode and the combined cost in friction is negligible compared with a bounce rate that damages sender reputation across your entire sending domain.
Most email validation patterns written before 2014 capped the TLD component at two to four characters, reflecting the fact that all TLDs at the time were two-character country codes or well-known three-letter generics like .com and .org. ICANN has since delegated hundreds of longer generic TLDs to registrars. Change the TLD quantifier in your pattern from {2,4} or {2,6} to {2,} to accept any current and future TLD length while retaining the minimum of two characters that distinguishes a TLD from a bare hostname label.
Yes. Plus-sign subaddressing, also called plus addressing or tagged addressing, is a standard feature supported by most major email providers including Gmail, Outlook, Fastmail, and ProtonMail. It allows users to create unique address variants like user+service@gmail.com for inbox filtering and tracking purposes. A meaningful portion of technically experienced users actively use this feature. Blocking it by omitting + from the local part character class frustrates these users with a rejection they cannot understand, since their address is entirely valid.
Remove the ^ and $ anchors from your pattern so the engine searches for email-shaped substrings rather than requiring the full string to be an email address, and enable the g flag to find all occurrences. The pattern [a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,} searches for all address-shaped substrings in the test text. In JavaScript code, use String.prototype.matchAll() or String.prototype.match() with the g flag to iterate over all matches and extract each address.
Per RFC 5321, the unquoted local part can contain letters, digits, and the special characters ! # $ % & ' * + - / = ? ^ _ ` { | } ~, plus dots that are not the first or last character and not consecutive. In practice, the overwhelming majority of email addresses in active use contain only letters, digits, dots, hyphens, underscores, and plus signs. A pattern covering this practical set handles real-world data reliably while remaining readable and maintainable.
Import the re module and use re.match(r'^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$', email_string). Using a raw string literal prefixed with r prevents Python from interpreting backslashes before the regex engine receives the pattern. For production Python code that requires strict RFC-compliant validation including DNS MX record checking, consider the email-validator package, which performs both structural parsing and optional DNS lookups that no regex-only approach can provide.
A theoretically complete regex that covers all RFC 5321 and 5322 syntactic forms including quoted local parts, domain literals with IP addresses, and nested comments is possible but impractically long. The most comprehensive version circulated online exceeds 6,000 characters and is effectively unmaintainable. No production team maintains a regex of that complexity. The standard approach is to use a simplified practical pattern for quick structural filtering and to rely on a purpose-built library such as Python's email-validator or JavaScript's validator.js for applications where RFC compliance and deliverability checking are genuine requirements.
Sign-up forms are the most exposed surface for email regex denial-of-service because the field accepts arbitrary user input that is evaluated server-side at high volume. Three precautions help. First, avoid nested quantifiers in your email pattern: rewrite ([a-zA-Z0-9]+\.)+[a-zA-Z]+ as the unrolled [a-zA-Z0-9]+(\.[a-zA-Z0-9]+)*. Second, set an absolute length cap (255 characters per RFC 5321) before applying the regex; truncating earlier ends any backtracking attempt in linear time. Third, if your runtime supports it, run the regex inside a timeout-bounded worker or use a library like safe-regex2 to statically detect dangerous patterns before deployment. Together these turn an attractive attack target into a routine validation.
IDN emails use non-ASCII characters in either the local part (SMTPUTF8) or the domain (punycode-encoded). A standard ASCII email regex rejects user@bücher.de directly but accepts the same address in its punycode form user@xn--bcher-kva.de. The pragmatic approach is to normalise before validating: if your form receives an address with non-ASCII characters in the domain, convert it to punycode using URL().hostname or a library like punycode.js, then run your existing pattern on the normalised result. For non-ASCII local parts, you generally need to either widen the local-part character class with Unicode property escapes under the u flag, or defer fully to a library that implements RFC 6531 SMTPUTF8 rules correctly.

Ready to get started?

Open the full Regex Tester — free, no account needed, works on any device.

Open Regex Tester →

Free · No account needed · Works on any device