Great work!

XP to next level

BugEater

RFC 5322 Deep Dive

Intermediate Manual QA 52 XP 54 min

Updated: 07/07/2026

Start Module

What RFC 5322 Actually Says

RFC 5322 (Internet Message Format) defines the format of email messages including the structure of email addresses. It is often cited but rarely read. The result is validators that implement a popular myth of what email addresses look like, rather than what the standard actually permits.

The address format you probably know: localpart@domain. What you may not know is how flexible each part can be.

The Local Part

The local part (everything before the @) can take two forms: a dot-atom or a quoted string.

Dot-atom form: A sequence of "atext" characters, separated by dots, where no dot appears at the start or end and no two dots appear consecutively.

The "atext" characters are: letters (A-Z, a-z), digits (0-9), and these symbols:

! # $ % & ' * + - / = ? ^ _ ` { | } ~

This is broader than most people expect. All of the following are valid local parts under RFC 5322:

  • user+tag (the + is valid)
  • user_name (the _ is valid)
  • user!name (the ! is valid)
  • user#tag (the # is valid)
  • very.common (dots between atext sequences are valid)
  • disposable.style.email.with+symbol (multiple dots and a +)

Quoted string form: The local part may be enclosed in double quotes, allowing a broader set of characters including spaces:

  • "user name"@example.com — valid per RFC 5322
  • "user@example"@example.com — valid (the @ inside quotes is literal)
  • "very.unusual.\"@\".unusual.com"@example.com — valid

Most email validators do not support quoted strings. This is technically a bug — they reject valid email addresses — but it is so universal in practice that major mail systems don't use quoted local parts either.

What Is NOT Valid in the Local Part

The dot rules are strict:

  • Cannot start with a dot: .user@example.com — invalid
  • Cannot end with a dot: user.@example.com — invalid
  • Cannot have two consecutive dots: user..name@example.com — invalid

The following characters are NOT valid in the unquoted local part (they require quoting):

( ) [ ] \ , ; : < > @

Spaces are also not valid without quoting.

Common Validator Bugs

Real-world validators frequently get these wrong:

Bug: Rejecting + in local part

This is the most common validator bug. The + character is explicitly valid in the dot-atom form. Gmail uses it for address tagging (user+newsletter@gmail.com). Any validator that rejects it is non-conformant and will block real Gmail users.

Bug: Rejecting consecutive subdomains in domain

user@mail.example.co.uk is valid. Some validators reject domains with more than one dot, treating only @example.com form as valid.

Bug: Rejecting quoted strings

"user name"@example.com is valid per RFC 5322. Validators that reject anything with spaces or that require the local part to match [a-zA-Z0-9._%+-]+ will reject this.

Bug: Maximum length not at the right granularity

RFC 5321 (the SMTP protocol) specifies: local part MUST NOT exceed 64 characters; the entire address MUST NOT exceed 320 characters; domain labels must not exceed 63 characters. Most validators either don't enforce these or enforce them with off-by-one errors.

Bug: Case-normalizing the local part

The RFC is explicit that the local part is technically case-sensitive (though mail systems often treat it as insensitive). A validator that lowercases the local part before storing it is making an assumption that may break User@gmail.com if the user registered as user@gmail.com.

Why Regex Cannot Validate Email

This is the canonical email regex that appears in thousands of codebases:

^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$

The problems:

  1. Rejects valid special characters (!, #, $, &, ', *, ?, ^, etc.)
  2. Rejects quoted strings entirely
  3. Allows consecutive dots in the local part (the + quantifier matches a..b)
  4. Allows leading/trailing dots in the local part
  5. The {2,} TLD requirement is wrong — TLDs can be 1 character (e.g. .q) or very long (e.g. .cancerresearch)
  6. Does not handle internationalized domain names (IDN)

The only correct way to validate an email address is:

  1. Use a proper parser that implements RFC 5322
  2. Or verify deliverability by sending a confirmation email

Regex is useful for a quick sanity check (does this string contain an @?) but cannot be the sole validation mechanism for conformance.

The CFWS Problem

RFC 5322 defines CFWS (Comment and Folding White Space) — a mechanism that allows comments and folding whitespace in various positions in an email address. This means the following is technically valid per RFC 5322:

user (this is a comment) @example.com

No real mail system generates addresses with comments. But parsers that implement the full RFC grammar must accept them. This is listed as "obs-" (obsolete) in practice but the RFC still requires acceptance.

As a tester, you don't need to generate these — but you should know they exist because a strict validator that rejects them is technically non-conformant.

Practical Test Suite for Email Validation

From everything in this module, here is the minimum test suite for any email validator:

Input Expected Reason
user@example.com valid baseline
user+tag@example.com valid + is valid atext
user_name@example.com valid _ is valid atext
user!name@example.com valid ! is valid atext
very.common@example.com valid dots are valid between atext
"user name"@example.com valid quoted string local part
.user@example.com invalid leading dot
user.@example.com invalid trailing dot
user..name@example.com invalid consecutive dots
user @example.com invalid space without quoting
user@example varies no TLD — RFC allows, practice varies
user@.example.com invalid domain starts with dot
@example.com invalid empty local part
user@ invalid empty domain
65+ char local part invalid exceeds RFC 5321 limit
320+ char full address invalid exceeds RFC 5321 limit

Challenge: Local Part Lab

The practice challenge for this module focuses specifically on the local part. You will submit email addresses and observe how the validator classifies them — valid, invalid with an error, or invalid in a way that reveals a bug (the validator rejects something RFC 5322 explicitly permits).

Use the atext character list and the dot rules to guide your exploration.

Module content