m
Building compliant mail software is fundamentally impossible because obsolete RFC standards conflict with widespread real-world client bugs, forcing parsers to tolerate malformed inputs to survive.
AI-assisted summary of Email Hates the Living — original source. Check the original for full context.
Source published:
Key ideas
- Email protocol specifications and real-world client implementations systematically diverge, making completely bug-free and standards-compliant email handling software impossible to implement. (0:04)
- Spammers routinely bypass email filters not by breaking standards, but by constructing strictly valid messages using obscure RFC edge cases such as comments in date fields and silent discarding of non-Base64 bytes. (2:23)
- Header folding rules (dating back to RFC 724) permanently destroy consecutive whitespace sequences during line unwrapping and create major truncation hazards in poorly implemented intermediate mail handlers. (4:20)
- Syntax-only email address validation is fundamentally ineffective; robust validation requires pragmatic multi-tiered checks, including live DNS MX record lookups and contextual abuse screening. (45:57)
Detailed notes
## Background This presentation was delivered by Ricardo Signes (rjbs) on June 16, 2008, and uploaded to YouTube by channel m on May 6, 2012. According to the page description, the talk covers the eldritch horrors, devilish ambiguities, and historical cruft buried within internet email protocols, offering a humorous and cautionary exploration of why writing email-handling software is inherently doomed.
## TL;DR Ricardo Signes breaks down the architectural insanity of internet email, arguing that flawed standards and non-compliant real-world implementations make it fundamentally impossible to write completely correct email-processing software. Tracing the evolution of email from RFC 724 and RFC 822 through MIME and modern standards, he demonstrates how arcane features—such as header folding, comment-folding whitespace (CFWS), parameter value continuations, and ambiguous Base64 handling—create immense parsing traps and security risks. He details the bizarre complexities of the `addr-spec` grammar, including quoted local-parts and address groups, while highlighting how spammers exploit specification edge cases to bypass naive filters. Ultimately, Signes urges developers to rely on battle-tested libraries, embrace practical pragmatism over strict RFC perfection, and avoid writing bespoke email code whenever possible.
## Atmosphere & style The presentation carries the frantic, darkly comedic energy of a seasoned engineer who has stared directly into an eldritch technical abyss and survived to tell the tale. Signes combines sharp Lovecraftian hyperbole and self-deprecating wit with deep technical expertise, delivering punchlines about broken specifications to an engaged, laughing audience of fellow programmers. The tone oscillates between exasperated horror and hard-earned pragmatic cynicism, creating an entertaining atmosphere of shared developer catharsis.
## Bulletin - [00:04](https://www.youtube.com/watch?v=4s9IjkMAmns&t=4s) Email protocol specifications and real-world client implementations systematically diverge, making completely bug-free and standards-compliant email handling software impossible to implement. - [02:23](https://www.youtube.com/watch?v=4s9IjkMAmns&t=143s) Spammers routinely bypass email filters not by breaking standards, but by constructing strictly valid messages using obscure RFC edge cases such as comments in date fields and silent discarding of non-Base64 bytes. - [04:20](https://www.youtube.com/watch?v=4s9IjkMAmns&t=260s) Header folding rules (dating back to RFC 724) permanently destroy consecutive whitespace sequences during line unwrapping and create major truncation hazards in poorly implemented intermediate mail handlers. - [45:57](https://www.youtube.com/watch?v=4s9IjkMAmns&t=2757s) Syntax-only email address validation is fundamentally ineffective; robust validation requires pragmatic multi-tiered checks, including live DNS MX record lookups and contextual abuse screening.
## Key takeaways - [00:04](https://www.youtube.com/watch?v=4s9IjkMAmns&t=4s) Writing completely standard-compliant email software is doomed to fail because real-world internet traffic routinely violates the specifications, forcing parsers to accept non-compliant input. - [02:23](https://www.youtube.com/watch?v=4s9IjkMAmns&t=143s) The Perl email module ecosystem reflects the deceptive complexity of the format: lightweight modules only function under strict constraints, while robust solutions like Mail::Message require massive codebases. - [04:20](https://www.youtube.com/watch?v=4s9IjkMAmns&t=260s) Header folding was introduced in RFC 724 to address display limits on hardware terminals, introducing lexical equivalence that allows arbitrary line breaks and indentation across message headers. - [06:25](https://www.youtube.com/watch?v=4s9IjkMAmns&t=385s) RFC 2822's Comment or Folding White Space (CFWS) permits recursively nested parenthetical comments between tokens, all of which semantically collapse into a single space. - [08:45](https://www.youtube.com/watch?v=4s9IjkMAmns&t=525s) Date headers permit obsolete military single-letter time zones and interspersed nested comments between date tokens, which modern parsers must still support for backwards compatibility. - [10:52](https://www.youtube.com/watch?v=4s9IjkMAmns&t=652s) The BNF grammars of RFC 2822 codify that obsolete constructs must be actively parsed and accepted rather than rejected, compounding maintenance overhead. - [12:22](https://www.youtube.com/watch?v=4s9IjkMAmns&t=742s) Standard SMTP enforces a strict 1,000-character line length limit and lacks native 8-bit transport, necessitating the development of the MIME suite (RFCs 2045–2049). - [13:59](https://www.youtube.com/watch?v=4s9IjkMAmns&t=839s) Base64 specifications mandate that non-Base64 characters must be silently ignored, creating an exploit vector where spammers inject garbage bytes to evade naive string filters. - [16:36](https://www.youtube.com/watch?v=4s9IjkMAmns&t=996s) In Quoted-Printable streams, escaping carriage return and line feed bytes as '=0D=0A' forces conforming clients to treat them as literal data bytes rather than visual line breaks. - [19:01](https://www.youtube.com/watch?v=4s9IjkMAmns&t=1141s) RFC 2047 encoded-words allow message headers to mix multiple distinct character sets and encodings within a single header line using the '=?charset?encoding?text?=' syntax. - [24:39](https://www.youtube.com/watch?v=4s9IjkMAmns&t=1479s) RFC 2184 (RFC 2231) introduced asterisk-based parameter continuation syntax ('param*0*='), creating a separate encoding system distinct from standard MIME encoded-words. - [28:28](https://www.youtube.com/watch?v=4s9IjkMAmns&t=1708s) Multipart message preambles appear before the first boundary and are completely unrendered by MIME-capable clients, allowing hidden notes or legacy fallback messages. - [33:43](https://www.youtube.com/watch?v=4s9IjkMAmns&t=2023s) The local-part of an email address must preserve case and permits quoted strings with backslash escaping, which malicious actors can exploit to inject CRLF control characters into headers. - [39:39](https://www.youtube.com/watch?v=4s9IjkMAmns&t=2379s) The empty address group construct ('undisclosed-recipients:;') is the only syntactically valid method to send an RFC-compliant email without exposing recipient addresses. - [43:46](https://www.youtube.com/watch?v=4s9IjkMAmns&t=2626s) Folding and unfolding headers collapses arbitrary whitespace into a single space, permanently stripping repeated whitespace unless it was explicitly octet-encoded. - [45:57](https://www.youtube.com/watch?v=4s9IjkMAmns&t=2757s) Email address validation cannot rely on grammar parsing alone; practical implementations must balance DNS MX lookups, internal blocklists, and contextual strictness to avoid delivery and bounce floods. - [47:36](https://www.youtube.com/watch?v=4s9IjkMAmns&t=2856s) Attachment filenames defined in Content-Disposition headers require path traversal sanitization by the receiver to prevent malicious senders from overwriting local files.
## Detailed walkthrough ### [00:04](https://www.youtube.com/watch?v=4s9IjkMAmns&t=4s) Introduction: Email Hates You and Wants You to Suffer
Ricardo Signes introduces himself as Rick Signes, known online as `rjbs` across CPAN, IRC, mailing lists, and Flickr. He explains that he maintains an extensive collection of email modules on CPAN and works for Pobox, a company whose entire business revolves around handling email. Signes sets expectations for the talk right away: he is not there to present an uplifting educational lecture on becoming a better programmer or mastering the construction of RFC 2183 `Content-Disposition` headers. Instead, he highlights the grim reality encoded within the foundational RFCs. Showing a favorite quote from the RFC introducing modern multipart messages—*"This is strange and broke, and compatibility is always favored over elegance"*—he declares it the understatement of the century.
The core thesis of the talk is that any attempt to write email-handling software is inherently doomed. Whether an engineer writes code to ingest raw messages from the outside world or to generate new messages to transmit out, the code is almost guaranteed to be wrong. This failure is not a matter of individual incompetence; rather, the underlying standards are flawed, and real-world implementations routinely violate those standards. As a result, code written strictly to specification fails to process actual internet traffic.
Signes delivers a direct warning to the audience about dealing with email code:
> “I’m not saying probably because I know you did it wrong and I can tell you how I know: it's impossible to get it right. The standards get it wrong, the main implementations get it wrong, and that means that doing it right is going to be wrong because you can't actually receive real email. For God's sake, stop writing code that deals with email.”
```mermaid flowchart TD accTitle: The Impossibility of Correct Email Handling accDescr: Diagram illustrating why standard and real-world email implementations cause email code to fail. subgraph SpecFailures["Standards & Reality"] A["RFC Standards Defective"] --> C["Strict Conformance Breaks"] B["Real-World Clients Non-Compliant"] --> C end subgraph Outcome["Resulting Failure"] C --> D["Your Email Code Fails"] end ```
[02:23](https://www.youtube.com/watch?v=4s9IjkMAmns&t=143s) CPAN Modules and Why Spammers Love Email
Signes details his involvement with the Perl Email Project, an effort dedicated to maintaining `Email::*` modules alongside several legacy `MIME::*` and `Mail::*` distributions. Having given a presentation the previous year about the bugs across the project's codebase, he explains that no module can fully conquer the underlying insanity. He breaks down the CPAN ecosystem options:
- `Email::Simple`: Marginally acceptable only under exceptionally narrow constraints: creating a new message from scratch rather than parsing one from disk or an external source, containing an exclusively 7-bit ASCII body, with zero chance of receiving 8-bit variable input, never functioning as a reply to an existing message, and addressing recipients solely by bare email address without human-readable display names. - `Email::MIME`: Capable of generating more varieties of valid messages than `Email::Simple`, yet still prone to producing broken output that fails depending on the recipient's software. - `MIME::Entity`: Offers slightly better standards compliance, but carries a bizarre interface and significant historical baggage. - `Mail::Message`: The "10-ton elephant" of Perl mail handling. It gets the vast majority of edge cases right, but developers routinely avoid it because its sheer bulk clashes with the persistent illusion that email is a simple domain.
Signes notes that the Byzantine complexity of message parsing creates an enormous exploit surface for spammers. Because compliant parsing is so counterintuitive, a sender wishing to conceal malicious payloads does not need to send malformed data. By crafting completely standards-compliant email constructed out of obscure RFC edge cases, spammers easily bypass standard parsers and security scanners that choke on the input.
[04:20](https://www.youtube.com/watch?v=4s9IjkMAmns&t=260s) Header Folding and Lexical Equivalence (RFC 724)
Addressing the history of this complexity, Signes pushes back against the belief that the rot began in 1982 with RFC 821 and RFC 822. Early specifications like RFC 561 and RFC 680 were simple and straightforward to parse. The real madness began in 1977 with RFC 724. RFC 724 introduced "header folding" to solve a presentation problem at the data layer: long headers did not fit on narrow Wyse terminals, and authors avoided writing a presentation wrapping layer by embedding line breaks directly into the transport format. Under header folding, a field could be broken across lines using a newline followed by indentation, creating lexical equivalence with an unfolded single line.
```mermaid flowchart LR accTitle: Header Folding Lexical Equivalence accDescr: RFC 724 allows unfolding a header across multiple indented lines while preserving equivalence. A["Subject: This is a really long subject line"] -->|"Lexically Equivalent (RFC 724)"| B["Subject: This is a\n really long\n subject line"] ```
RFC 724 permits line breaks and whitespace to be inserted wherever a terminal requires wrapping. While this allows wrapping long headers, it also permits splitting headers across an arbitrary number of single-word lines. In real-world systems, encountering such bizarre formatting is common. Half the time it reflects a completely non-compliant client, and the other half it is strictly legal under ancient specifications. Because parsers cannot reliably distinguish between intentional standards exploitation and accidental bugs, receiving systems are forced to accept virtually everything.
[06:25](https://www.youtube.com/watch?v=4s9IjkMAmns&t=385s) CFWS: Folding White Space and Nested Comments
Signes examines how the specifications define valid locations for linear whitespace. RFC 724 states that whitespace may be freely inserted in "reasonable places," dryly noting that "the existence of another lexical analyzer is assumed." In practical terms, this rule means whitespace may be inserted anywhere two tokens meet. Furthermore, any arbitrary whitespace is treated as equivalent to a comment, and comments are allowed to nest inside parentheses. When a comment acts as a delimiter between tokens, the specification dictates that the entire comment structure collapses into the semantic equivalent of a single space.
Signes illustrates this by showing how an ordinary header can be progressively obfuscated with whitespace and nested commentary while remaining strictly identical in meaning:
> “If you ever want to see an email programmer cry and see his eyes glaze over with rage and desperation, just ask him about comment or folding whitespace.”
RFC 2822 later codified this concept as CFWS (Comment or Folding White Space). While RFC 2822 attempted to rein in the damage, its remedies were minimal. It outlawed lines composed entirely of whitespace—a syntax permitted under RFC 822 and RFC 724—but left the rest of the parsing nightmare intact.
- An RFC comment is wrapped in matching parentheses: `(this is a comment)`. - Comments can nest recursively: `(outer comment (nested comment))`. - For semantic understanding, any comment acting as a token separator is evaluated as a single space character. - RFC 2822 strictly prohibits empty lines consisting solely of whitespace characters, eliminating one historical edge case from RFC 822.
[08:45](https://www.youtube.com/watch?v=4s9IjkMAmns&t=525s) Date Headers, Military Time Zones, and RFC 2822 Obsoletion
Signes shifts focus to the ubiquitous `Date` header, which is mandatory on every email message to denote composition and transmission time. While modern protocols favor ISO 8601, email dates allow a vast array of legacy variations. Standard forms include conventional `Day, DD Mon YYYY HH:MM:SS ±ZZZZ` formats, but the specification also permits arbitrary whitespace padding and military single-letter time zone indicators. In military time zones, letters A through M (omitting J) represent time zones east of UTC, Z represents Greenwich Mean Time, and N through Y span time zones west of UTC.
Because date fields consist of discrete tokens, comments can technically be interspersed throughout the date components. Signes demonstrates an extreme date header filled with nested comments between the day, month, year, and time tokens. He jokes that a particular comment might look invalid until realizing empty comments `()` are strictly forbidden by the grammar.
RFC 2822 attempted to restrict comments to the end of the date field. However, robust mail systems cannot enforce RFC 2822 rules in isolation. Because modern software must remain backwards-compatible with incoming RFC 822 mail, parsers must continue to support deeply nested, interspersed comments embedded inside timestamp components. What appears to be a tidy grammar in newer RFC documents is undermined by the requirement to support legacy pseudo-grammars that tolerate complete madness.
- Every email is formally required to include a `Date` header. - Military time zones (such as `Z` for Zulu/GMT, or single-character zone offsets like `D`) remain valid within legacy date parsing rules. - Comments cannot be completely empty; `()` without content violates the specification. - RFC 2822 relegates mid-token date comments to obsolete syntax sections, but parsers must still retain the legacy logic to function on the live internet.
[10:52](https://www.youtube.com/watch?v=4s9IjkMAmns&t=652s) BNF Grammars, Obsolete Syntax, and the Structure of Email
RFC specifications gradually adopted Backus–Naur Form (BNF) to define email message structures, establishing formal rules for components such as dates, days, months, and years. In a straightforward world, a date would consist of a day (one or two digits), a month (one of the English three-letter abbreviations), and a four-digit year. However, standards like RFC 2822 complicate this by declaring that a day can be either standard digits or an "obsolete day," and a month can be a normal name or an "obsolete month." An obsolete month is defined simply as a standard month name flanked by folding white space and comments. This design choice creates a maintenance nightmare because any parser following the standard cannot merely reject non-conforming data.
> "The term is anything that is obsolete must be accepted and parsed." — Ricardo Signes
The core structure of an Internet text message appears deceptive in its simplicity: a message consists solely of a block of headers, optionally followed by a blank line and the message body, all represented in plain ASCII characters. Because the body is just an unformatted stream of text, early implementers assumed the complexity of email was entirely confined to the headers. This assumption proved completely false once messages needed to cross real networks.
```mermaid flowchart TD accTitle: Email Message Anatomy accDescr: Diagram showing the basic breakdown of an RFC 822 email message into headers and an ASCII body.
subgraph Msg["RFC 822 Message Structure"] H["Header Fields\n(Complex BNF, Folding White Space)"] SEP["Blank Line (CRLF CRLF)"] B["Message Body\n(Plain 7-bit ASCII)"] H --> SEP SEP --> B end ```
- RFC date specifications define months as three-letter abbreviations: Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec. - Obsolete constructs in the grammar mandate full parsing support rather than deprecation or outright rejection. - Standard email messages enforce an absolute separation between the header section and the body text via a single empty line (`\r\n\r\n`).
---
[12:22](https://www.youtube.com/watch?v=4s9IjkMAmns&t=742s) The "Simple" Mail Transfer Protocol and the Birth of MIME
RFC 821 superseded early experimental mechanisms that sent mail across networks, including Unix-to-Unix Copy (UUCP) and File Transfer Protocol (FTP) extensions. Dubbed the Simple Mail Transfer Protocol (SMTP), its name stands as a historical contradiction. Under standard RFC 821 SMTP, lines are hard-capped at a maximum length of 1,000 characters (including the trailing carriage return and line feed). Unlike headers, message bodies offer no mechanism for folding excessively long lines, and the protocol provides no built-in way to transmit 8-bit characters. The only native protocol-level solution to non-ASCII text was an implicit demand that international users avoid using 8-bit characters entirely.
To solve the limitations of transmitting rich media and international alphabets over 7-bit transport, Multipurpose Internet Mail Extensions (MIME) was developed. Early precursors to MIME attempted to establish encapsulation rules; RFC 934 defined message forwarding using explicit finite-state automata, while RFC 1049 supported specialized body types like `troff`. RFC 1341 formally defined MIME, but its initial iteration attempted to introduce an SGML-compatible markup language for rich text in Section 7. The modern MIME architecture was ultimately standardized across a cohesive suite of documents: RFC 2045 through RFC 2049.
> "821 calls this the simple mail transfer protocol and like all the best names it is a lie." — Ricardo Signes
- RFC 821 line length restriction: 1,000 characters maximum, inclusive of the terminating `<CRLF>`. - RFC 934 formalized encapsulation behavior by specifying explicit finite-state automata for forwarding agents. - RFC 1049 defined early content-type mechanisms, famously supporting types such as `troff`. - RFC 1341 was superseded by the core MIME suite spanning RFCs 2045, 2046, 2047, 2048, and 2049.
---
[13:59](https://www.youtube.com/watch?v=4s9IjkMAmns&t=839s) Base64 Encoding, Character Sets, and Lenient Parsing Flaws
Sending an 8-bit message over a 7-bit SMTP channel requires declaring an encoding format in the message headers. Using `Content-Transfer-Encoding: base64` transforms arbitrary 8-bit byte sequences into a 6-bit printable ASCII representation. However, turning text into bytes introduces fundamental character encoding problems. If a sender types text in UTF-8, the system emits specific byte sequences; if a receiving client lacks character set metadata and guesses ISO-8859-1 (Latin-1) or Mac OS Roman, it produces completely garbled strings rather than readable text. Resolving this requires an explicit `Content-Type: text/plain; charset="utf-8"` header.
Base64 implementations contain a serious parser loophole: the specification mandates that any character encountered in a Base64 stream that is not a valid Base64 digit must be silently ignored. This permissive handling predated RFC 2119's standardized keyword requirements (`MUST`, `SHOULD`, `MAY`), leaving the handling of malformed input ambiguous across mail clients. While some implementations attempt to reject malformed input, standard-compliant implementations strip invalid characters, allowing hidden data to slip past basic filters. Spammers exploit this behavior to bypass naive content inspection filters (such as `procmail` recipes checking for strings like "Viagra") by splitting keywords with arbitrary non-Base64 bytes that mail user agents silently discard during decoding.
> "When you write email code that parses the body by splitting up the lines of the body you have failed, and everyone does this." — Ricardo Signes
```mermaid flowchart LR accTitle: Base64 and Charset Decoding Pipeline accDescr: Pipeline displaying how input text converts to bytes, Base64 transport, and displays differently based on client charset detection.
subgraph Encoding["Sender Side"] T["Text Input\n(e.g., UTF-8)"] --> BY["Raw Byte Stream"] BY --> B64["Base64 Encoding\n(7-bit ASCII Safe)"] end
subgraph Transport["SMTP Transport"] B64 --> NET["Network Transfer\n(Max 1000 chars/line)"] end
subgraph Decoding["Receiver Side"] NET --> D64["Base64 Decoding\n(Discards Non-Digits)"] D64 --> C{"Declared Charset?"} C -->|"utf-8"| OK["Readable Original Text"] C -->|"iso-8859-1"| MOJ["Mojibake Output"] C -->|"macintosh"| MAC["Corrupted Mac Glyphs"] end ```
- Base64 maps 8-bit binary input into a safe 64-character 7-bit ASCII alphabet (`A–Z`, `a–z`, `0–9`, `+`, `/`). - Omitting `charset` declarations forces mail clients to guess the encoding, yielding mojibake across platforms. - Non-Base64 characters must be silently ignored according to early specifications, breaking simple line-by-line body parsers.
---
[16:36](https://www.youtube.com/watch?v=4s9IjkMAmns&t=996s) Quoted-Printable Traps and Literal Newline Semantics
As an alternative to Base64, MIME offers `Content-Transfer-Encoding: quoted-printable`, designed to keep primarily ASCII text human-readable. Only characters outside the standard ASCII range—or characters that have syntactic significance—must be escaped as an equals sign followed by a two-digit hexadecimal byte value (such as `=E9`). Some overzealous encoders aggressively escape standard characters, including spaces (`=20`), creating noisy but valid text.
A severe semantic trap exists regarding line breaks in quoted-printable streams. In standard quoted-printable text, an actual line break is indicated by a literal hard carriage-return/line-feed (`CRLF`). If an encoder instead represents a newline by escaping the individual bytes as hex strings (`=0D=0A`), the specification dictates that these are literal CR and LF control characters rather than visual line endings. Mail user agents like Mutt strictly adhere to this rule: instead of rendering a line break on screen, they render raw, unparsed `^M` carriage return symbols or literal character blocks, corrupting the message layout.
> "If I put a literal CRLF there it means that I want a new line when you display the message, but if I encode the CRLF it means that I want the CR byte and the LF byte." — Ricardo Signes
| Feature | Base64 | Quoted-Printable | |:--- |:--- |:--- | | **Primary Use Case** | Binary attachments or non-Latin text | Primarily 7-bit ASCII with sparse 8-bit bytes | | **Human Readability** | Completely illegible raw text | Mostly readable ASCII text with hex escapes | | **Line Break Meaning** | Hard newlines ignored; formatting purely data | Literal `<CRLF>` creates newlines; `=0D=0A` yields literal control bytes | | **Overhead** | Flat ~33% size increase | Low for ASCII; up to 200% increase for non-ASCII text |
- Quoted-printable encodes bytes using hexadecimal pairs preceded by `=`. - Escaping carriage return and line feed bytes as `=0D=0A` changes their semantic meaning from structural line breaks to raw byte data. - User agents such as Mutt intentionally render encoded `=0D=0A` sequences as literal control characters (`^M`) to conform to spec semantics.
---
[19:01](https://www.youtube.com/watch?v=4s9IjkMAmns&t=1141s) RFC 2047 Encoded-Words and Multi-Charset Header Chaos
While `Content-Transfer-Encoding` solves encoding issues within the message body, it does not apply to RFC 822/2822 message headers. Headers are strictly restricted to 7-bit ASCII, meaning non-ASCII characters in display names within the `From:` or `To:` fields (such as "Vlad" spelled with Cyrillic or accented characters) cause immediate transport and parsing failures. Because `Content-Transfer-Encoding` cannot be applied to headers, the IETF created RFC 2047 to define "encoded-words."
An encoded-word is a specialized token that represents non-ASCII data within headers using the syntax `=?charset?encoding?encoded_text?=`. The encoding token is a single character: `Q` represents a header-specific variant of quoted-printable (where spaces can be represented by underscores), while `B` represents standard Base64. Because the specification permits individual adjacent encoded-words to declare entirely different character sets and encoding formats within the same header field, a single human name can legally be composed of a UTF-8 Q-encoded first name, an unencoded 7-bit ASCII middle token, and an EBCDIC B-encoded surname concatenated together.
> "Encoded-word is a new token introduced by RFC 2047 and it's just like a word, but it's encoded: that means it starts with equals question mark, it ends with question mark equals, and there's two question marks in the middle." — Ricardo Signes
- Encoded-word format: `=?<charset>?<encoding>?<data>?=`. - In RFC 2047, `Q` denotes the header variant of Quoted-Printable, and `B` denotes Base64. - RFC 2047 allows multiple adjacent tokens with different character sets (e.g., UTF-8, ISO-8859-1, EBCDIC) to construct a single logical display string.
[21:32](https://www.youtube.com/watch?v=4s9IjkMAmns&t=1292s) MIME Encoded Words, Underscore Escaping, and Structured Comments
Ricardo Signes explains that even when dealing with entirely 7-bit ASCII strings—such as a sender's display name—senders or spammers might choose to encode them anyway just for safety or obfuscation. However, standard quoted-printable encoding cannot simply be dropped into an encoded-word token (`=?charset?encoding?encoded-text?=`) without modification. Because spaces cannot be permitted inside encoded words (a parser would not know where the token terminates), an underscore (`_`) is substituted for spaces. As Signes dryly points out, this creates an absurd dialect discrepancy: “in normal quoted printable underscore is underscore in this quoted printable underscore is space great let's put it under the rug and keep going.”
```mermaid flowchart TD accTitle: Quoted-Printable Encoding vs MIME Encoded-Word Q Encoding accDescr: Comparison of character handling between standard quoted-printable bodies and RFC 2047 header tokens.
subgraph StandardQP["Standard Quoted-Printable (RFC 2045 Body)"] A1["Underscore '_'"] --> B1["Represents literal '_'"] A2["Space ' '"] --> B2["Represents literal ' ' or '=20'"] end
subgraph HeaderQ["MIME Header 'Q' Encoding (RFC 2047)"] C1["Underscore '_'"] --> D1["Represents literal Space ' '"] C2["Space ' '"] --> D2["Illegal: breaks token boundary"] end ```
The resulting headers can quickly degenerate into an unreadable tangle containing multiple character sets within a single string. Signes notes that prior to Unicode, reliably decoding a single header with two or more character sets was essentially impossible. Furthermore, email standards permit comments inside structured header fields. These comments can appear between almost any two components and are dropped by parsers, yet they are strictly structured whitespace: - Comments can nest arbitrarily deep inside matching parentheses. - Comments can themselves contain encoded words. - All of this must be parsed properly without breaking header boundaries.
[22:55](https://www.youtube.com/watch?v=4s9IjkMAmns&t=1375s) File Attachments, Missing RFCs, and the Parameter Hack
Moving on to message bodies, Signes looks at a reply to a "Weekly Newsletter" containing an attachment. Attachments do not arrive naturally as files; they must be structured as discrete email payloads using headers, Base64 encoding, and MIME semantics. Signes walks through the historical mess of attaching a binary document (like a Microsoft Word `.doc` file):
When RFC 2046 was drafted, it indicated that to provide an attachment filename, implementations should use a header called `Content-Disposition`, but the specification noted that `Content-Disposition` would only be formally defined in a future RFC. RFC 2046 also strictly warned that the field could not contain encoded words. Because that defining specification did not emerge for nine months, developers improvised by stuffing arbitrary parameters (like `title`) into `Content-Type`. This introduced a new conundrum: if a document title contains 8-bit non-ASCII characters, how does one encode it? - `Content-Transfer-Encoding` does not apply because parameters sit in the header, not the body. - RFC 2047 encoded-word syntax (`=?charset?Q?...?=`) was explicitly forbidden in MIME parameter values.
As Signes summarizes the dilemma: “so right encoded words um we can't use those in parameters so we can't use that equals question mark question mark question mark question mark equals thing so yeah there's no solution to this problem um you you just got to suck it up.”
[24:39](https://www.youtube.com/watch?v=4s9IjkMAmns&t=1479s) RFC 2184/2231 Parameter Value Continuations and Header Folding
Nine months later, RFC 2184 (later RFC 2231) arrived to specify how parameter values should encode non-ASCII text and handle folding. Rather than reusing existing mechanisms, it invented completely new syntax: 1. An asterisk (`*`) is appended to the parameter name (e.g., `title*=`) to indicate the value is encoded. 2. The value begins with the character set, a single quote, the language tag (e.g., `utf-8'en'`), another single quote, followed by percent-encoded octets. 3. Quoted-printable was rejected because equal signs look too much like standard parameter assignments (`foo=bar`), and Base64 was rejected for poor human readability.
```mermaid flowchart LR accTitle: Parameter Value Splitting and Encoding via RFC 2184 accDescr: Sequence showing how long parameter lines are split into indexed parts with selective encoding flags.
P0["title*0*=utf-8'en'First%20Part%20"] --> P1["title*1*=Second%20Part%20"] P1 --> P2["title*2*=Third%20Part%20"] P2 --> P3["title*3=FinalPartASCII"]
subgraph Assembly["Parsed Full Parameter"] Result["Full Title: 'First Part Second Part Third Part FinalPartASCII'"] end
P0 -.-> Result P1 -.-> Result P2 -.-> Result P3 -.-> Result ```
This collided head-on with header line folding. While RFC 822 introduced folding (inserting CRLF followed by whitespace) to keep lines under 78 or 80 characters for human readability, mail clients evolved to demand it unconditionally: “it's gotten point at this at this time that uh if you don't fold your header stuff breaks so now you must fold.” But because parameters cannot have arbitrary whitespace injected into the middle of continuous tokens, RFC 2184 introduced parameter segmenting: - Parameter names append a number and an optional asterisk: `title*0*=...`, `title*1*=...`, `title*2*=...`, and `title*3=...`. - If an individual segment contains pure 7-bit ASCII, the asterisk is omitted (as in `title*3=`), while encoded segments keep the asterisk. - The language and charset are established once in part zero and must remain consistent across subsequent parts.
[26:54](https://www.youtube.com/watch?v=4s9IjkMAmns&t=1614s) Content-Disposition, Advisory Metadata, and RFC Grammar Bugs
When `Content-Disposition` was finally specified, it allowed senders to declare `attachment`, provide a filename (using the asterisk-encoded parameter format), and theoretically treat mail messages like a remote filesystem. Senders could attach filesystem metadata: - Parameter `size`: strictly advisory and approximate, meaning parsers must never rely on it as an exact byte count. - Parameter `modification-date`: storing file timestamps. - Legal comments scattered directly between the parameter declarations.
Signes highlights a widespread trap regarding trailing semicolons in parameter lists. Under the grammar, parameters are defined strictly as delimited pairs: `value; param=val; param=val` with no trailing semicolon allowed at the end of the header. Yet implementations consistently violate this rule. Signes points out why this cannot be enforced strictly: “if you wonder why I making a point of this because it's not that crazy it's because half the time the RFC that defines this mentions it it gets it wrong in the examples the RFCs get it wrong everyone gets this wrong so you can't reject email because it's wrong which means when you parse email you have to get it right it's just it's a fact of life.”
[28:28](https://www.youtube.com/watch?v=4s9IjkMAmns&t=1708s) Multipart Architecture, Boundaries, and the Preamble
To actually assemble the multipart message containing both text and attachments, the original top-level message body is scooped out and placed inside a nested MIME entity. The container message is declared with `Content-Type: multipart/...` and specifies an arbitrary text `boundary` string to delineate each subpart.
```mermaid flowchart TD accTitle: Multipart Email Structure and Preamble accDescr: Structural layout of a multipart MIME email highlighting the unrendered preamble and bounded parts.
TopHeaders["Top-level Headers: Content-Type: multipart/mixed; boundary=..."] Preamble["Preamble: Unrendered ASCII text outside boundaries"] B1["--boundary"] Part1["Part 1: Text message (text/plain)"] B2["--boundary"] Part2["Part 2: Word Attachment (application/msword; Content-Disposition)"] B3["--boundary--"] Epilogue["Epilogue: Trailing ignored text"]
TopHeaders --> Preamble Preamble --> B1 B1 --> Part1 Part1 --> B2 B2 --> Part2 Part2 --> B3 B3 --> Epilogue ```
Signes breaks down the structural rules of multipart messages: - Between the boundary delimiters lie complete, standalone MIME entities, each with their own headers and payload. - Any text appearing before the very first boundary delimiter is the **preamble**, and text after the final delimiter (`--boundary--`) is the **epilogue**. - Because the top-level `Content-Type` is multipart, `Content-Transfer-Encoding` is forbidden on the outer message; the preamble is therefore strictly 7-bit US-ASCII and invisible to modern MIME-compliant clients. - Senders frequently use the preamble to leave warning text for legacy clients. Signes recounts his favorite spam encounter using this feature: an HTML part selling pills, a plain text part selling pills, and a preamble that read simply, “get a capable email client.”
Finally, Signes notes that language tags made their way back to encoded words in RFC 2231/RFC 5646 formats as well, allowing headers to declare things like `utf-8*en`, before wrapping up the composition phase: “okay so we've composed a message it's got from it's got to it's got an attachment it's got a body it's great this is the best message we've ever had now we're going to send it.”
[31:41](https://www.youtube.com/watch?v=4s9IjkMAmns&t=1901s) The Grammar of `addr-spec` and Domain Literals
Ricardo Signes turns to his favorite topic: email addresses. He recounts an email he received from someone testing the Perl module `Email::Valid`, complaining that it marked an absurd address as valid and asking how that could possibly be true. To demonstrate why, Signes walks through the formal grammar governing `addr-spec`, the specification defining an email address.
```mermaid flowchart TD accTitle: Email Address Grammar Decomposition accDescr: Diagram showing how addr-spec breaks down into local-part, @, and domain rules.
subgraph AS["addr-spec"] LP["local-part"] AT["@"] DOM["domain"] end
subgraph DOM_RULES["domain Parsing"] SUB["subdomain"] DOT_SUB["(. subdomain)*"] ATOM["atom (non-specials, non-control)"] end
LP --> AT --> DOM DOM --> SUB --> ATOM DOM --> DOT_SUB --> ATOM ```
He simplifies the specification on the slide by stripping out the `domain-literal` syntax (used for routing directly by IP, like `rjbs@[1.2.3.4]`, bypassing MX lookups) and removing unused definitions like `dtext`. Looking strictly at `domain`, the grammar defines it as a `subdomain` followed by zero or more sequences of a dot and another `subdomain`. Each `subdomain` is a `domain-ref`, which is an `atom`: one or more characters excluding spaces, control characters, and defined specials. Because the rules for domain literals permit quotes and spaces, technically bizarre constructs remain entirely syntactically valid according to the specifications.
[33:43](https://www.youtube.com/watch?v=4s9IjkMAmns&t=2023s) The Local-Part: Preserving Case and the Threat of Injection
Signes explains that weird domain syntaxes are largely a theoretical problem ("shooting fish in a barrel") because the specification left room for future protocols beyond DNS, whereas in practice, software simply resolves hostnames via DNS. Instead, the true nightmare lies on the left side of the `@` sign: the `local-part`.
Signes reflects on how the specifications treat these boundaries: “The real hate in email messages is the local part and the local part is everything to the left side of the at sign.” A `local-part` is composed of words separated by dots, and crucially, it must be case-preserved. Violating this rule is one of the most common bugs in web applications. Signes admits to his own early blunder writing email software that assumed all incoming addresses were lowercase, causing him to drop legitimate incoming mail sent to uppercase variants like `RJBS`.
```mermaid flowchart LR accTitle: Anatomy of local-part Syntax accDescr: Flowchart illustrating the components of a local-part including words, atoms, and quoted strings.
LP["local-part"] --> W["word (. word)*"] W --> ATOM["atom"] W --> QS["quoted-string"] QS --> ESC["backslash escaping (\)"] QS --> SP["embedded spaces"] ```
Because a word can be either an `atom` or a `quoted-string` (where backslashes escape characters and double quotes enclose spaces), the grammar permits extreme local parts: - Standard identifiers like `rjbs` - Subaddressing variants like `rjbs+tag` - Unquoted or quoted unconventional punctuation, such as `first.last` or `!#$%&'*+-/=?^_{|}~` - Embedded spaces and escaped characters inside quotes
The danger escalates when quoted strings contain literal control characters: - Signes highlights an address containing embedded carriage returns and line feeds: `"Ricardo\r\nTo: rjbs"@example.com`. - Parsers that fail to respect quoting rules will split the header prematurely, interpreting the carriage return as the end of the header and the remainder as a whole new header (`To: rjbs`). - Signes points out the operational risk: “That is two message heads no matter what your software wants to tell you, it's just another vector for abuse.”
[36:50](https://www.youtube.com/watch?v=4s9IjkMAmns&t=2210s) Phrases, Address Groups, and the "How Many Addresses" Quiz
Moving beyond the bare `addr-spec`, Signes discusses the `phrase`, which is the display name placed before an address enclosed in angle brackets (e.g., `Ricardo Signes <rjbs@cpan.org>`), and mentions that comments in parentheses can appear alongside them. He then introduces a lesser-known specification feature: the address group. An address group consists of a group name, a colon, a comma-separated list of addresses, and a terminating semicolon (such as `Technical Staff (R&D): rjbs@example.com, user@example.com;`).
Signes challenges the audience to spot how many valid email addresses appear on an example slide:
```text Team: rjbs.@cpan.org, http://example.com, "Van Helsing"@vampires.com, (Invisible Man), Alito@justice.gov.; ```
When an audience member guesses two, Signes walks through the slide token by token to show why almost every address fails: - `rjbs.@cpan.org` is invalid because dots cannot be the trailing (or leading) character of a local-part. - `http://example.com` fails because colons are illegal unquoted characters in local-parts. - `"Van Helsing"@vampires.com` fails in this specific slide because an explicit eight-bit character is present without proper encoding. - `(Invisible Man)` is merely a comment inside parentheses, not an address at all. - Commas without addresses between them are legally skipped, functioning similarly to empty list separators in Perl. - `Alito@justice.gov.` is invalid because the fully qualified domain name includes a trailing root dot; while valid in DNS lookups, a trailing dot is forbidden in the email grammar. - Consequently, only one actual address on the entire slide satisfies the RFC criteria.
[39:39](https://www.youtube.com/watch?v=4s9IjkMAmns&t=2379s) Nested Groups, RFC Discrepancies, and Undisclosed Recipients
The complexity deepens when evaluating nested address groups across conflicting specifications. RFC 733 / RFC 822 treated nested groups unclearly, whereas RFC 2822 made nesting explicitly illegal. Signes highlights the real-world headache of standard revisions: while developers prefer to target newer RFCs like 2821 and 2822, older systems deployed across the Internet continue to operate under RFC 821 and RFC 822 rules. Parsers are forced to balance strict adherence against the messy reality of lenient implementations.
Signes reveals the single most practical takeaway of the entire presentation: - “That is the only way to produce a valid email message that does not have any recipients.” - An empty group—conventionally written as `undisclosed-recipients:;`—provides a syntactically valid `To:` header containing a name, a colon, and an immediate semicolon with zero addresses. - This allows bulk senders or BCC-only mailers to satisfy the parser requirement for a destination header without exposing private recipient addresses. - Signes quips: “If you are trying to send a message and you are doing it with something other than Mutt or Mail.app, you are losing the game already.”
[41:53](https://www.youtube.com/watch?v=4s9IjkMAmns&t=2513s) Q&A: Header Line Folding and Length Limits
Noticing he only has about eight minutes remaining, Signes decides to postpone his planned segment on MIME until next year's conference and opens the floor for questions: “Who dares ask a question?”
An audience member named Todd explains that his workplace purchased an email list management application that began misbehaving, leading him to inspect the RFCs regarding header line folding and maximum line lengths. Todd asks whether line length restrictions apply before or after a line has been unfolded.
Signes reframes the question (“What's the deal with header line folding?”) and explains the folding mechanics: - Folding header lines (inserting a carriage return/line feed followed by whitespace) is generally optional for the sender, except when dealing with specific rigid parameter values. - Senders are encouraged to break lines around the 72- or 79-character mark. - The recommended line length limits apply to the full logical length of the line, including the header field name prefix (such as `Foo-Bar-Baz:`). - Senders have broad discretion over where whitespace breaks occur. - Signes concludes with his personal preference on folding headers: “If it were up to me and everything accepted everything, I would never fold it.”
[43:46](https://www.youtube.com/watch?v=4s9IjkMAmns&t=2626s) Header Folding, Whitespace Loss, and Truncation Bugs
Ricardo Signes explains a subtle and frustrating flaw with email header line folding. When a line is folded, an application finds a point where there is whitespace, inserts a carriage return followed by a space, and continues. However, an arbitrary amount of whitespace can be placed on either side of that carriage return, and upon processing, the whole sequence is compressed down into a single space. Consequently, if a header required multiple consecutive spaces for any reason, that information is permanently destroyed unless encoded as literal octets.
An audience member raises a related scenario: an incoming message is addressed to 500 recipients on a `To:` header line, neatly folded into short individual lines by the sender's client. However, an application their company purchased ingests the message, unfolds the header into a single massive string of 500 addresses, decides the result exceeds an internal maximum header line length, and truncates it. Signes replies that while an official length ceiling might exist in some specification, he does not know of one, and very little worthwhile software enforces arbitrary limits on header length. Addressing the practical reality of email engineering, Ricardo Signes emphasizes: “Another point to to weigh in pragmatic for a moment, the point with email, the specs are all crap, you can't trust them, you can barely deal with the specs and expect anything to work, what you really need to do is do whatever works.” He hates resorting to such hacks in professional enterprise code, but in email handling, survival demands doing whatever prevents software from destructively unfolding and truncating valid headers.
```mermaid flowchart TD accTitle: Header Folding and Unfolding Truncation Issue accDescr: Flowchart illustrating how folded email headers can be improperly truncated by receiving software. subgraph SENDER["Sender Application"] A["500 Email Addresses"] --> B["Fold across lines with CR + Space"] end subgraph RECEIVER["Faulty Receiving Application"] B --> C["Unfold all lines into single long string"] C --> D{"Exceeds internal max length?"} D -- "Yes" --> E["Truncate header & destroy recipients"] end ```
[45:57](https://www.youtube.com/watch?v=4s9IjkMAmns&t=2757s) Email Address Validation and Practical Pragmatism
An audience member asks for the appropriate snappy response to give a manager who demands adding email address validation to an application. Signes answers that the real response must simply be “Yes, sir.” He points out: “Email address validation is impossible, but that doesn't mean it's not worth attempting.” Signes maintains the Perl module `Email::Valid` (noting with self-deprecating humor that he did not author it, but merely applies patches like he does for a lot of email software), and he considers it quite good.
Signes explains that merely parsing local syntax against the formal RFC grammar is technically possible, but yields very little useful information. Pragmatic validation requires multi-tiered checks:
- Verifying whether the domain name actually exists in DNS. - Checking for valid MX records associated with that domain. - Screening against internal blocklists of known bogus addresses. - Applying contextual strictness: at Pobox, if incoming mail is simply being forwarded along, they assume it is good enough and pass it through; conversely, if an end-user attempts to register an address as a brand-new username, they enforce a far stricter set of rules.
Skipping address validation entirely causes catastrophic downstream consequences. Signes cautions that if you refuse to validate, your mail servers accept raw garbage, futile outbound delivery attempts clog up the outgoing mail exchangers (MXs), and engineers end up having to build extensive bounce parsing systems—an operational ordeal so painful that Signes calls it “a whole other sequel to this.”
[47:36](https://www.youtube.com/watch?v=4s9IjkMAmns&t=2856s) MIME Filename Encoding and Path Traversal Hazards
An audience member asks whether multi-line header folding rules also apply to file names in attachments. Signes clarifies that the most standard, canonical place to locate an attachment's name is inside the `filename` or `name` parameter of a structured `Content-Disposition` header. Because it is defined as a parameter, it relies on MIME parameter value and line continuations:
- Non-ASCII 8-bit octets must use the asterisk character encoding syntax (e.g., `filename*="utf-8''..."`). - Long parameter values split across multiple sections utilize continuation numbers with asterisks (such as `filename*0*`, `filename*1*`, `filename*2*`). - The parameter must only specify the leaf file name, not directory paths. Because email clients cannot strictly enforce this on the wire, receiving software must actively sanitize input to prevent malicious path traversal from blowing away files on the local filesystem.
As the session wraps up, Signes notes that he has run out of time, thanking the room to warm applause.
## Notable quotes > [45:57](https://www.youtube.com/watch?v=4s9IjkMAmns&t=2757s) Email address validation is impossible, but that doesn't mean it's not worth attempting. — Ricardo Signes
> [00:04](https://www.youtube.com/watch?v=4s9IjkMAmns&t=4s) The standards get it wrong, the main implementations get it wrong, and that means that doing it right is going to be wrong because you can't actually receive real email. — Ricardo Signes
> [13:59](https://www.youtube.com/watch?v=4s9IjkMAmns&t=839s) When you write email code that parses the body by splitting up the lines of the body you have failed, and everyone does this. — Ricardo Signes
> [39:39](https://www.youtube.com/watch?v=4s9IjkMAmns&t=2379s) If you are trying to send a message and you are doing it with something other than Mutt or Mail.app, you are losing the game already. — Ricardo Signes
> [33:43](https://www.youtube.com/watch?v=4s9IjkMAmns&t=2023s) The real hate in email messages is the local part and the local part is everything to the left side of the at sign. — Ricardo Signes
## Mentioned Ricardo Signes, Pobox, CPAN, Perl Email Project, Email::Simple, Email::MIME, MIME::Entity, Mail::Message, Email::Valid, RFC 561, RFC 680, RFC 724, RFC 733, RFC 821, RFC 822, RFC 934, RFC 1049, RFC 1341, RFC 2045, RFC 2046, RFC 2047, RFC 2048, RFC 2049, RFC 2119, RFC 2183, RFC 2184, RFC 2231, RFC 2821, RFC 2822, RFC 5646, Mutt, Mail.app, UUCP, FTP, SMTP, IMAP, MIME
## Video description By Ricardo SIGNES (rjbs) from ABE.pm, Philadelphia.pm Date: Monday June 16, 2008 14:50 Duration: 45 minutes Target audience: Lightning Tags: brains email hate horror lovecraft mail rant warning wtf you.are.all.going.to.die zombie
Email: you see it every day. It's on your desktop. It's in your servers. Through the magic of modern technology, it flows invisibly through the air and into your PDA! Your cellular phone conducts silent and arcane conversations with distant servers, speaking the ancient language of SMTP and the unknowable dialects of IMAP. Surely all this technology means progress of mankind... or does it?
Now you can learn the truth: buried deep within the eldrich documents describing the slow accretion of features in the Elder Protocols lie subtle recursions and devilish ambiguities -- grammars that are not grammars, strings quietly stripped of their higher bits -- designed to slowly bend the mind of all who implement them.
Now you can hear of the horrors perpetrated by those who became thrall to these documents -- and by those, too, who fought to oppose them for the sake of their own dwindling sanity.
Now it can be told: Email Hates the Living!
WARNING: This talk is low in career-sustaining educational content.
[Source](https://www.youtube.com/watch?v=4s9IjkMAmns)