Developer Toolbox

Regex: Email address

This pattern accepts what people type into a sign-up form: a local part of letters, digits and ._%+-, an @, a domain with at least one dot, and a top-level domain of two or more letters. It is deliberately simpler than the email standard, which allows addresses no real form needs.

Open in Regex Tester The pattern and every example below are filled in.

Pattern

^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$

How it works

^
Start of the string.
[A-Za-z0-9._%+-]+
The local part: one or more letters, digits, dots, underscores, %, + or -.
@
The at sign.
[A-Za-z0-9.-]+
The domain, with any subdomains: letters, digits, dots and dashes.
\.
A literal dot before the top-level domain.
[A-Za-z]{2,}
The top-level domain: two or more letters (io, com, museum).
$
End of the string.

In your language

JavaScript
/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/

A literal; new RegExp(source, flags) builds the same from a string.

Python
re.compile(r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$")

A raw string, so backslashes reach re as written. re.ASCII keeps \d to 0-9, as in JavaScript (Python matches any Unicode digit otherwise). Use re.fullmatch to test a whole string.

Java
Pattern.compile("^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$")

A normal string literal, so every backslash is doubled. matcher(s).matches() tests the whole string.

Go
regexp.MustCompile(`^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$`)

A raw string in backticks. RE2 runs in linear time but has no lookaround and no backreferences.

PHP
preg_match('/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/D', $input)

PCRE with / delimiters inside a single-quoted string. Without the D modifier, $ also matches before a final newline, so it is added to patterns that end in $.

C#
new Regex(@"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$")

A verbatim string: backslashes stay, a quote is doubled. RegexOptions.ECMAScript keeps \d to 0-9, as in JavaScript. $ also matches before a final newline; to reject one, end the pattern with \z instead.

Common mistakes

  • Not RFC 5322

    The standard allows quoted local parts ("john doe"@example.com) and IP literals (user@[192.0.2.1]). This pattern rejects them, which is what most forms want.

  • International addresses

    Domains in other scripts pass only in their punycode form (xn--...) and only under an ASCII top-level domain, and local parts with letters outside ASCII (josé@example.com) fail. In JavaScript (with the u flag), Java, .NET and PHP (with the u modifier), \p{L} matches any letter; Python's re has no \p, the third-party regex module does.

  • Valid is not deliverable

    A typo like [email protected] passes. The only real check is a confirmation email with a link in it.