RFC 2045
Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies
Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies ๐
Okay bestie, this is RFC 2045 ๐ It's a Standards Track document from the Network Working Group, dated November 1996. The authors are N. Freed (Innosoft) and N. Borenstein (First Virtual). It obsoletes RFC 1521, RFC 1522, and RFC 1590. So the whole MIME thing starts right here, and it's giving foundational era ๐
Status of this Memo ๐ฎ
This document is an Internet standards track protocol for the Internet community, and it's asking for discussion and suggestions for improvements ๐ซถ For the standardization state and status of this protocol, check the current edition of the "Internet Official Protocol Standards" (STD 1). Distribution of this memo is unlimited โจ
Abstract ๐ฆ
Okay so, STD 11, RFC 822, is the message format that defines a whole lot of detail about US-ASCII message headers, but it leaves the message content (aka the message body) as flat US-ASCII text ๐ฅฒ This set of documents, called the Multipurpose Internet Mail Extensions (MIME), redefines the message format so it can do four big new things:
- textual message bodies in character sets other than US-ASCII,
- an extensible set of different formats for non-textual message bodies,
- multi-part message bodies, and
- textual header information in character sets other than US-ASCII.
These documents are based on earlier work documented in RFC 934, STD 11, and RFC 1049, but they extend and revise that work. Because RFC 822 said so little about message bodies, these documents are largely orthogonal to RFC 822, rather than being a revision of it ๐
This first document covers the various headers used to describe the structure of MIME messages. The second document, RFC 2046, defines the general structure of the MIME media typing system and an initial set of media types. The third document, RFC 2047, describes extensions to RFC 822 so non-US-ASCII text data can go in Internet mail header fields. The fourth document, RFC 2048, specifies various IANA registration procedures for MIME-related facilities. The fifth and final document, RFC 2049, describes MIME conformance criteria, and it also gives some illustrative examples of MIME message formats, acknowledgements, and the bibliography ๐
These documents are revisions of RFCs 1521, 1522, and 1590, which were themselves revisions of RFCs 1341 and 1342. An appendix in RFC 2049 describes the differences and changes from previous versions ๐
Table of Contents ๐๏ธ
1. Introduction ......................................... 3
2. Definitions, Conventions, and Generic BNF Grammar .... 5
2.1 CRLF ................................................ 5
2.2 Character Set ....................................... 6
2.3 Message ............................................. 6
2.4 Entity .............................................. 6
2.5 Body Part ........................................... 7
2.6 Body ................................................ 7
2.7 7bit Data ........................................... 7
2.8 8bit Data ........................................... 7
2.9 Binary Data ......................................... 7
2.10 Lines .............................................. 7
3. MIME Header Fields ................................... 8
4. MIME-Version Header Field ............................ 8
5. Content-Type Header Field ............................ 10
5.1 Syntax of the Content-Type Header Field ............. 12
5.2 Content-Type Defaults ............................... 14
6. Content-Transfer-Encoding Header Field ............... 14
6.1 Content-Transfer-Encoding Syntax .................... 14
6.2 Content-Transfer-Encodings Semantics ................ 15
6.3 New Content-Transfer-Encodings ...................... 16
6.4 Interpretation and Use .............................. 16
6.5 Translating Encodings ............................... 18
6.6 Canonical Encoding Model ............................ 19
6.7 Quoted-Printable Content-Transfer-Encoding .......... 19
6.8 Base64 Content-Transfer-Encoding .................... 24
7. Content-ID Header Field .............................. 26
8. Content-Description Header Field ..................... 27
9. Additional MIME Header Fields ........................ 27
10. Summary ............................................. 27
11. Security Considerations ............................. 27
12. Authors' Addresses .................................. 28
A. Collected Grammar .................................... 29
1. Introduction ๐
Ever since it came out in 1982, RFC 822 has been the standard format for textual mail messages on the Internet ๐ It's been so successful that the RFC 822 format got adopted, fully or partly, way beyond the Internet and the Internet SMTP transport defined by RFC 821. As it got used more and more, a bunch of limitations became increasingly restrictive for the user community ๐ฅบ
RFC 822 was meant to specify a format for text messages, so non-text messages (like multimedia messages with audio or images) just aren't mentioned at all. Even for text, RFC 822 isn't enough for mail users whose languages need character sets richer than US-ASCII. Since RFC 822 doesn't specify mechanisms for mail containing audio, video, Asian language text, or even text in most European languages, more specifications are needed โจ
One of the notable limitations of RFC 821/822 based mail systems is that they cap the contents of electronic mail messages to relatively short lines (e.g. 1000 characters or less [RFC-821]) of 7bit US-ASCII. This forces users to convert any non-textual data they want to send into seven-bit bytes that can be represented as printable US-ASCII characters before invoking a local mail UA (User Agent, the program human users use to send and receive mail). Examples of such encodings currently used on the Internet include pure hexadecimal, uuencode, the 3-in-4 base 64 scheme specified in RFC 1421, the Andrew Toolkit Representation [ATK], and many others ๐ซ
The limitations of RFC 822 mail become even more obvious when gateways are designed to exchange mail messages between RFC 822 hosts and X.400 hosts. X.400 [X400] specifies mechanisms for including non-textual material within electronic mail messages. The current standards for mapping X.400 messages to RFC 822 messages say either that X.400 non-textual material must be converted to (not encoded in) IA5Text format, or that it must be discarded, with the RFC 822 user notified that discarding has happened. This is clearly undesirable, because information a user may want to receive gets lost ๐ญ Even when a user agent can't handle the non-textual material, the user might have some mechanism outside the UA that can pull useful information out of it. Plus, it doesn't account for the fact that the message may eventually be gatewayed back into an X.400 message handling system (meaning the X.400 message is "tunneled" through Internet mail), where the non-textual information would totally become useful again ๐ง
This document describes several mechanisms that work together to solve most of these problems without introducing any serious incompatibilities with the existing world of RFC 822 mail. Specifically, it describes:
- A MIME-Version header field, which uses a version number to declare a message to be conformant with MIME. It lets mail processing agents tell these messages apart from those generated by older or non-conformant software, which are presumed to lack such a field.
- A Content-Type header field, generalized from RFC 1049, which can be used to specify the media type and subtype of the data in the body of a message, and to fully specify the native representation (canonical form) of that data.
- A Content-Transfer-Encoding header field, which can be used to specify both the encoding transformation that was applied to the body and the domain of the result. Encoding transformations other than the identity transformation are usually applied to data so it can pass through mail transport mechanisms that might have data or character set limitations.
- Two additional header fields that can further describe the data in a body: the Content-ID and Content-Description header fields.
All of the header fields defined in this document are subject to the general syntactic rules for header fields specified in RFC 822. In particular, all of these header fields except for Content-Disposition can include RFC 822 comments, which have no semantic content and should be ignored during MIME processing ๐
Finally, to specify and promote interoperability, RFC 2049 provides a basic applicability statement for a subset of the above mechanisms, defining a minimal level of "conformance" with this document ๐ธ
HISTORICAL NOTE: Several of the mechanisms described in this set of documents may seem somewhat strange or even baroque at first. It's important to know that compatibility with existing standards AND robustness across existing practice were two of the highest priorities of the working group that developed these documents. In particular, compatibility was always favored over elegance ๐
Again, check the current edition of the "Internet Official Protocol Standards" for the standardization state and status of this protocol. RFC 822 and STD 3, RFC 1123 also provide essential background for MIME, since no conforming implementation of MIME can violate them. Several other informational RFC documents will also be of interest to the MIME implementor, in particular RFC 1344, RFC 1345, and RFC 1524 ๐ฆ
2. Definitions, Conventions, and Generic BNF Grammar โจ
okay bestie, this section is the glossary and house rules ๐๐ . Everything in this set is written in prose, but most of it is ALSO written in augmented BNF notation from RFC 822 ๐ง . You'll need to be comfy with that notation to follow these docs, and RFC 822 has the full explanation if you want it ๐.
Some of the augmented BNF here makes named references to syntax rules from RFC 822. So the full formal grammar is the collected grammar appendices from each document in this set, combined with the BNF of RFC 822, plus the changes RFC 1123 made to RFC 822 (it specifically changes the syntax for return', date and mailbox) ๐.
All numeric and octet values are in decimal notation here ๐ข. Media type values, subtype values, and parameter names are case-insensitive ๐. Parameter values, though, are case-sensitive unless the specific parameter says otherwise. Don't mix those up, periodt ๐ .
FORMATTING NOTE: Notes like this one are extra, nonessential info. You can skip them and you won't miss anything you need to know ๐ฆ. They're here to explain the rationale behind the design or the historical context, so if you're just building a conformant implementation you can jump right past them. But if you're curious why things are the way they are, these are the good parts ๐ง.
2.1. CRLF
"CRLF" in this set of documents means the pair of octets for the two US-ASCII characters CR (decimal value 13) and LF (decimal value 10), in that order ๐ธ. Together they mark a line break in RFC 822 mail โจ.
2.2. Character Set
In MIME, "character set" means a method of turning a sequence of octets into a sequence of characters ๐. Going the other way isn't required to be unconditional or unambiguous ๐คทโโ๏ธ. Not every character can be represented by a given character set, and a character set can give you more than one octet sequence for the same characters ๐.
The definition is broad on purpose ๐. It covers everything from simple single-table mappings like US-ASCII to complex table-switching methods like the ones using ISO 2022's techniques. Still, the definition attached to a MIME character set name has to fully specify the mapping. Using outside profiling info to figure out the exact mapping is not allowed ๐ซ.
NOTE: "Character set" originally described straightforward schemes like US-ASCII and ISO-8859-1, which map single octets to single characters one-to-one ๐. Multi-octet coded character sets and switching techniques made things messier ๐ญ. Some communities call what MIME calls a "character set" a "character encoding," and they use "coded character set" for an abstract mapping from integers (not octets) to characters ๐ซถ.
2.3. Message
When it isn't further qualified, "message" means either a complete (or "top-level") RFC 822 message being sent over a network, or a message wrapped inside a body of type "message/rfc822" or "message/partial" ๐ฌ๐.
2.4. Entity
"Entity" refers specifically to the MIME-defined header fields and contents of either a message or one of the parts in the body of a multipart entity ๐. Defining entities is basically the whole point of MIME ๐. Since an entity's contents are often called the "body," it makes sense to talk about the body of an entity ๐ธ.
Any kind of field can show up in an entity's header ๐. Only the fields whose names start with "content-" have any MIME-related meaning, though. That doesn't mean the others mean nothing at all, though! An entity that's also a message has non-MIME header fields, and their meanings are defined by RFC 822 ๐ฎโจ.
2.5. Body Part
"Body part" means an entity inside of a multipart entity ๐งฉ.
2.6. Body
When it isn't further qualified, "body" means the body of an entity, which is either the body of a message or the body of a body part ๐.
NOTE: The previous four definitions are clearly circular ๐ญ. That's unavoidable, because the overall structure of a MIME message really is recursive ๐.
2.7. 7bit Data
"7bit data" is data that's all represented as relatively short lines, with 998 octets or fewer between CRLF line separators [RFC-821] ๐. No octets with decimal values above 127 are allowed, and NULs (octets with decimal value 0) aren't allowed either ๐ซ. CR (decimal value 13) and LF (decimal value 10) octets only show up as part of CRLF line separators ๐ .
2.8. 8bit Data
"8bit data" is also data that's all represented as relatively short lines, with 998 octets or fewer between CRLF line separators [RFC-821] ๐. The difference is that octets with decimal values above 127 are allowed here ๐. Just like with "7bit data," CR and LF octets only appear as part of CRLF line separators, and NULs still aren't allowed ๐ซถ.
2.9. Binary Data
"Binary data" means data where any sequence of octets at all is allowed ๐.
2.10. Lines
"Lines" are sequences of octets separated by CRLF sequences ๐. This matches both RFC 821 and RFC 822 โจ. "Lines" only describes a unit of data in a message, and it may or may not match something a user agent actually displays ๐.
3. MIME Header Fields ๐
MIME defines a bunch of new RFC 822 header fields to describe the content of a MIME entity ๐. These header fields show up in at least two places:
- As part of a regular RFC 822 message header.
- In a MIME body part header inside a multipart construct.
Here's the formal definition of these header fields ๐ง :
entity-headers := [ content CRLF ]
[ encoding CRLF ]
[ id CRLF ]
[ description CRLF ]
*( MIME-extension-field CRLF )
MIME-message-headers := entity-headers
fields
version CRLF
; The ordering of the header
; fields implied by this BNF
; definition should be ignored.
MIME-part-headers := entity-headers
[ fields ]
; Any field not beginning with
; "content-" can have no defined
; meaning and may be ignored.
; The ordering of the header
; fields implied by this BNF
; definition should be ignored.
The syntax for each specific MIME header field gets its own section after this ๐.
4. MIME-Version Header Field ๐ธ
Since RFC 822 came out in 1982, there's really only been one format standard for Internet messages ๐ฎ. Nobody felt much need to declare which format standard they were using ๐. This document is an independent spec that complements RFC 822 โจ. The extensions here are built to be compatible with RFC 822, but there are still situations where a mail-processing agent would want to know whether a message was written with the new standard in mind ๐ง.
So this document defines a new header field, "MIME-Version," which declares the version of the Internet message body format standard in use ๐.
Messages composed under this document MUST include that header field, with exactly this text ๐ :
MIME-Version: 1.0
Having this header field is a promise that the message was composed in compliance with this document ๐ซถ.
A future document might extend the message format standard again, so there's a formal BNF for the MIME-Version content ๐ฎ:
version := "MIME-Version" ":" 1*DIGIT "." 1*DIGIT
That means any future format specifiers, which might replace or extend "1.0," have to be two integer fields separated by a period ๐ข. If a message comes in with a MIME-version value other than "1.0," you can't assume it conforms to this document ๐ซ.
Quick reminder: the MIME-Version header field is required at the top level of a message ๐ฌ. It isn't required for each body part of a multipart entity ๐งฉ. For the embedded headers of a body of type "message/rfc822" or "message/partial," it's only required if the embedded message is itself claimed to be MIME-conformant ๐.
It isn't possible to fully specify how a mail reader that conforms with MIME as defined here should handle a message that shows up in the future with some MIME-Version value other than "1.0" ๐ญ.
Also, version control for specific media types doesn't happen through the MIME-Version mechanism ๐ โโ๏ธ. Some formats, like application/postscript, have version numbering conventions built into the media format itself ๐. Where those conventions exist, MIME doesn't replace them ๐. Where they don't exist, a MIME media type can use a "version" parameter in the content-type field if it needs one โจ.
NOTE TO IMPLEMENTORS: When you check MIME-Version values, you must ignore any RFC 822 comment strings that are present ๐. Specifically, these four MIME-Version fields are equivalent ๐:
MIME-Version: 1.0
MIME-Version: 1.0 (produced by MetaSend Vx.x)
MIME-Version: (produced by MetaSend Vx.x) 1.0
MIME-Version: 1.(produced by MetaSend Vx.x)0
If there's no MIME-Version field, a receiving mail user agent (whether it conforms to MIME or not) may choose to interpret the message body using local conventions ๐ง. Lots of those conventions are in use, and honestly, in practice non-MIME messages can contain just about anything ๐.
It's impossible to be certain that a non-MIME mail message is actually plain text in the US-ASCII character set ๐ญ. It might be a message that uses nonstandard local conventions predating MIME, with text in another character set, or with non-textual data that can't be automatically recognized (like a uuencoded compressed UNIX tar file) ๐.
5. Content-Type Header Field โจ
okay bestie, the whole point of Content-Type is to describe the body well enough that the receiving user agent can pick the right app or mechanism to show it, or otherwise handle it properly ๐ The value of this field is called a media type ๐
HISTORICAL NOTE: Content-Type was first defined in RFC 1049 ๐ฐ๏ธ RFC 1049 used a simpler and less powerful syntax, but it's largely compatible with the mechanism we're looking at here ๐ธ
Content-Type says what kind of data is in the body of an entity, using media type and subtype identifiers, plus any extra info certain media types might need ๐ฆ After the media type and subtype names, the rest of the header is just a set of parameters written as attribute=value. The order of parameters does not matter ๐
In general, the top-level media type tells you the broad category of data, and the subtype names a specific format within that category ๐ง So image/xyz is enough for a user agent to know it's an image, even if it has never heard of the format "xyz" ๐ธ This matters because it decides whether it's reasonable to show a user the raw data from an unknown subtype. Showing raw data for an unknown subtype of text might be fine, but for an unknown subtype of image or audio, not so much ๐ญ For this reason, registered subtypes of text, image, audio, and video should not contain embedded information that's really a different type. Compound formats should be represented with the "multipart" or "application" types instead ๐ซถ
Parameters are modifiers of the media subtype, so they don't fundamentally change what the content is ๐ Which parameters make sense depends on the media type and subtype. Most parameters belong to one specific subtype, but a given top-level media type can define parameters that work for any subtype of that type โจ Parameters can be required by their content type or subtype, or they can be optional. MIME implementations must ignore any parameters whose names they don't recognize ๐
For example, "charset" works with any subtype of "text", and "boundary" is required for any subtype of "multipart" ๐
There are NO globally-meaningful parameters that apply to every media type ๐ โโ๏ธ If you need something truly global, the MIME way is to define extra Content-* header fields for it ๐
The initial set of seven top-level media types is defined in RFC 2046 ๐ Five of them are discrete types, where the content is basically opaque as far as MIME processing is concerned. The other two are composite types, which need extra handling by MIME processors ๐ฅ
This set of top-level media types is meant to be pretty much complete ๐ New types in the larger set should usually come from creating new subtypes of these initial types. Going forward, more top-level types may only be defined through a standards-track extension to this standard ๐ If anyone needs to use another top-level type for some reason, it must be given a name starting with "X-" to show it's non-standard and to avoid a clash with a future official name ๐
5.1. Syntax of the Content-Type Header Field
In the Augmented BNF notation of RFC 822, a Content-Type header field value is defined like this ๐
content := "Content-Type" ":" type "/" subtype
*(";" parameter)
; Matching of media type and subtype
; is ALWAYS case-insensitive.
type := discrete-type / composite-type
discrete-type := "text" / "image" / "audio" / "video" /
"application" / extension-token
composite-type := "message" / "multipart" / extension-token
extension-token := ietf-token / x-token
ietf-token := <An extension token defined by a
standards-track RFC and registered
with IANA.>
x-token := <The two characters "X-" or "x-" followed, with
no intervening white space, by any token>
subtype := extension-token / iana-token
iana-token := <A publicly-defined extension token. Tokens
of this form must be registered with IANA
as specified in RFC 2048.>
parameter := attribute "=" value
attribute := token
; Matching of attributes
; is ALWAYS case-insensitive.
value := token / quoted-string
token := 1*<any (US-ASCII) CHAR except SPACE, CTLs,
or tspecials>
tspecials := "(" / ")" / "<" / ">" / "@" /
"," / ";" / ":" / "\" / <">
"/" / "[" / "]" / "?" / "="
; Must be in quoted-string,
; to use within parameter values
Quick note: tspecials is the same as the RFC 822 "specials" list, with the three extras "/", "?", and "=" added and the "." taken out ๐ธ
Also, a subtype specification is MANDATORY, so you can never leave it out of a Content-Type header field ๐ โโ๏ธ That means there are no default subtypes, period ๐
Type, subtype, and parameter names are not case sensitive. So TEXT, Text, and TeXt are all the same top-level media type ๐ฆ Parameter values are usually case sensitive, but sometimes they're read case-insensitively depending on what they're for ๐ค (For example, multipart boundaries are case-sensitive, but the "access-type" parameter for message/External-body is not ๐)
The value of a quoted string parameter doesn't include the quotes ๐ The quotation marks are just there to mark where the value starts and ends, and they're not part of the value itself. Comments are also allowed, following the RFC 822 rules for structured header fields ๐ So these two forms are completely equivalent ๐ฏโโ๏ธ
Content-type: text/plain; charset=us-ascii (Plain text)
Content-type: text/plain; charset="us-ascii"
Beyond this syntax, the only real rule for subtype names is that their uses must not conflict ๐ญ Nobody wants two different communities using "Content-Type: application/foobar" to mean two different things! The process for defining new media subtypes isn't meant to restrict anyone. It's just a way to publicize their definition and how they're used ๐ฃ So there are two acceptable ways to define new media subtypes:
- Private values (starting with "X-") may be defined bilaterally between two cooperating agents without outside registration or standardization. Such values cannot be registered or standardized. ๐
- New standard values should be registered with IANA as described in RFC 2048. ๐
The second document in this set, RFC 2046, defines the initial set of media types for MIME ๐
5.2. Content-Type Defaults
Default RFC 822 messages without a MIME Content-Type header are treated by this protocol as plain text in the US-ASCII character set ๐ผ You can spell that out explicitly like this:
Content-type: text/plain; charset=us-ascii
This default is assumed whenever no Content-Type header field is specified ๐ซถ It's also recommended that this default be assumed when a syntactically invalid Content-Type header field shows up ๐งฏ If there's a MIME-Version header field but no Content-Type header field at all, a receiving User Agent can also assume the sender meant plain US-ASCII text โจ Plain US-ASCII text can still be assumed when there's no MIME-Version or when the Content-Type header field is syntactically invalid, but the sender's intent might have been something else ๐คทโโ๏ธ
6. Content-Transfer-Encoding Header Field ๐ฆ
Lots of media types that would be super useful over email are, in their "natural" format, 8bit character or binary data ๐ฉ That kind of data can't be sent over some transfer protocols. For example, RFC 821 (SMTP) limits mail messages to 7bit US-ASCII data, with lines no longer than 1000 characters including any trailing CRLF line separator ๐
So we need a standard way to encode that data into a 7bit short-line format ๐ง It's also good to properly label unencoded material in less restrictive formats, for direct use over less restrictive transports ๐ This document specifies that such encodings are indicated by a new "Content-Transfer-Encoding" header field ๐ This field hasn't been defined by any previous standard, so it's brand new ๐
6.1. Content-Transfer-Encoding Syntax
The Content-Transfer-Encoding field's value is a single token naming the type of encoding, from the list below. Formally, it looks like this ๐ง
encoding := "Content-Transfer-Encoding" ":" mechanism
mechanism := "7bit" / "8bit" / "binary" /
"quoted-printable" / "base64" /
ietf-token / x-token
These values are not case sensitive, so Base64, BASE64, and bAsE64 are all equivalent ๐ An encoding type of 7BIT requires that the body is already in a 7bit mail-ready representation ๐ฌ It's also the default: "Content-Transfer-Encoding: 7BIT" is assumed if the Content-Transfer-Encoding header field isn't there at all ๐
6.2. Content-Transfer-Encodings Semantics ๐
okay so this one single Content-Transfer-Encoding token is doing TWO jobs at once ๐ซถ first, it tells you what kind of encoding transformation the body went through, which tells you what decoding step you need to get the original back. second, it tells you what the domain of the result is โจ
the transformation part of any Content-Transfer-Encoding gives you, either out loud or by implication, one single, well-defined decoding algorithm. for any sequence of encoded octets, that algorithm either turns it back into the original octets or says "nope, this isn't a legal encoded sequence" ๐ Content-Transfer-Encodings transformations never depend on any extra external profile info to work properly. and ngl this is important: decoders MUST NOT have any wiggle room here, they must produce a single, well-defined output for a valid encoding. encoders though? totally free. encoding the same octets into different but equivalent encoded sequences is perfectly legal ๐ฆ
three transformations are defined so far: identity, the "quoted-printable" encoding, and the "base64" encoding. the domains are "binary", "8bit" and "7bit" ๐
the Content-Transfer-Encoding values "7bit", "8bit", and "binary" all mean the identity (i.e. NO) encoding transformation was performed. so they're basically just labels ๐ท๏ธ telling you what domain the body data lives in, and they give you handy info about what sort of encoding might be needed to send it over a given transport system. the terms "7bit data", "8bit data", and "binary data" are all defined in Section 2.
the quoted-printable and base64 encodings take their input from an arbitrary domain and turn it into material in the "7bit" range. so it's safe to carry over restricted transports ๐ก๏ธ the specific definitions of those transformations come below.
the proper Content-Transfer-Encoding label must ALWAYS be used. labelling unencoded data that contains 8bit characters as "7bit" is not allowed, and neither is labelling unencoded non-line-oriented data as anything other than "binary". absolutely not ๐ โโ๏ธ
unlike media subtypes, a proliferation of Content-Transfer-Encoding values is both undesirable AND unnecessary. BUT, a single transformation into the "7bit" domain just doesn't seem possible ๐ญ there's a tradeoff between wanting a compact, efficient encoding for mostly-binary data and wanting a somewhat readable encoding for data that's mostly (but not entirely) 7bit. so at least two encoding mechanisms are needed: a more or less readable one (quoted-printable) and a "dense" or "uniform" one (base64) ๐
mail transport for unencoded 8bit data is defined in RFC 1652. as of the initial publication of this document, there are no standardized Internet mail transports where it's legit to include unencoded binary data in mail bodies. so there are literally no circumstances where the "binary" Content-Transfer-Encoding is actually valid in Internet mail ๐ BUT, if binary mail transport ever becomes a reality on the Internet, or when MIME is used with any other binary-capable mail transport mechanism, binary bodies must be labelled as such using this mechanism. the future is binary, bestie ๐ฎ
NOTE: The five values defined for the Content-Transfer-Encoding field imply nothing about the media type other than the algorithm by which it was encoded or the transport system requirements if unencoded. ๐ง
6.3. New Content-Transfer-Encodings ๐
implementors can define private Content-Transfer-Encoding values if they really need to, but they MUST use an x-token, which is a name prefixed by "X-", to show that it's non-standard. for example: Content-Transfer-Encoding: x-my-new-encoding ๐ง additional standardized Content-Transfer-Encoding values MUST be specified by a standards-track RFC, and the requirements those specs need to meet are in RFC 2048. so basically, the whole content-transfer-encoding namespace EXCEPT anything beginning with "X-" is explicitly reserved to the IETF for future use ๐
unlike media types and subtypes, making new Content-Transfer-Encoding values is STRONGLY discouraged ๐ซ it seems likely to hinder interoperability, with very little potential benefit
6.4. Interpretation and Use ๐
if a Content-Transfer-Encoding header field shows up as part of a message header, it applies to the entire body of that message. if it shows up as part of an entity's headers, it only applies to the body of that entity. if an entity is of type "multipart", the Content-Transfer-Encoding is NOT permitted to have any value other than "7bit", "8bit" or "binary". and some subtypes of the "message" type have even harsher restrictions, which is a whole mood ๐ค
it's worth noting that most media types are defined in terms of octets rather than bits. so these mechanisms are for encoding arbitrary octet streams, not bit streams ๐ธ if you DO have a bit stream you want to encode with one of these, it must first be converted to an 8bit byte stream using the network standard bit order ("big-endian"). in that order, the earlier bits in a stream become the higher-order bits in an 8bit byte. and a bit stream that doesn't end on an 8bit boundary must be padded with zeroes. RFC 2046 has a mechanism for noting that padding was added, for the application/octet-stream media type, which has a "padding" parameter ๐งโโ๏ธ
the encoding mechanisms here explicitly encode ALL data in US-ASCII. so say an entity has header fields like this:
Content-Type: text/plain; charset=ISO-8859-1
Content-transfer-encoding: base64
this MUST be read as: the body is a base64 US-ASCII encoding of data that was originally in ISO-8859-1, and it'll be in that character set again after decoding ๐
certain Content-Transfer-Encoding values can only be used on certain media types. in particular, it is EXPRESSLY FORBIDDEN to use any encodings other than "7bit", "8bit", or "binary" with any composite media type, meaning one that recursively includes other Content-Type fields. right now the only composite media types are "multipart" and "message". all encodings that are wanted for bodies of type multipart or message must be done at the innermost level, by encoding the actual body that needs encoding ๐
it should also be noted that, by definition, if a composite entity has a transfer-encoding value like "7bit", but one of the enclosed entities has a less restrictive value like "8bit", then one of two things is true. either the outer "7bit" label is wrong, because 8bit data is included, or the inner "8bit" label put an unnecessarily high demand on the transport system, because the included data was actually 7bit-safe all along ๐
NOTE ON ENCODING RESTRICTIONS: Okay, the ban on using content-transfer-encodings on composite body data might feel overly strict, BUT it's there to prevent nested encodings. that's where data goes through an encoding algorithm multiple times and has to be decoded multiple times before anyone can view it ๐ nested encodings add a LOT of complexity for user agents. besides the obvious efficiency problems with multiple encodings, they can obscure the basic structure of a message. in particular, they can make it seem like several decoding operations are needed just to find out what types of bodies a message contains. banning nested encodings might make life harder for certain mail gateways, but that seems way less of a problem than what nested encodings would do to user agents ๐ซถ
any entity with an unrecognized Content-Transfer-Encoding MUST be treated as if it has a Content-Type of "application/octet-stream", no matter what the Content-Type header field actually says. no exceptions, periodt ๐
NOTE ON THE RELATIONSHIP BETWEEN CONTENT-TYPE AND CONTENT-TRANSFER-ENCODING: You might think the Content-Transfer-Encoding could be inferred from the characteristics of the media being encoded, or at least that certain encodings could be mandated for specific media types. there are a few reasons that's not the case ๐ง first, given the different types of transports used for mail, some encodings might be right for some combinations of media types and transports, but not others. (for example, on an 8bit transport, no encoding would be needed for text in certain character sets, while those same encodings are clearly required for 7bit SMTP.)
second, certain media types might need different kinds of transfer encoding under different circumstances. for example, lots of PostScript bodies might consist entirely of short lines of 7bit data, so they need no encoding at all. other PostScript bodies (especially those using Level 2 PostScript's binary encoding mechanism) may only be reasonably represented using a binary transport encoding ๐จ๏ธ
finally, since the Content-Type field is meant to be an open-ended specification mechanism, strictly tying media types to encodings would effectively couple an application protocol to one specific lower-level transport. that's NOT desirable, since the developers of a media type shouldn't have to know about every transport in use and what its limitations are ๐ฆ
6.5. Translating Encodings ๐
the quoted-printable and base64 encodings are designed so that converting between them is possible. the only tricky bit in that conversion is handling hard line breaks in quoted-printable output ๐ when converting from quoted-printable to base64, a hard line break in the quoted-printable form represents a CRLF sequence in the canonical form of the data. so it MUST be converted to a corresponding encoded CRLF in the base64 form of the data. and the other way around: a CRLF sequence in the canonical form of the data you get after base64 decoding must be converted to a quoted-printable hard line break, but ONLY when converting text data. ๐
6.6. Canonical Encoding Model ๐ธ
ok so there was some confusion in the previous versions of this RFC about when email data should be converted to canonical form and encoded. especially how that process affects the treatment of CRLFs, since newline representation varies wildly from system to system, and also the relationship between content-transfer-encodings and character sets ๐ฅด that's why a canonical model for encoding is presented in RFC 2049 โจ
6.7. Quoted-Printable Content-Transfer-Encoding ๐
okay bestie, so quoted-printable is the encoding for data that's mostly printable US-ASCII characters ๐. The whole point is that the encoded octets are unlikely to get messed with by mail transport ๐ซถ. If the data is mostly US-ASCII text, the encoded version still looks readable to humans, which is so iconic โจ. A body that's entirely US-ASCII can also be QP-encoded, just to keep the data intact if the message goes through a gateway that translates characters and/or wraps lines ๐ฆ.
Here's how each octet gets represented, using these rules ๐ :
(1) General 8bit representation ๐ธ Any octet can be written as an "=" followed by two hex digits showing its value, EXCEPT a CR or LF that's part of a CRLF line break in the canonical (standard) form of the data. The hex alphabet here is 0123456789ABCDEF, and you MUST use uppercase letters, because lowercase is not allowed ๐
โโ๏ธ. So decimal 12 (US-ASCII form feed) becomes =0C, and decimal 61 (the US-ASCII EQUAL SIGN) becomes =3D. This rule must be followed, unless one of the rules below allows a different encoding.
(2) Literal representation ๐ฆ Octets with decimal values 33 through 60 inclusive, and 62 through 126 inclusive, MAY just be written as the US-ASCII characters they match. That's EXCLAMATION POINT through LESS THAN, and GREATER THAN through TILDE.
(3) White Space ๐ง Octets 9 and 32 MAY be written as US-ASCII TAB (HT) and SPACE characters, but they MUST NOT be written that way at the end of an encoded line. Any TAB or SPACE on an encoded line MUST be followed on that same line by a printable character. An "=" at the end of an encoded line, which is the soft line break from rule #5, is allowed to come after one or more TABs or SPACEs. So if octet 9 or 32 ends an encoded line, it has to be encoded using Rule #1. Why? Some MTAs (Message Transport Agents, the programs that carry messages from one user to another, or handle part of that trip) are known to pad lines with SPACEs, and others strip white space off the end of lines ๐. That means when you decode a Quoted-Printable body, you must delete any trailing white space on a line, because the intermediate transport agents probably added it.
(4) Line Breaks ๐ A line break in a text body, which is a CRLF in the text canonical form, must be written as a (RFC 822) line break, which is also a CRLF, in Quoted-Printable. Non-text media types usually don't have line breaks as CRLF in their canonical form, so they can't have hard line breaks (the kind that are meant to be meaningful and shown to the user) in their QP encoding. Things like =0D, =0A, =0A=0D and =0D=0A will show up all the time in non-text data, obvi ๐.
Note that lots of implementations encode the local representation directly, without converting to canonical form first, encoding, then converting back. This can apply to plain text on systems with newline conventions other than CRLF. That shortcut is totally allowed, but only if doing the canonicalization and encoding in one step gives the same result as doing the three steps separately โจ.
(5) Soft Line Breaks ๐ท Quoted-Printable REQUIRES that encoded lines be no more than 76 characters long ๐. If a line is longer than that, you have to use "soft" line breaks. An equal sign as the last character on an encoded line marks a soft line break, which doesn't mean anything in the actual text ๐.
Here's how a single raw line that says "Now's the time for all folk to come to the aid of their country." looks in Quoted-Printable:
Now's the time =
for all folk to come=
to the aid of their country.
This is the trick for long lines that the user agent can put back together ๐. The 76 character limit doesn't count the trailing CRLF, but it counts every other character, including equal signs ๐งฎ.
Hyphens (-) can be written as themselves in Quoted-Printable ๐ญ. So if you wrap a quoted-printable body inside one or more multipart entities, you have to make sure the boundary delimiter never shows up anywhere in the encoded body. A good strategy is picking a boundary with =_ in it, since that can never appear in a quoted-printable body. Check out the definition of multipart messages in RFC 2046 for more ๐.
NOTE: Quoted-Printable is kind of a compromise between being readable and being reliable in transport ๐ค. Bodies encoded this way work reliably over most mail gateways, but might not work perfectly over a few, especially ones that translate into EBCDIC. Base64 Content-Transfer-Encoding gives you more confidence. If you want reasonably reliable transport through EBCDIC gateways, you can also quote these US-ASCII characters using rule #1:
!"#$@[\]^`{|}~
Quoted-printable data is usually treated as line-oriented, so the way line breaks between lines of QP data are represented might change in transport. That's the same thing that's always happened to plain text mail when it moves between systems with different newline conventions ๐. If those changes are likely to corrupt the data, base64 is probably the smarter pick than Quoted-Printable ๐ซถ.
NOTE: Some substrings can never be generated by the Quoted-Printable encoding rules, so they're formally illegal if they show up in a QP encoder's output. This note lists those cases and suggests how to handle them if a decoder runs into them ๐ต๏ธโโ๏ธ.
(1) An "=" followed by two hex digits, where one or both are lowercase letters from "abcdef", is formally illegal ๐ค. A robust implementation might choose to read them as the matching uppercase letters.
(2) An "=" followed by a character that's neither a hex digit (including "abcdef") nor the CR of a CRLF pair is illegal ๐ซ. This can happen when US-ASCII text gets included in a quoted-printable part without being QP-encoded first. A reasonable robust approach is to keep the "=" and the following character in the decoded data unchanged, and if possible, tell the user that proper decoding wasn't possible at that spot in the data.
(3) An "=" can't be the last or second-to-last character in an encoded object ๐ฌ. This can be handled the same way as case (2).
(4) Control characters other than TAB, and CR and LF when they're part of CRLF pairs, must not appear ๐จ. The same goes for octets with decimal values over 126. If a decoder finds them in incoming quoted-printable data, a robust implementation might leave them out of the decoded data and warn the user that illegal characters were found.
(5) Encoded lines must not be longer than 76 characters, not counting the trailing CRLF ๐. If a decoder finds longer lines in incoming encoded data, a robust implementation might still decode them, and might report the bad encoding to the user.
WARNING TO IMPLEMENTORS: If you're encoding binary data in quoted-printable, you have to be careful to encode CR and LF as=0Dand=0A, respectively ๐จ. In particular, a CRLF sequence in binary data should be encoded as=0D=0A. Otherwise, if CRLF were treated as a hard line break, it could be decoded incorrectly on platforms with different line break conventions. Yikes!
For the formalists out there ๐ค, here's the grammar for quoted-printable data:
quoted-printable := qp-line *(CRLF qp-line)
qp-line := *(qp-segment transport-padding CRLF)
qp-part transport-padding
qp-part := qp-section
; Maximum length of 76 characters
qp-segment := qp-section *(SPACE / TAB) "="
; Maximum length of 76 characters
qp-section := [*(ptext / SPACE / TAB) ptext]
ptext := hex-octet / safe-char
safe-char := <any octet with decimal value of 33 through
60 inclusive, and 62 through 126>
; Characters not listed as "mail-safe" in
; RFC 2049 are also not recommended.
hex-octet := "=" 2(DIGIT / "A" / "B" / "C" / "D" / "E" / "F")
; Octet must be used for characters > 127, =,
; SPACEs or TABs at the ends of lines, and is
; recommended for any character not listed in
; RFC 2049 as "mail-safe".
transport-padding := *LWSP-char
; Composers MUST NOT generate
; non-zero length transport
; padding, but receivers MUST
; be able to handle padding
; added by message transports.
IMPORTANT: Adding LWSP between the elements in this BNF is NOT allowed ๐ โโ๏ธ, because this BNF doesn't describe a structured header field. Don't do it, bestie ๐.
6.8. Base64 Content-Transfer-Encoding โจ
okay so base64 is the encoding for when your data is basically a random pile of octets and nobody needs to read it ๐ซถ The algorithm is simple, but the encoded data ends up only about 33 percent bigger than the original, which is lowkey a fair deal. It's basically the same encoding used in Privacy Enhanced Mail (PEM) applications, as defined in RFC 1421. Iconic callback ๐
It uses a 65-character subset of US-ASCII so each printable character carries 6 bits ๐ฆ That extra 65th character, "=", is the special one that signals a processing function (it's the padding character, more on that in a sec).
NOTE: this subset is the real main character ๐ It's represented identically in all versions of ISO 646, including US-ASCII, and every character in it is also represented identically in all versions of EBCDIC. Other popular encodings, like the one used by the uuencode utility, Macintosh binhex 4.0 [RFC-1741], and the base85 encoding specified as part of Level 2 PostScript, don't have these properties. So they don't meet the portability requirements a binary transport encoding for mail has to meet. Not me being picky, just facts ๐
The encoder works in 24-bit groups. Going left to right, you glue 3 8-bit input groups together to make one 24-bit group. Then you split those 24 bits into 4 six-bit groups, and each one gets translated into a single digit of the base64 alphabet ๐ง When you're encoding a bit stream with base64, the stream is presumed to be ordered most-significant-bit first. So the first bit is the high-order bit of the first 8-bit byte, the eighth bit is the low-order bit of that same byte, and so on. Order matters, bestie ๐
Each 6-bit group works as an index into an array of 64 printable characters, and the character at that index goes into the output string. The alphabet in Table 1 was picked so it's universally representable, and it leaves out characters with special meaning to SMTP (like ".", CR, and LF) and to the multipart boundary delimiters defined in RFC 2046 (like "-") ๐
Table 1: The Base64 Alphabet
Value Encoding Value Encoding Value Encoding Value Encoding
0 A 17 R 34 i 51 z
1 B 18 S 35 j 52 0
2 C 19 T 36 k 53 1
3 D 20 U 37 l 54 2
4 E 21 V 38 m 55 3
5 F 22 W 39 n 56 4
6 G 23 X 40 o 57 5
7 H 24 Y 41 p 58 6
8 I 25 Z 42 q 59 7
9 J 26 a 43 r 60 8
10 K 27 b 44 s 61 9
11 L 28 c 45 t 62 +
12 M 29 d 46 u 63 /
13 N 30 e 47 v
14 O 31 f 48 w (pad) =
15 P 32 g 49 x
16 Q 33 h 50 y
The encoded output has to be in lines of no more than 76 characters each. Decoding software must ignore all line breaks and any characters that aren't in Table 1 ๐ In base64 data, characters other than those in Table 1, line breaks, and other white space probably mean a transmission error. A warning or even a message rejection might be appropriate under some circumstances, so keep an eye out ๐
Now the end of the data gets special handling if there are fewer than 24 bits left. A full encoding quantum is always completed at the end of a body. When an input group has fewer than 24 bits, zero bits get added on the right until you have an integral number of 6-bit groups. Padding at the end is done with the "=" character. All base64 input is an integral number of octets, so only these three cases can happen:
- the final quantum of encoding input is an integral multiple of 24 bits. Here, the final unit of encoded output is an integral multiple of 4 characters with no "=" padding.
- the final quantum of encoding input is exactly 8 bits. Here, the final unit of encoded output is two characters followed by two "=" padding characters.
- the final quantum of encoding input is exactly 16 bits. Here, the final unit of encoded output is three characters followed by one "=" padding character.
Since "=" is only used for padding at the end of the data, seeing any "=" characters is evidence that the end of the data was reached without truncation in transit. That's a nice little safety net ๐ซถ BUT no such assurance is possible when the number of octets transmitted was a multiple of three and no "=" characters are present. So don't get too cocky about it ๐ญ
Any characters outside the base64 alphabet are to be ignored in base64-encoded data.
Care has to be taken with line breaks if base64 is applied directly to text that hasn't been converted to canonical form โจ In particular, text line breaks must be converted into CRLF sequences before base64 encoding. The thing to note is that some implementations let the encoder do this directly, instead of in a prior canonicalization step.
NOTE: there's no need to worry about quoting potential boundary delimiters inside base64-encoded bodies within multipart entities, because no hyphen characters are used in the base64 encoding. Periodt ๐
7. Content-ID Header Field ๐
okay so when you're building a high-level user agent, it's often useful for one body to reference another one ๐ฆ That's why bodies can be labelled with the "Content-ID" header field, which is syntactically identical to the "Message-ID" header field:
id := "Content-ID" ":" msg-id
Just like Message-ID values, Content-ID values must be generated to be world-unique ๐
The Content-ID value can uniquely identify MIME entities in several contexts, especially for caching data referenced by the message/external-body mechanism. The Content-ID header is generally optional, but its use is MANDATORY in implementations that generate data of the optional MIME media type "message/external-body". So every message/external-body entity has to have a Content-ID field so its data can be cached ๐ฅ
Also, the Content-ID value has special semantics for the multipart/alternative media type. That's explained in the section of RFC 2046 that deals with multipart/alternative. Go check it out, it's giving plot twist ๐
8. Content-Description Header Field ๐ธ
Sometimes you really want to attach some descriptive info to a body. For example, you might mark an "image" body as "a picture of the Space Shuttle Endeavor." That text goes in the Content-Description header field, and this header field is always optional ๐ง
description := "Content-Description" ":" *text
The description is presumed to be given in the US-ASCII character set. The mechanism specified in RFC 2047 can be used for non-US-ASCII Content-Description values, so you're not stuck with plain ASCII if you need more ๐
9. Additional MIME Header Fields ๐
Future documents may choose to define additional MIME header fields for various purposes ๐ฎ Any new header field that further describes the content of a message should begin with the string "Content-". That way, these fields are easy to tell apart from ordinary RFC 822 message header fields. Iykyk ๐
MIME-extension-field := <Any RFC 822 header field which
begins with the string
"Content-">
10. Summary โญ
Using the MIME-Version, Content-Type, and Content-Transfer-Encoding header fields, you can include arbitrary types of data in RFC 822 conformant mail messages in a standardized way ๐ No restrictions imposed by either RFC 821 or RFC 822 are violated. Care was also taken to avoid problems caused by the extra restrictions that some Internet mail transport mechanisms impose (see RFC 2049). Honestly so thoughtful ๐ฅน
The next document in this set, RFC 2046, specifies the initial set of media types that can be labelled and transported using these headers ๐
11. Security Considerations ๐จ
Security issues are discussed in the second document in this set, RFC 2046. Go read that one before you ship anything, bestie ๐
12. Authors' Addresses ๐ฎ
For more information, the authors of this document are best contacted via Internet mail ๐
Ned Freed
Innosoft International, Inc.
1050 East Garvey Avenue South
West Covina, CA 91790
USA
Phone: +1 818 919 3600
Fax: +1 818 919 3614
EMail: ned@innosoft.com
Nathaniel S. Borenstein
First Virtual Holdings
25 Washington Avenue
Morristown, NJ 07960
USA
Phone: +1 201 540 8967
Fax: +1 201 993 3032
EMail: nsb@nsb.fv.com
MIME is a result of the work of the Internet Engineering Task Force Working Group on RFC 822 Extensions. The chairman of that group, Greg Vaudreuil, can be reached at:
Gregory M. Vaudreuil
Octel Network Services
17080 Dallas Parkway
Dallas, TX 75248-1905
USA
EMail: Greg.Vaudreuil@Octel.Com
Appendix A -- Collected Grammar ๐๐
okay so this appendix is the whole grammar in one place ๐งโจ every BNF rule this document defines, all lined up for you bestie ๐
the grammar isn't totally self-contained though, ngl ๐ it borrows a bunch of names from RFC 822 instead of copying them, so nothing gets out of sync between the two docs. whenever a term isn't defined here, go look it up in RFC 822 ๐
attribute := token
; Matching of attributes
; is ALWAYS case-insensitive.
composite-type := "message" / "multipart" / extension-token
content := "Content-Type" ":" type "/" subtype
*(";" parameter)
; Matching of media type and subtype
; is ALWAYS case-insensitive.
description := "Content-Description" ":" *text
discrete-type := "text" / "image" / "audio" / "video" /
"application" / extension-token
encoding := "Content-Transfer-Encoding" ":" mechanism
entity-headers := [ content CRLF ]
[ encoding CRLF ]
[ id CRLF ]
[ description CRLF ]
*( MIME-extension-field CRLF )
extension-token := ietf-token / x-token
hex-octet := "=" 2(DIGIT / "A" / "B" / "C" / "D" / "E" / "F")
; Octet must be used for characters > 127, =,
; SPACEs or TABs at the ends of lines, and is
; recommended for any character not listed in
; RFC 2049 as "mail-safe".
iana-token := <A publicly-defined extension token. Tokens
of this form must be registered with IANA
as specified in RFC 2048.>
ietf-token := <An extension token defined by a
standards-track RFC and registered
with IANA.>
id := "Content-ID" ":" msg-id
mechanism := "7bit" / "8bit" / "binary" /
"quoted-printable" / "base64" /
ietf-token / x-token
MIME-extension-field := <Any RFC 822 header field which
begins with the string
"Content-">
MIME-message-headers := entity-headers
fields
version CRLF
; The ordering of the header
; fields implied by this BNF
; definition should be ignored.
MIME-part-headers := entity-headers
[fields]
; Any field not beginning with
; "content-" can have no defined
; meaning and may be ignored.
; The ordering of the header
; fields implied by this BNF
; definition should be ignored.
parameter := attribute "=" value
ptext := hex-octet / safe-char
qp-line := *(qp-segment transport-padding CRLF)
qp-part transport-padding
qp-part := qp-section
; Maximum length of 76 characters
qp-section := [*(ptext / SPACE / TAB) ptext]
qp-segment := qp-section *(SPACE / TAB) "="
; Maximum length of 76 characters
quoted-printable := qp-line *(CRLF qp-line)
safe-char := <any octet with decimal value of 33 through
60 inclusive, and 62 through 126>
; Characters not listed as "mail-safe" in
; RFC 2049 are also not recommended.
subtype := extension-token / iana-token
token := 1*<any (US-ASCII) CHAR except SPACE, CTLs,
or tspecials>
transport-padding := *LWSP-char
; Composers MUST NOT generate
; non-zero length transport
; padding, but receivers MUST
; be able to handle padding
; added by message transports.
tspecials := "(" / ")" / "<" / ">" / "@" /
"," / ";" / ":" / "\" / <">
"/" / "[" / "]" / "?" / "="
; Must be in quoted-string,
; to use within parameter values
type := discrete-type / composite-type
value := token / quoted-string
version := "MIME-Version" ":" 1*DIGIT "." 1*DIGIT
x-token := <The two characters "X-" or "x-" followed, with
no intervening white space, by any token>
That's the whole collection, bestie ๐ซถ๐ every rule, all in one spot. Now go forth and parse like the legend you are ๐๐
๐ฆ where this page comes from
- ietf: rfc2045 1996-11
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms