Understanding Email Validation Regex
Email validation with regular expressions is one of the most common tasks in web development. Every contact form, signup page, and newsletter subscription box needs to check whether the user typed a syntactically valid email address before sending it to a server. A well-crafted regex catches obvious typos instantly on the client side — before any network request.
The standard pattern /^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}/ is the result of decades of community refinement. It is not a perfect RFC 5321 implementation — that would be a 6,000-character monster — but it correctly validates 99.9% of real email addresses people actually type.
Breaking Down the Pattern
Every part of the regex has a specific job:
^— Start anchor. The pattern must match from the very beginning of the string, preventing a garbage prefix like[email protected]from passing.[a-zA-Z0-9._%+\-]+— Local part (before the @). Allows letters, digits, dots, underscores, percent signs, plus signs, and hyphens. The+quantifier requires at least one character.@— The literal at-sign that separates local part from domain.[a-zA-Z0-9.\-]+— Domain name. Allows letters, digits, dots (for subdomains), and hyphens. Matchesmail.google.comorsub.domain.co.uk.\.[a-zA-Z]{2,}— Top-level domain. Requires a literal dot followed by at least two letters — covers.com,.org,.photography, etc.$— End anchor. Ensures nothing comes after the TLD.
Language-Specific Usage
JavaScript
function isValidEmail(email) {
const pattern = /^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$/;
return pattern.test(email);
}
// Usage
isValidEmail('[email protected]'); // true
isValidEmail('@nodomain.com'); // false
isValidEmail('plaintext'); // false
isValidEmail('[email protected]'); // true (double dots allowed by this pattern)Python
import re
EMAIL_PATTERN = re.compile(
r'^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$'
)
def is_valid_email(email: str) -> bool:
return bool(EMAIL_PATTERN.match(email))
# Examples
is_valid_email('[email protected]') # True
is_valid_email('noDomainAtAll') # FalsePHP
function isValidEmail(string $email): bool {
$pattern = '/^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$/';
return (bool) preg_match($pattern, $email);
}
// PHP also ships with filter_var which uses a similar approach:
$valid = filter_var($email, FILTER_VALIDATE_EMAIL);Java
import java.util.regex.Pattern;
private static final Pattern EMAIL_PATTERN = Pattern.compile(
"^[a-zA-Z0-9._%+\\-]+@[a-zA-Z0-9.\\-]+\\.[a-zA-Z]{2,}$"
);
public static boolean isValidEmail(String email) {
return EMAIL_PATTERN.matcher(email).matches();
}Common Pitfalls and Edge Cases
Consecutive dots in the local part
The simple pattern above allows [email protected] (double dot). RFC 5321 forbids consecutive dots in the local part. Add a negative lookahead if you need strict compliance: /^(?!.*\.\.)…$/.
Leading or trailing dots
[email protected] and [email protected] pass the simple regex but are technically invalid. Add anchored assertions to reject them: /^[a-zA-Z0-9][a-zA-Z0-9._%+\-]*[a-zA-Z0-9]@…/ (requires the local part to start and end with an alphanumeric character when it is longer than one character).
New generic TLDs
ICANN now allows TLDs longer than 6 characters: .photography, .international, .academy. The {2,} quantifier in the pattern handles all current TLDs because there is no practical upper length limit.
Internationalised domain names (IDN)
Domains like münchen.de use Punycode encoding (mnchen-3ya.de) in the DNS system. The simple ASCII regex matches the Punycode form. If users type native Unicode domains, use a library with IDN support before running the regex.
When Not to Use Regex Alone
Regex validates syntax, not deliverability. An address like [email protected] passes regex validation even if the domain does not exist and no mailbox is configured. For production systems, add:
- DNS MX record check — verify the domain has mail exchange records.
- Confirmation email — the gold standard: send a link to the address and only activate the account when the link is clicked.
- Disposable email detection — block single-use addresses with a blocklist like disposable-email-domains on GitHub.
Comparison of Popular Email Regex Patterns
| Pattern | Complexity | Best for |
|---|---|---|
| /^[^@]+@[^@]+$/ | Minimal | Quick sanity check only |
| [a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,} | Standard | Most web forms ✅ |
| HTML5 type=email built-in | Browser-native | Simple HTML forms |
| RFC 5322 full pattern | Expert | Spec-compliant systems |
Testing Your Email Regex
Use the live Regex Tester above to run your pattern against a batch of test cases. A comprehensive test suite for email validation should include:
- Valid:
[email protected] - Valid:
[email protected] - Valid:
[email protected] - Valid:
[email protected] - Valid:
[email protected] - Invalid:
Abc.example.com(no @) - Invalid:
A@b@[email protected](multiple @) - Invalid:
user@(missing domain) - Invalid:
@example.com(empty local part)