After reading dozens of RFCs and testing hundreds of implementations, certain failure patterns repeat reliably. Knowing them in advance lets you target your tests at the most likely defects.
Gotcha 1: The Regex That Rejects Valid Input
The most common RFC conformance failure is a regex used as a validator that was written from memory rather than derived from the spec. These regexes typically:
- Restrict the character set more than the RFC allows (missing
+,!,#,^, etc.) - Disallow structures that are valid per RFC (quoted strings, percent-encoding, IP literals)
- Include constraints that weren't in the original spec (TLD length limits, minimum label count)
How to find it: take the full list of valid characters from the ABNF definition and test each one individually. For email local parts: !, #, $, %, &, ', *, +, -, /, =, ?, ^, _, `, {, |, }, ~. Any rejection is a bug.
Gotcha 2: Case-Sensitivity on Case-Insensitive Fields
Many RFC tokens are explicitly case-insensitive. HTTP method names are case-sensitive per RFC (GET ≠ get) but HTTP header names are case-insensitive (Content-Type = content-type = CONTENT-TYPE). Domain names are case-insensitive. MIME type names are case-insensitive.
Implementations frequently get this wrong in both directions:
- Treating case-insensitive tokens as case-sensitive (rejecting
Content-Typewhen expectingcontent-type) - Treating case-sensitive tokens as case-insensitive (matching
GETandgetwhen they should be distinct)
How to find it: submit the same token in all-uppercase, all-lowercase, and mixed case. Compare the results.
Gotcha 3: Missing Obsolete Syntax Support
Most RFCs that supersede older RFCs include "obs-" (obsolete) sections that define syntax valid in older versions. Implementations are required to accept obsolete syntax even though they should not generate it.
For email:
- Whitespace between the local part and
@is obsolete but must be accepted - Comments
(...)in addresses are obsolete but must be accepted - Folding whitespace in header fields is obsolete but must be accepted
Implementations written only from the current RFC without reading the obs- sections will reject valid obsolete forms.
How to find it: test with the obsolete forms from the obs- sections. If they are rejected, the implementation doesn't support the full required grammar.
Gotcha 4: Off-By-One Length Limits
RFC length limits are almost always maximum inclusive: "MUST NOT exceed 64 characters" means 64 is the maximum valid value. Implementations sometimes code >= 64 (should be > 64) or > 63 (correct) vs >= 64 (also correct but inverted).
How to find it: test exactly at the limit (should succeed), and exactly one over (should fail). Specifically:
- Email local part: 64 characters should succeed; 65 should fail
- Email full address: 320 characters should succeed; 321 should fail
- Domain label: 63 characters should succeed; 64 should fail
A validator with an off-by-one error will reject 64-character local parts or accept 65-character local parts.
Gotcha 5: The "No TLD" Case
RFC 5322 does not require a TLD. An address like user@localhost is syntactically valid. RFC 5321 (SMTP transport) also allows it — mail to localhost is historically valid for local delivery.
Applications that validate for real internet use may reasonably require a TLD (for practical deliverability). But:
- The application may be used in private network environments where
localhostis a real mail destination - The application may consume email addresses from external systems that generate RFC-valid but TLD-less addresses
- The error message "invalid email" is misleading when the actual rejection reason is "no TLD"
How to find it: submit user@localhost, user@mail, user@192.168.1.1 (IP literal). Document whether each is accepted or rejected and whether the behavior matches the stated requirements.
Gotcha 6: IP Address Literals in Domain
RFC 5321 allows IP addresses as the domain part in square brackets: user@[192.168.1.1] and user@[IPv6:2001:db8::1]. RFC 5322 also permits domain literals.
Most validators reject this entirely. For applications that process email addresses from any source (including API consumers, imported data, SMTP servers), rejecting IP-literal addresses may cause failures.
How to find it: test user@[127.0.0.1] and user@[IPv6:::1]. If accepted, verify the full address is stored correctly. If rejected, determine whether the rejection is intentional and documented.
Gotcha 7: The IDN Domain Double-Encoding Bug
When an application accepts internationalized domain names, it must handle them consistently:
- Accept Unicode form:
user@münchen.de - Accept punycode form:
user@xn--mnchen-3ya.de - Store one canonical form
- Display the correct form to the user
The double-encoding bug: the application converts münchen to punycode xn--mnchen-3ya, then applies punycode encoding again on the stored value, producing xn--xn--mnchen-3ya-... — invalid punycode.
How to find it: submit an email with a known IDN domain in Unicode form. Retrieve the stored value. Decode it. Verify it matches the submitted address exactly.