Skip to main content
ByteKiwi

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.

6 min read
Regex Encoding Configuration

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

PatternAccepts user@example.comAccepts user+tag@sub.ioRejects user@.comRejects 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’t
  • user@thisdoesnotexist.xyz - domain doesn’t resolve
  • typo@gmial.com - common misspelling

For deliverability, you need:

  1. DNS MX record lookup - verify the domain accepts mail
  2. SMTP verification - connect to the mail server and check the mailbox (slow, often blocked)
  3. 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.