Regex Email Validation Patterns: What Works and What Doesn't
A developer's guide to email validation with regex - from the simple pattern that covers 99% of cases to RFC 5322 edge cases, plus JavaScript examples you can use today.
Email validation with regex is one of those tasks developers revisit every few years and find confusing each time. The pattern that looks too simple usually works fine. The technically correct one spans multiple lines and still misses real-world edge cases.
This guide cuts through the noise with patterns you can actually use.
Why email validation is tricky
The RFC 5321 and RFC 5322 specifications for email addresses allow far more than you’d expect:
# Valid per RFC 5321:
user+tag@example.com
"user name"@example.com
user@[192.168.1.1]
user@xn--nxasmq6b.com
very.unusual."@".unusual.com@example.com
A fully RFC-compliant regex is several hundred characters long and still misses some valid addresses. In practice, you want to catch obvious typos, not parse the full spec.
The pattern that covers 99% of cases
For most web applications, this pattern works well:
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
What it checks:
- Starts with one or more non-whitespace, non-@ characters
- Has exactly one
@ - Has a domain with at least one dot
- Domain doesn’t contain whitespace or additional
@symbols
emailRegex.test('user@example.com'); // true
emailRegex.test('user+tag@sub.domain.io'); // true
emailRegex.test('user@example'); // false - no dot
emailRegex.test('user @example.com'); // false - space in local part
emailRegex.test('@example.com'); // false - empty local part
emailRegex.test('user@@example.com'); // false - double @
Test this pattern live in the ByteKiwi Regex Tester.
A more complete pattern
When you need tighter validation (rejecting clearly malformed addresses):
const emailRegex =
/^[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])?)*\.[a-zA-Z]{2,}$/;
This pattern:
- Allows all RFC 5321 special characters in the local part
- Validates each domain label (no leading/trailing hyphens)
- Requires a TLD of at least 2 characters
Pattern comparison
| Pattern | Accepts user@example.com | Accepts user+tag@sub.io | Rejects user@.com | Rejects user@com |
|---|---|---|---|---|
| Simple | ✓ | ✓ | ✗ | ✗ |
| Complete | ✓ | ✓ | ✓ | ✓ |
| HTML5 | ✓ | ✓ | ✓ | ✓ |
JavaScript examples
Basic validation function
function isValidEmail(email) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email.trim());
}
isValidEmail('alice@example.com'); // true
isValidEmail(' alice@example.com'); // true (trimmed)
isValidEmail('not-an-email'); // false
Form validation with feedback
function validateEmailField(input) {
const value = input.value.trim();
const emailRegex = /^[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])?)*\.[a-zA-Z]{2,}$/;
if (!value) return { valid: false, message: 'Email is required' };
if (!emailRegex.test(value)) return { valid: false, message: 'Enter a valid email address' };
return { valid: true };
}
Extract emails from a block of text
const text = `
Contact us at support@example.com or billing@example.org.
For urgent matters: alice@team.io
`;
const emailPattern = /[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}/g;
const emails = text.match(emailPattern);
// ['support@example.com', 'billing@example.org', 'alice@team.io']
What regex can’t catch
Regex validates format, not deliverability. These all pass any regex:
fake@example.com- domain exists but address doesn’tuser@thisdoesnotexist.xyz- domain doesn’t resolvetypo@gmial.com- common misspelling
For deliverability, you need:
- DNS MX record lookup - verify the domain accepts mail
- SMTP verification - connect to the mail server and check the mailbox (slow, often blocked)
- Email confirmation flow - the only reliable method
Common edge cases
Plus addressing (subaddressing)
Gmail and many providers support user+label@example.com. This is a single valid address - the label is often stripped by the recipient’s server. Your regex must allow + in the local part.
// ✓ Allow plus signs
/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test('user+newsletter@gmail.com'); // true
Subdomains
alice@mail.company.co.uk // valid - multiple domain labels
alice@sub.sub.example.com // valid - deeply nested subdomain
New TLDs
As of 2024 there are over 1,500 TLDs including .photography, .academy, and .xn--p1ai (Cyrillic IDN). Any regex requiring a short TLD list will reject real addresses.
Case sensitivity
The local part of an email is technically case-sensitive per RFC 5321, but in practice most providers treat it as case-insensitive. Normalize to lowercase before storage and comparison:
const normalized = email.trim().toLowerCase();
Testing patterns
The fastest way to iterate on a regex is to run it against a set of test cases. Use the Regex Tester to paste in your pattern and check multiple inputs at once.
A solid test suite for email validation:
const valid = [
'user@example.com',
'user+tag@example.com',
'user.name@sub.example.co.uk',
'user123@example.io',
'a@b.co',
];
const invalid = [
'user',
'@example.com',
'user@',
'user @example.com',
'user@@example.com',
'user@example',
'',
];
FAQ
Should I use a regex or an email validation library?
For most apps, a simple regex is enough. Libraries like validator.js or zod include well-tested patterns so you don’t have to maintain your own. Use a library when you need i18n support or want battle-tested edge case handling.
What regex does the HTML <input type="email"> use?
The WHATWG spec defines a specific pattern. It’s intentionally not RFC-compliant but handles the real-world majority of addresses. You can rely on native browser validation and add your own check for non-browser contexts.
How do I validate email in TypeScript?
function isEmail(value: string): boolean {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value.trim());
}
Or with Zod:
import { z } from 'zod';
const schema = z.object({ email: z.string().email() });
Does my regex need to handle Unicode email addresses?
Internationalized email addresses (e.g., 用户@例子.广告) are technically valid per RFC 6531 but are rarely supported end-to-end. If you’re building for a global audience, add the Unicode property escapes \p{L} and \p{N} to your character classes and use the u flag.
Why do regex email validators disagree?
Because the RFC specification is complex and there’s no single “correct” interpretation for real-world use. Different tools prioritize different trade-offs between strictness, false positives, and implementation complexity.