Email Addresses That Break Software: Validation Edge Cases
Quoted local parts, IPv6 literals, the 64/254-character limits, 769 TLDs a {2,4} regex rejects: 32 email validation edge cases tested against 8 validators.
By VincentPublished September 4, 2026Last updated September 4, 202613 min read

Names taught us to distrust validation. Birthdays taught us to distrust arithmetic. Phone numbers taught us to distrust interpretation. The fourth field in this series is the one every form on the internet asks for: the email address.
Everyone has a regex for it. Almost nobody has read the grammar that regex claims to implement, and almost no two implementations agree. So instead of arguing, we measured. We took 32 edge-case addresses and ran them through eight validators that people actually ship.
The 32 break down as 14 addresses that RFC 5321 permits, 14 that it forbids, and 4 that are legal only under the 2012 extension for non-ASCII email. The eight validators disagreed on 19 of them. Every validator rejected at least one address the standard allows. All eight rejected the same valid one.
What the standards actually say
Two documents define an email address. RFC 5321, the SMTP specification, defines the mailbox a mail server accepts [rfc5321]. RFC 5322, the message-format specification, defines the same shape as it appears in a message header [rfc5322]. Both agree on the outline: a local part, an @, and a domain.
The local part is everything before the @. It can take two forms. A dot-string is made of letters, digits and the specials !#$%&'*+-/=?^_`{|}~, in runs separated by single dots; a dot may not start it, end it, or repeat. A quoted string is anything inside double quotes, including spaces and a second @.
The domain is everything after the @. Usually it is a hostname: labels of letters, digits and hyphens, joined by dots. No label may start or end with a hyphen, and none may be longer than 63 characters [rfc1035]. The domain can also be an IP address in square brackets, such as [192.168.1.1]. An IPv6 address must carry the IPv6: tag inside the brackets.
The length limits are the most misquoted part, so the table gives them with section numbers. The 320-character figure that circulates online is not a rule. It is 64 + 1 + 255, the sum of two ceilings that can never be reached at the same time, because the path that carries the address is capped first.
| What | Limit | Where it is written | What people quote instead |
|---|---|---|---|
| Local part (before the @) | 64 octets | RFC 5321 §4.5.3.1.1 | — |
| Domain (after the @) | 255 octets | RFC 5321 §4.5.3.1.2 | — |
| Whole address | 254 characters | RFC 5321 §4.5.3.1.3 (path 256 incl. < >), erratum 1690 | 320 (= 64 + 1 + 255, unreachable) |
| One domain label | 63 octets | RFC 1035 §2.3.4 | — |
| Number of dots in the domain | none required | RFC 5321 §4.1.2 (Domain = sub-domain *("." sub-domain)) | "at least one" |
| Top-level domain length | no limit in the grammar | RFC 1035 label rule: up to 63 | 2 to 4 letters |
The edge cases that actually break systems
The local part can contain almost anything
Unquoted, the local part already allows nineteen punctuation characters that most hand-written whitelists forbid. The address !#$%&'*+-/=?^_`{}|~@example.org uses every one of them, and it is valid [rfc5322]. Six of our eight validators accept it. The two that reject it are Zod 3 and Zod 4, whose default pattern is deliberately narrower than the grammar [zod-email].
The plus sign matters most in practice. The tag convention, where user+shop@example.com delivers to user@example.com, is documented in RFC 5233 [rfc5233] and honoured by Gmail, Outlook.com, Fastmail and Proton. Forms that reject a plus are not enforcing a standard. They are enforcing a business rule about one person holding many tags, and they should say so.
Quoted local parts are the opposite case: fully legal, almost never seen. "john doe"@example.com is a valid mailbox with a space in it. The famous "very.(),:;<>[]\".VERY.\"very@\\ \"very\".unusual"@strange.example.com is valid too [wiki-email]. Exactly one of the eight validators, validator.js, accepts either. Rejecting them is a reasonable product decision, because no mainstream provider will create such a mailbox. It should be a decision, though, not an accident of the regex.
Dots go the other way. The grammar forbids a dot at the start or end of the local part, and two in a row. So .user@example.com, user.@example.com and Abc..123@example.com are all invalid. The browser's own type=email input accepts all three. Its regex permits them, and the HTML Standard openly calls this a "willful violation of RFC 5322", chosen because real mail servers were seen accepting such addresses [whatwg-email].
Case is the last trap. RFC 5321 §2.4 says the receiving host must treat the local part as case-sensitive, and in the same section discourages anyone from relying on it. No major provider distinguishes John@ from john@. Gmail goes further and ignores dots, so j.smith and jsmith reach the same inbox [gmail-dots]. String equality is therefore not address equality, which matters the moment an email is a unique key.
The domain is not letters, a dot and two-to-four letters
The most-copied domain pattern ends in \.[a-z]{2,4}$. That rule was roughly true in 2005. It is now wrong for most of the root zone.
We counted the IANA list on 2026-09-04 [iana-tlds]. There are 1,438 top-level domains. 248 are two letters (the country codes), 216 are three, and 205 are four. The remaining 769, or 53.5%, are longer than four characters, and the pattern rejects every one of them. That includes all 151 internationalised TLDs, whose on-the-wire form starts with xn-- and runs from 8 to 24 characters. It also includes plain ASCII names as long as .travelersinsurance, at 18. The longest of all is xn--vermgensberatung-pwb, the ASCII form of .vermögensberatung, at 24.

| TLD length | Count | Share | Examples |
|---|---|---|---|
| 2 characters | 248 | 17.2% | .us .jp .de — every country-code TLD |
| 3 characters | 216 | 15.0% | .com .org .app .dev |
| 4 characters | 205 | 14.3% | .info .shop .blog .zip |
| 5–6 characters | 313 | 21.8% | .email .photo .museum .travel |
| 7–8 characters | 205 | 14.3% | .finance .software .xn--p1ai (.рф) |
| 9–11 characters | 179 | 12.4% | .marketing .technology .photography |
| 12–24 characters | 72 | 5.0% | .international .travelersinsurance .xn--vermgensberatung-pwb |
| Longer than 4 (total) | 769 | 53.5% | rejected by \.[a-z]{2,4}$ |
Below the top level, the grammar allows things the regexes reject, and forbids things they accept. user@localhost is syntactically valid, because RFC 5321 requires no dot in a domain. ICANN has prohibited dotless names for new generic TLDs since 2013 [icann-dotless], but every intranet and every developer laptop has addresses like it. The HTML5 input and Angular accept it; the other six reject it.
Address literals are the reverse. user@[192.168.1.1] and user@[IPv6:2001:db8::1] are both valid under §4.1.3 [rfc5321]. Only two validators accept the IPv4 form, and none of the eight accepts the IPv6 form. validator.js has an allow_ip_domain option for it, off by default [validatorjs]. Meanwhile the one-line regex happily accepts user@-example.com, user@exam_ple.com and user@example.com., none of which is a legal hostname.
One valid address deserves a closer look precisely because all eight validators accepted it. user@xn--80ak6aa92e.com is pure ASCII and perfectly formed. It is also the encoded form of аррӏе.com written in Cyrillic, the 2017 demonstration that a browser can show apple.com for a domain that is not Apple's [wiki-homograph]. Syntax validation cannot tell you that, and it is not supposed to. A sign-up form that treats "valid" as "trustworthy" has confused the two.
The length limits nobody enforces
The limits in the table above are the least-enforced rules in the standard. We built three addresses, each exactly one character over a line: a 65-character local part, a 255-character address, and a 64-character domain label.
Six of eight validators accepted the over-long local part. Five accepted the over-long address. Four accepted the over-long label. Angular's Validators.email was the only one to reject all three, because its regex carries explicit length checks for 64 and 254 [angular-email]. Python's email-validator rejected the 255-character address with the message "1 character too many", yet accepted the 65-character local part [py-email-validator].
This is not academic. An address that passes your form and fits your varchar(255) column can still be refused by the first SMTP server that sees it. The refusal arrives as a bounce, hours later, attributed to nothing.
Unicode is three different problems
The domain. user@例え.jp is how a person writes the address. user@xn--r8jz45g.jp is how it travels. IDNA converts the Unicode form (the U-label) into an ASCII form starting xn-- (the A-label) before DNS ever sees it [rfc5890]. A validator that rejects the Unicode form is not wrong; it is telling you to convert first. Python's email-validator does the conversion for you and hands back the ASCII domain. Three of our eight accept the Unicode form as typed. The other five reject it.
The local part. üser@example.com and θσερ@εχαμπλε.ψομ are illegal under RFC 5321 and legal under RFC 6531, the SMTPUTF8 extension of 2012, which both the sending and the receiving server must support [rfc6531]. Gmail has accepted such addresses since 2014 [gmail-eai], so they exist in the wild. The same three validators accept them. The HTML5 input rejects them by design, since its grammar is ASCII-only, and so do Zod, Angular and the emailregex.com pattern. Whether you should accept them depends on whether your mail provider can deliver to them. That is a question for your provider, not your regex.
Characters that are wrong but invisible. This is the one that hurts. A full-width @ (U+FF20) is what a Japanese or Chinese keyboard produces when the input mode is left on. user@example.com contains no @ at all, and all eight validators reject it. That is correct, but the error message shows the user an address that looks right.
Worse is user@example.com followed by a zero-width space (U+200B). It survives copy-and-paste from chat apps and web pages, and it renders as nothing. validator.js accepts it, in the local part or the domain; so does the one-line regex. Python's email-validator rejects it with the phrase "unsafe characters", which is the behaviour you want. Finally, user@exаmple.com with a Cyrillic а is accepted by the three Unicode-tolerant validators. It would be delivered to xn--exmple-4nf.com, a domain that is not example.com.
An email address is not an identity
Everything above concerns whether a string is an address. A separate class of bugs assumes that one address is one person, or one person is one address. Gmail's dot-insensitivity makes j.smith@gmail.com and jsmith@gmail.com one mailbox. Plus tags make smith+a@ and smith+b@ one mailbox. Case makes Smith@ and smith@ one mailbox. And a role address such as billing@ is many people.
If an email is your unique key, write the equivalence rule down. Lower-case the domain. Compare the local part case-insensitively. Decide per provider whether to strip dots and tags. Store the address as the user typed it. Disposable domains are a different question again, covered in disposable email vs fake email.
Addresses that are safe to put in test data
The safe choice is the one the standards made for you. example.com, example.net and example.org are reserved by RFC 2606 [rfc2606] and listed in the special-use registry of RFC 6761 [rfc6761]. They also publish a null MX record. We checked example.com on 2026-09-04: its MX record is 0 . (a zero and a lone dot). RFC 7505 defines that record as a statement that the domain accepts no mail, so a conforming sender does not even try [rfc7505]. The reserved top-level domains .test, .example and .invalid work the same way.
What is not safe is anything that merely looks fake. test@test.com and test@gmail.com are real domains with real inboxes. A verification link sent to one is a verification link sent to a stranger. Every address from our email generator and identity generator is at one of the three reserved domains, for exactly this reason.
8 validators versus 32 edge cases (2026)
We chose validators by how often they are shipped, not by how correct they claim to be:
- the regex the HTML Standard specifies for input type=email [whatwg-email];
- Zod 3.25's z.string().email() and Zod 4.5's z.email() [zod-email];
- validator.js 13.15's isEmail with default options [validatorjs];
- the regex inside Angular's Validators.email [angular-email];
- Python email-validator 2.3, with deliverability checks turned off [py-email-validator];
- the one-line ^[^\s@]+@[^\s@]+\.[^\s@]+$ that Stack Overflow has copied more than any other;
- the pattern emailregex.com presents as the RFC 5322 standard [emailregex].
Each address was scored against RFC 5321 on 2026-09-04. The 28 ASCII cases have an unambiguous verdict. The 4 Unicode cases are legal only with SMTPUTF8, so they are reported separately rather than scored. In the tables, read across a row to see how one address fared, and down a column to see one validator's habits.

| Valid address | Why it is valid | HTML5 | Zod 3 | Zod 4 | validator.js | Angular | Python email-validator | one-line regex | emailregex.com |
|---|---|---|---|---|---|---|---|---|---|
| simple@example.com | baseline dot-string | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| first.last+tag@example.com | plus subaddress (RFC 5233) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| x@example.com | one-character local part | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| !#$%&'*+-/=?^_`{}|~@example.org | every atext special (RFC 5322 §3.2.3) | ✓ | ✗ | ✗ | ✓ | ✓ | ✓ | ✓ | ✓ |
| "john doe"@example.com | quoted local part with a space | ✗ | ✗ | ✗ | ✓ | ✗ | ✗ | ✗ | ✗ |
| "very.(),:;<>[]\".VERY.\"very@\\ \"very\".unusual"@strange.example.com | quoted local part with @ and escapes | ✗ | ✗ | ✗ | ✓ | ✗ | ✗ | ✗ | ✗ |
| user@[192.168.1.1] | IPv4 address literal (§4.1.3) | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✓ | ✓ |
| user@[IPv6:2001:db8::1] | IPv6 address literal with tag (§4.1.3) | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ |
| user@localhost | dotless domain (§4.1.2) | ✓ | ✗ | ✗ | ✗ | ✓ | ✗ | ✗ | ✗ |
| user@example.museum | 6-letter TLD | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| user@example.photography | 11-letter TLD | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| user@xn--80ak6aa92e.com | IDN domain as A-label | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| a…a@example.com (64 a's) | local part at the 64-octet maximum | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| 254-character address | whole address at the maximum | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Invalid address | Why it is invalid | HTML5 | Zod 3 | Zod 4 | validator.js | Angular | Python email-validator | one-line regex | emailregex.com |
|---|---|---|---|---|---|---|---|---|---|
| Abc..123@example.com | consecutive dots | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | ✓ | ✗ |
| .user@example.com | leading dot | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | ✓ | ✗ |
| user.@example.com | trailing dot before the @ | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | ✓ | ✗ |
| john doe@example.com | unquoted space | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ |
| user@@example.com | two @ signs | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ |
| user@-example.com | label begins with a hyphen | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✓ | ✗ |
| user@exam_ple.com | underscore in a domain label | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✓ | ✗ |
| user@example.com. | trailing dot on the domain | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✓ | ✗ |
| user@[2001:db8::1] | IPv6 literal without the IPv6: tag | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ |
| a…a@example.com (65 a's) | local part one over 64 octets | ✓ | ✓ | ✓ | ✗ | ✗ | ✓ | ✓ | ✓ |
| 255-character address | one over the 254 maximum | ✓ | ✓ | ✓ | ✗ | ✗ | ✗ | ✓ | ✓ |
| user@a…a.com (64 a's) | domain label one over 63 octets | ✗ | ✓ | ✓ | ✗ | ✗ | ✗ | ✓ | ✓ |
| user@example.com | full-width @ (U+FF20), no ASCII @ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ |
| user@example.com + U+200B | zero-width space appended | ✗ | ✗ | ✗ | ✓ | ✗ | ✗ | ✓ | ✗ |
| Unicode address | What it is | HTML5 | Zod 3 | Zod 4 | validator.js | Angular | Python email-validator | one-line regex | emailregex.com |
|---|---|---|---|---|---|---|---|---|---|
| user@例え.jp | IDN domain as U-label (→ xn--r8jz45g.jp) | ✗ | ✗ | ✗ | ✓ | ✗ | ✓ | ✓ | ✗ |
| üser@example.com | non-ASCII local part | ✗ | ✗ | ✗ | ✓ | ✗ | ✓ | ✓ | ✗ |
| θσερ@εχαμπλε.ψομ | Greek local part and domain | ✗ | ✗ | ✗ | ✓ | ✗ | ✓ | ✓ | ✗ |
| user@exаmple.com | Cyrillic а homograph (→ xn--exmple-4nf.com) | ✗ | ✗ | ✗ | ✓ | ✗ | ✓ | ✓ | ✗ |
What the tables show, validator by validator:
- Thirteen unanimous verdicts, nineteen splits. Eight valid addresses were accepted by all, and five addresses were rejected by all. One of those five, user@[IPv6:2001:db8::1], is valid. No validator we tested accepts an IPv6 literal, and only two accept the IPv4 form.
- HTML5 breaks the RFC on purpose and has no length rule. Five false accepts: the three dot cases the specification calls a willful violation, plus the over-long local part and the over-long address. Its four false rejects are the quoted strings and the two literals.
- Zod 3 and Zod 4 gave identical verdicts on all 32: 19 correct, 3 false accepts (the three length cases) and 6 false rejects (specials, quoted strings, literals, dotless). Zod 4 adds presets we also checked: z.regexes.html5Email accepts the specials, rfc5322Email accepts the quoted local part, and unicodeEmail accepts üser@example.com [zod-email].
- Angular was the only validator with zero false accepts, because its regex encodes the 64- and 254-character limits. It rejects the two quoted strings and the two literals.
- validator.js accepted the most valid addresses, including the quoted strings nothing else took, and rejected only the literals and the dotless host. But it accepts a zero-width space anywhere in the address.
- Python's email-validator normalises rather than matches. It converts IDN domains to A-labels, names the full-width @ and the zero-width space in its errors, and explains every rejection in a sentence. It accepted the 65-character local part.
- The one-line regex is a presence check for an @ and a dot, and that is all it is. Ten of the 14 invalid addresses pass, including underscores, hyphens at the edge of a label, a trailing dot and an invisible character.
How our generator handles email — including the bugs we shipped
Every profile from our identity generator carries an email address. The history of that one field is three bugs long.
The domain. Until 2026-08-16 the generator drew from teleworm.us, rhyta.com, jourrapide.com, dayrep.com and armyspy.com. Those domains look inert and are not. Four of the five have live mail-exchanger records pointing at a public throwaway-inbox service, where anyone who types an address can read its mail. So a "fake" address really did receive mail. A user who tested a sign-up flow with one sent the verification or password-reset link into a mailbox the whole internet could open.
The fix was the one the standards already provide: the three RFC 2606 domains with a null MX. It is the email analogue of the 555-01XX phone block and the never-issued SSN range. The safety comes from a reserved range, not from a domain nobody seems to be using.
The handle. An address is derived from the name: first initial, surname, a number. The derivation began by deleting every character that was not an ASCII letter. For the nine countries whose names are not written in Latin script, that deleted the entire name. Japanese, Korean, Chinese, Russian, Greek, Ukrainian, Thai, Hebrew and Taiwanese profiles shipped addresses like 91@example.com on 100% of draws. Those now fall back to a Latin word pair, which is why roughly a quarter of all generated handles read like cobaltfalcon42 rather than a name.
The letters. The third bug is the one this post found. It is the same deletion, applied to Latin names with diacritics. Müller became mller. Suárez became surez. Đoàn became on, because its Đ does not even decompose to a D plus a mark.
We measured it on 2026-09-04 over 400 seeded identities for each of our 38 countries, 15,200 addresses in all. 1,782 of them, 11.7%, had lost at least one letter; 2,258 letters were lost in total. Seventeen countries were affected. The worst were the ones whose spelling leans hardest on accents: 85.3% of Vietnamese handles, 72.5% of Turkish, 58.3% of Hungarian, 43% of Spanish.

| Country | Handles affected | Example before | Same name after |
|---|---|---|---|
| Vietnam | 85.3% | Quỳnh Đoàn → qon | qdoan |
| Turkey | 72.5% | Neslişah Evliyaoğlu → nevliyaolu | nevliyaoglu |
| Hungary | 58.3% | Mia Pintér → mpintr | mpinter |
| Spain | 43.0% | Gabriel Suárez Guerrero → gsurezguerrero | gsuarezguerrero |
| Mexico | 38.0% | Jesús Sotelo Delacrúz → jsotelodelacrz | jsotelodelacruz |
| Poland | 34.8% | Amanda Woliński → awoliski | awolinski |
| Sweden | 30.8% | Torbjörn Mårtensson → tmrtensson | tmartensson |
| Finland | 20.3% | Annikki Järvinen → ajrvinen | ajarvinen |
| Norway | 15.3% | Marie Østli → mstli | mostli |
| Switzerland | 11.5% | Yvonne Hürlimann → yhrlimann | yhurlimann |
| Portugal | 10.3% | Romeu Araújo → rarajo | raraujo |
| Germany | 10.0% | Sanja Bürklein → sbrklein | sburklein |
| Austria | 9.5% | Mona Börner → mbrner | mborner |
| Denmark | 3.3% | Ella Jørgensen → ejrgensen | ejorgensen |
| France | 1.5% | Ève Laurent → laurent | elaurent |
| Italy | 0.8% | Evaldo Patanè → epatan | epatane |
| Brazil | 0.8% | Ígor Braga → braga | ibraga |
The fix is to fold before stripping. Unicode normalisation form D splits ü into u plus a combining mark, and removing the marks leaves the base letter. That alone handles ü, ğ, ỳ, ő and every accented vowel. A short table covers the letters that do not decompose: ß to ss, ø to o, æ to ae, œ to oe, ł to l, đ to d, ð to d, þ to th, dotless ı to i. Only after that does the strip remove what genuinely has no Latin letter in it.
Re-run over the same 15,200 seeds, the count of handles missing a letter is zero. The median address grew from 22 characters to 23: the missing letters, put back.
Two honest limits remain. Across the 15,200 addresses there were 14 duplicates, all but two of them in the nine fallback countries. There, a pool of 256 word pairs and a two-digit number allows about 25,000 distinct handles, and 400 draws collide about as often as the birthday paradox predicts. If you need uniqueness at scale, key on more than one field.
And the generator never emits a quoted local part, an address literal or a non-ASCII address. That is by design: its job is realistic addresses at a domain that cannot receive mail. If you want your validator exercised against those cases, take them from the tables above. The free API will give you a thousand well-formed ones to sit alongside them.
The conclusion is the one this series keeps reaching: validate less, test more. Accept the plus, the specials and the long TLD. Reject only what no server on earth would take: a missing @, whitespace, more than 254 characters. Convert Unicode domains rather than refusing them. Spend the effort you save on a fixture file with the 254- and 255-character addresses, the IPv6 literal and the zero-width space. Those are the cases the eight most-shipped validators disagree about today.
The earlier fields in this series are names, birthdays and phone numbers. The charts on this page are CC BY 4.0: reuse them with a link back here. And re-run our counts against the IANA list on the day you publish. The number of TLDs is one of the few facts in this post that will be different next year.
References & sources
- RFC 5321: Simple Mail Transfer Protocol — §4.1.2 Mailbox syntax, §4.1.3 address literals, §4.5.3.1 size limits — IETF
- RFC 5322: Internet Message Format — §3.2.3 atext, §3.4.1 addr-spec — IETF
- RFC 5321 Erratum 1690: the 256-octet path limit includes the angle brackets, so an address is at most 254 — RFC Editor
- RFC 1035: Domain Names — Implementation and Specification (§2.3.4 label limit of 63 octets) — IETF
- RFC 5233: Sieve Email Filtering — Subaddress Extension (the user+detail convention) — IETF
- RFC 6531: SMTP Extension for Internationalized Email (SMTPUTF8) — IETF
- RFC 5890: Internationalized Domain Names for Applications — U-labels and A-labels — IETF
- RFC 2606: Reserved Top Level DNS Names — example.com, .test, .example, .invalid — IETF
- RFC 6761: Special-Use Domain Names — IETF
- RFC 7505: A Null MX Resource Record for Domains That Accept No Mail — IETF
- HTML Standard: the E-mail state of input, its regex and the "willful violation of RFC 5322" — WHATWG
- Root zone database — the list of top-level domains (version 2026090400) — IANA
- New gTLD dotless domain names prohibited (2013) — ICANN
- Zod API reference — emails: the default pattern and the html5Email, rfc5322Email and unicodeEmail presets — Zod
- validator.js — isEmail options, including allow_ip_domain — GitHub
- Validators.email — the built-in email validator and its regex — Angular
- email-validator: a robust email address syntax and deliverability validation library for Python — PyPI
- Email address regular expression that 99.99% works — the "RFC 5322 official standard" pattern — emailregex.com
- A first step toward more global email — Gmail accepts non-Latin addresses (2014) — Google
- Dots don't matter in Gmail addresses — Google
- Email address — examples of valid and invalid addresses — Wikipedia
- IDN homograph attack — the 2017 аррӏе.com (xn--80ak6aa92e.com) demonstration — Wikipedia
Frequently asked questions
What is the maximum length of an email address?+
254 characters. RFC 5321 limits the local part to 64 octets and the domain to 255. It also caps the whole forward-path at 256 octets, including the angle brackets around the address. So the address itself cannot exceed 254; the RFC Editor's erratum 1690 spells this out. The 320 figure often quoted is just 64 + 1 + 255, a sum of two limits that can never be reached at the same time.
Is a plus sign valid in an email address?+
Yes. The plus is one of the characters RFC 5322 allows unquoted in the local part. The tag convention, where user+shop@example.com delivers to user@example.com, is described in RFC 5233 and supported by Gmail, Outlook.com, Fastmail and Proton. All eight validators we tested accept it. Forms that reject it use a hand-written character whitelist, usually to stop one person registering many tags.
Are email addresses case-sensitive?+
Technically the local part is: RFC 5321 says the part before the @ must be treated as case-sensitive by the receiving server, while the domain never is. In practice no major provider distinguishes John@ from john@, and Gmail also ignores dots in the local part. Store the address as typed, lower-case the domain, and compare the local part case-insensitively when you check for duplicates.
Can an email address contain non-ASCII characters like ü or 例?+
In the domain, yes: the Unicode form is converted to an ASCII form such as xn--r8jz45g.jp before it reaches DNS. In the local part, only under RFC 6531 (SMTPUTF8, 2012), which both mail servers must support; Gmail has accepted such addresses since 2014. Of the eight validators we tested, three accept üser@example.com and five reject it, including the browser's own type=email input, whose grammar is ASCII-only.
What is the best regex to validate an email address?+
None of them is correct, so pick one whose mistakes you can name. In our test the HTML5 type=email regex, Angular's Validators.email and validator.js each got 19 to 24 of 28 RFC cases right, and the one-line ^[^\s@]+@[^\s@]+\.[^\s@]+$ got 14. The reliable check is not a regex at all: require exactly one @ with something on both sides, cap the length at 254, and confirm the address by sending to it.
Which email addresses are safe to use in test data?+
Addresses at example.com, example.net and example.org. RFC 2606 reserves them, and they publish a null MX record (0 .) that tells mail servers not to attempt delivery at all. Any address under the reserved .test, .example or .invalid top-level domains works too. Do not use test@test.com or test@gmail.com: those are real domains, and the inbox may belong to someone.
More on test data practice
- Mock Data vs. Real Data: Why Teams Test With Fake Profiles
- Deterministic Test Data: Why Seeding Beats Random Generation
- Test Data Management: 9 Best Practices
- Synthetic Data for Machine Learning: When and How to Use It
- Birthdays That Break Software: Date Edge Cases for QA
- What Is Synthetic Test Data? A Developer's Guide