Regex Email Validation — Pattern, Edge Cases & Best Practices

Email validation with regex seems simple until you start hitting edge cases: subaddresses, internationalized domains, IP literals, quoted local parts. This guide covers the practical patterns developers actually use, the edge cases they miss, and when to stop fighting the spec and just send a confirmation email.

The Standard Email Regex Pattern

The pragmatic email regex used by most production applications:

// Simple — catches 99% of typos const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; // More thorough — validates local part and domain structure const EMAIL_RE_STRICT = /^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$/; // HTML5 browser default (from the spec) const EMAIL_RE_HTML5 = /^[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])?)*$/;

Why Email Regex Is Harder Than It Looks

The email specification (RFC 5321 and RFC 5322) allows a wide range of formats that most developers don't expect to be valid:

EmailValid?Why
user@example.comYesStandard format
user+tag@example.comYesSubaddressing (+ trick) is valid
user.name@sub.example.co.ukYesSubdomain and 2-part TLD
user@[192.168.1.1]YesIP address literal is valid per RFC
"user name"@example.comYesQuoted local part allows spaces
user..name@example.comNo (usually)Consecutive dots in local part
user@exampleNoNo TLD — fails most validators
@example.comNoEmpty local part
user @example.comNoSpace in local part (unquoted)

HTML5 vs Regex Validation

<input type="email"> gives you browser-native validation for free. It uses the HTML5 living standard's email pattern, which is a reasonable practical validator. The browser shows a built-in error tooltip when the format is invalid.

<!-- Browser validates on submit --> <input type="email" name="email" required /> <!-- Add custom pattern for extra strictness --> <input type="email" name="email" pattern="[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}" required />

Caveat: HTML5 validation is bypassed by JavaScript form submission and by users with JavaScript disabled. Always validate server-side too.

JavaScript Email Validation Examples

// Basic validation function isValidEmail(email) { return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email); } // With trimming and lowercase normalization function validateEmail(input) { const email = input.trim().toLowerCase(); const re = /^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$/; return { valid: re.test(email), normalized: email, }; } // TypeScript typed version interface EmailValidationResult { valid: boolean; normalized: string; reason?: string; } function validateEmailTS(input: string): EmailValidationResult { const email = input.trim().toLowerCase(); if (!email) return { valid: false, normalized: email, reason: "Empty input" }; if (!email.includes('@')) return { valid: false, normalized: email, reason: "Missing @" }; const re = /^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$/; return { valid: re.test(email), normalized: email, reason: re.test(email) ? undefined : "Invalid format", }; }

Python Email Validation

import re EMAIL_RE = re.compile( r'^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$' ) def validate_email(email: str) -> bool: return bool(EMAIL_RE.match(email.strip().lower())) # Using the email-validator library (more thorough) # pip install email-validator from email_validator import validate_email, EmailNotValidError try: valid = validate_email("user@example.com") print(valid.email) # Normalized email except EmailNotValidError as e: print(str(e))

Go Email Validation

package main import ( "net/mail" "regexp" "strings" ) var emailRe = regexp.MustCompile( `^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$`, ) // Regex approach func isValidEmailRegex(email string) bool { return emailRe.MatchString(strings.TrimSpace(email)) } // Standard library approach (more lenient, RFC 5322 compliant) func isValidEmailStdlib(email string) bool { _, err := mail.ParseAddress(email) return err == nil }

Related Tools

Related Guides

FAQ

What is the best regex for email validation?

There is no single 'best' email regex — it depends on your strictness requirements. For most applications, a pragmatic pattern like /^[^\s@]+@[^\s@]+\.[^\s@]+$/ is sufficient. For RFC 5321 compliance, the pattern becomes extremely complex and is rarely worth the effort.

Should I validate email addresses with regex on the frontend?

Use regex for a quick sanity check to catch obvious typos (missing @, missing domain), but never rely on it for true validation. The only reliable way to validate an email address is to send a confirmation email and require the user to click a link.

Does HTML5 input type=email validate emails?

Yes. The browser's built-in email validation uses a pattern similar to /^[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])?)*$/. It's a reasonable baseline for most use cases.

Why is email validation with regex so difficult?

The email address specification (RFC 5321 and RFC 5322) is surprisingly complex. It allows quoted strings, comments, IP address literals, internationalized domain names (IDN), and subaddressing (the + trick). A fully RFC-compliant regex is thousands of characters long and hard to maintain.

How do I validate an email in JavaScript without a library?

Use a simple regex with test(): const isValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email). This rejects addresses without @, without a dot in the domain, and addresses with spaces — which covers the vast majority of user typos.