How the pattern works
| Part | Meaning |
|---|---|
^ | Start of the string |
[A-Za-z0-9._%+-]+ | The local part: one or more letters, digits, dots, underscores, percent, plus or hyphen signs |
@ | A literal @ |
[A-Za-z0-9.-]+ | The domain name, including subdomains |
\. | A literal dot before the top-level domain |
[A-Za-z]{2,} | The top-level domain: two or more letters (com, io, museum) |
$ | End of the string |
Code examples
JavaScript
const re = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/;
re.test(value); // true or falsePython
import re
bool(re.fullmatch(r'[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}', value))PHP
preg_match('/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/', $value) === 1;
Notes and limitations
This is the practical pattern most sign-up forms use. It accepts some technically odd addresses (two dots in a row) and rejects rare valid ones (quoted local parts, IP-address domains). The only real test of an email address is sending a confirmation link — in HTML forms, <input type="email"> gives you browser validation for free.