RFC 1341
MIME (Multipurpose Internet Mail Extensions): Mechanisms for Specifying and Describing the Format of Internet Message Bodies
MIME (Multipurpose Internet Mail Extensions): Mechanisms for Specifying and Describing the Format of Internet Message Bodies ๐
Okay bestie, this is RFC 1341 ๐ and it's the one that finally lets email carry more than plain text. The authors are N. Borenstein (Bellcore) and N. Freed (Innosoft). It came out of the Network Working Group in June 1992 ๐ธ and it's an IAB standards track protocol โจ. The title block doesn't list anything it obsoletes or updates, so there's nothing to cross-check there ๐.
Status of this Memo ๐
This RFC specifies an IAB standards track protocol for the Internet community, and asks for discussion and suggestions for improvements ๐ . Check the current edition of the "IAB Official Protocol Standards" for the standardization state and status of this protocol ๐ฆ. Distribution of this memo is unlimited ๐.
Abstract ๐ง
So RFC 822 defines a message representation protocol that gets super detailed about headers, but it leaves the message content (the message body) as flat ASCII text ๐. This document redefines the format of message bodies so you can represent and exchange multi-part textual and non-textual bodies without loss of information ๐. It's based on earlier work in RFC 934 and RFC 1049, but it extends and revises that work โจ. RFC 822 said so little about message bodies that this document is largely orthogonal to (rather than a revision of) RFC 822 ๐ซถ.
This document is designed to give you facilities to include multiple objects in a single message, to represent body text in character sets other than US-ASCII, to represent formatted multi-font text messages, and to represent non-textual material such as images and audio fragments ๐. It also generally makes it easier to add new types of Internet mail later, for use by cooperating mail agents ๐ฅ.
Heads up: this document does not extend Internet mail header fields to permit anything other than US-ASCII text data. It's recognized that such extensions are necessary, and they're the subject of a companion document [RFC -1342] ๐.
A table of contents appears at the end of this document ๐.
1. Introduction โจ
Okay so, since it was published in 1982, RFC 822 [RFC-822] has defined the standard format of textual mail messages on the Internet ๐ . It was such a hit that the RFC 822 format has been adopted, wholly or partially, well beyond the confines of the Internet and the Internet SMTP transport defined by RFC 821 [RFC-821] ๐. But as the format has seen wider use, a bunch of limitations have become increasingly restrictive for the user community ๐ญ.
RFC 822 was only ever meant to specify a format for text messages ๐. So non-text messages, like multimedia messages that might include audio or images, aren't even mentioned ๐. Even for text, RFC 822 isn't enough for mail users whose languages need character sets richer than US ASCII [US-ASCII] ๐ธ. Since RFC 822 doesn't specify mechanisms for mail containing audio, video, Asian language text, or even text in most European languages, additional specifications are needed ๐.
One of the notable limitations of RFC 821/822 based mail systems is that they limit the contents of electronic mail messages to relatively short lines of seven-bit ASCII ๐ฆ. This forces users to convert any non-textual data they want to send into seven-bit bytes that can be represented as printable ASCII characters before invoking a local mail UA (User Agent, a program with which human users 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 1113, the Andrew Toolkit Representation [ATK], and many others โจ.
The limitations of RFC 822 mail get even more apparent as gateways are designed to allow mail messages to be exchanged between RFC 822 hosts and X.400 hosts ๐ฅ. X.400 [X400] specifies mechanisms for including non-textual body parts within electronic mail messages ๐ง. The current standards for mapping X.400 messages to RFC 822 messages say that either X.400 non-textual body parts should be converted to (not encoded in) an ASCII format, or they should be discarded while notifying the RFC 822 user that discarding has occurred ๐ฉ. That's clearly undesirable, because information a user may want to receive is lost ๐. Even if a user's UA can't handle the non-textual body part, the user might have some mechanism outside the UA that can extract useful information from it ๐ซถ. Also, 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 definitely become useful again ๐ .
This document describes several mechanisms that combine to solve most of these problems without introducing any serious incompatibilities with the existing world of RFC 822 mail โจ. In particular, it describes:
- A MIME-Version header field, which uses a version number to declare a message to be conformant with this specification. It lets mail processing agents tell such messages apart from those generated by older or non-conformant software, which is presumed to lack such a field ๐.
- A Content-Type header field, generalized from RFC 1049 [RFC-1049], which can be used to specify the type and subtype of data in the body of a message and to fully specify the native representation (encoding) of that data ๐ฆ.
- 2.a. A "text" Content-Type value, which can be used to represent textual information in a number of character sets and formatted text description languages in a standardized manner ๐.
- 2.b. A "multipart" Content-Type value, which can be used to combine several body parts, possibly of differing types of data, into a single message ๐งฉ.
- 2.c. An "application" Content-Type value, which can be used to transmit application data or binary data, and hence, among other uses, to implement an electronic mail file transfer service ๐พ.
- 2.d. A "message" Content-Type value, for encapsulating a mail message ๐.
- 2.e An "image" Content-Type value, for transmitting still image (picture) data ๐ธ.
- 2.f. An "audio" Content-Type value, for transmitting audio or voice data ๐ง.
- 2.g. A "video" Content-Type value, for transmitting video or moving image data, possibly with audio as part of the composite video data format ๐ฌ.
- A Content-Transfer-Encoding header field, which can be used to specify an auxiliary encoding that was applied to the data so it can pass through mail transport mechanisms that may have data or character set limitations ๐.
- Two optional header fields that can be used to further describe the data in a message body: the Content-ID and Content-Description header fields ๐ท๏ธ.
MIME has been carefully designed as an extensible mechanism, and it's expected that the set of content-type/subtype pairs and their associated parameters will grow significantly over time ๐ฑ. Several other MIME fields, notably including character set names, are likely to get new values defined over time too ๐. To make sure that set of values gets developed in an orderly, well-specified, and public manner, MIME defines a registration process that uses the Internet Assigned Numbers Authority (IANA) as a central registry for such values ๐. Appendix F gives details about how IANA registration is accomplished ๐๏ธ.
Finally, to specify and promote interoperability, Appendix A of this document provides a basic applicability statement for a subset of the above mechanisms, which defines a minimal level of "conformance" with this document ๐ซก.
HISTORICAL NOTE: Some of the mechanisms described in this document may seem a little 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 this document ๐ซถ. In particular, compatibility was always favored over elegance ๐.
2. Notations, Conventions, and Generic BNF Grammar ๐
This document is being published in two versions, one as plain ASCII text and one as PostScript ๐จ๏ธ. The latter is recommended, though the textual contents are identical ๐ธ. There's also an Andrew-format copy of this document available from the first author (Borenstein) ๐ฆ.
Although the mechanisms specified in this document are all described in prose, most are also described formally in the modified BNF notation of RFC 822 ๐ง . Implementors will need to be familiar with this notation to understand this specification, and they're referred to RFC 822 for a complete explanation of the modified BNF notation ๐.
Some of the modified BNF in this document refers to syntactic entities that are defined in RFC 822 and not in this document ๐. So a complete formal grammar is obtained by combining the collected grammar appendix of this document with the one from RFC 822 โจ.
The term CRLF, in this document, refers to the sequence of the two ASCII characters CR (13) and LF (10) which, taken together in this order, denote a line break in RFC 822 mail ๐.
Okay so, "character set" in this doc does NOT mean "a set of characters" lol. It means a coded character set, in the sense of ISO character set standardization work. Don't misread it, bestie ๐ซถ
The term "message", when it's not further qualified, means either the complete (or "top-level") message being sent across a network, or a message wrapped up inside a body of type "message" ๐ฌ
A "body part" is one of the parts of the body of a multipart entity ๐งฉ A body part has its own header and body, so you can totally talk about the body of a body part. Iconic ๐
An "entity" is either a message or a body part. Every kind of entity has a header and a body ๐
"Body", when it's not further qualified, means the body of an entity. So either the body of a message or the body of a body part ๐ธ
Note: the last four definitions are clearly circular ๐ This is unavoidable, since the overall structure of a MIME message is recursive, so it's giving Russian nesting doll energy ๐ช
In this document, all numeric and octet values are written in decimal notation ๐ข
It must be noted that Content-Type values, subtypes, and parameter names as defined in this document are case-insensitive โจ Parameter values, though, are case-sensitive unless the specific parameter says otherwise. Plot twist ๐
FORMATTING NOTE: This document has been carefully formatted for ease of reading. The PostScript version, in particular, puts notes like this one, which the reader can skip, in a smaller, italicized font, and indents them too. In the text version, only the indentation is kept, so if you're reading the text version you might want to grab the PostScript one instead. However, all such notes will be indented and start with "NOTE:" or some similar intro, even in the text version ๐
The point of these non-essential notes is to share the rationale behind this document, or to place it in its historical or evolutionary context ๐ฆ Feel free to skip them if you're just focused on building a compliant implementation. They're handy if you want to understand why the document is written the way it is ๐ง
For ease of recognition, all BNF definitions are placed in a fixed-width font in the PostScript version of this document ๐
3. The MIME-Version Header Field โจ
Okay so, since RFC 822 came out in 1982, there has really only been one format standard for Internet messages, and nobody really felt the need to declare which format standard was being used ๐ This document is an independent document that complements RFC 822. The extensions here were defined to be compatible with RFC 822, but there are still situations where it'd be useful for a mail-processing agent to know whether a message was composed with the new standard in mind ๐
So this document defines a new header field, "MIME-Version", which is used to declare the version of the Internet message body format standard in use ๐
Messages composed in accordance with this document MUST include this header field, with the following verbatim text:
MIME-Version: 1.0
The presence of this header field is an assertion that the message has been composed in compliance with this document ๐
Since a future document might extend the message format standard again, there's a formal BNF for the content of the MIME-Version field:
MIME-Version := text
So future format specifiers, which might replace or extend "1.0", are (minimally) constrained by the definition of "text", which appears in RFC 822 ๐ฆ
Note that the MIME-Version header field is required at the top level of a message. It is not required for each body part of a multipart entity. It is required for the embedded headers of a body of type "message" if and only if the embedded message is itself claimed to be MIME-compliant ๐
4. The Content-Type Header Field ๐
The purpose of the Content-Type field is to describe the data in the body fully enough that the receiving user agent can pick an appropriate agent or mechanism to present the data to the user, or otherwise deal with the data in an appropriate manner ๐
HISTORICAL NOTE: The Content-Type header field was first defined in RFC 1049. RFC 1049 Content-types used a simpler and less powerful syntax, but one that is largely compatible with the mechanism given here ๐
The Content-Type header field specifies the nature of the data in the body of an entity, by giving type and subtype identifiers, plus auxiliary info that might be needed for certain types โจ After the type and subtype names, the rest of the header field is just a set of parameters in attribute/value notation. The meaningful parameters differ for different types. The ordering of parameters is not significant. One of the defined parameters is a "charset" parameter, which declares the character set used in the body. Comments are allowed under RFC 822 rules for structured header fields ๐
Generally, the top-level Content-Type is used to declare the general type of data, while the subtype specifies a specific format for that type. So a Content-Type of "image/xyz" is enough to tell a user agent that the data is an image, even if the user agent has never heard of the image format "xyz" ๐ผ๏ธ That info can be used to decide whether to show a user the raw data from an unrecognized subtype. That might be reasonable for unrecognized subtypes of text, but not for unrecognized subtypes of image or audio ๐ For this reason, registered subtypes of audio, image, text, and video should not contain embedded information that's really of a different type. Compound types should be represented using the "multipart" or "application" types ๐ซถ
Parameters modify the content-subtype and don't fundamentally affect the requirements of the host system ๐ง Most parameters only make sense with certain content-types, but others are "global", meaning they might apply to any subtype. For example, the "boundary" parameter only makes sense for the "multipart" content-type, but the "charset" parameter might make sense with several content-types ๐
A starter set of seven Content-Types is defined by this document. This set of top-level names is meant to be substantially complete. Additions to the larger set of supported types can generally be made by creating new subtypes of these initial types. In the future, more top-level types may only be defined by an extension to this standard. If another primary type is ever used, it must be given a name starting with "X-" to flag its non-standard status and avoid a potential conflict with a future official name ๐ฉ
Here's the Extended BNF notation of RFC 822 for a Content-Type header field value:
Content-Type := type "/" subtype *[";" parameter]
type := "application" / "audio"
/ "image" / "message"
/ "multipart" / "text"
/ "video" / x-token
x-token := <The two characters "X-" followed, with no
intervening white space, by any token>
subtype := token
parameter := attribute "=" value
attribute := token
value := token / quoted-string
token := 1*<any CHAR except SPACE, CTLs, or tspecials>
tspecials := "(" / ")" / "<" / ">" / "@" ; Must be in
/ "," / ";" / ":" / "\" / <"> ; quoted-string,
/ "/" / "[" / "]" / "?" / "." ; to use within
/ "=" ; parameter values
Note that the definition of "tspecials" is the same as the RFC 822 definition of "specials" with the addition of the three characters "/", "?", and "=" ๐ง
Also, a subtype specification is MANDATORY. There are no default subtypes ๐จ
The type, subtype, and parameter names are not case sensitive. For example, TEXT, Text, and TeXt are all equivalent ๐ธ Parameter values are normally case sensitive, but certain parameters are interpreted as case-insensitive depending on the intended use. (For example, multipart boundaries are case-sensitive, but the "access-type" for message/External-body is not case-sensitive.) ๐
Beyond this syntax, the only constraint on subtype names is the desire that their uses must not conflict. That is, it would be undesirable to have two different communities using "Content-Type: application/foobar" to mean two different things ๐ฌ The process of defining new content-subtypes isn't meant to be a way of imposing restrictions. It's just a way of publicizing the usages. So there are two acceptable mechanisms for defining new Content-Type subtypes:
- Private values (starting with "X-") may be defined bilaterally between two cooperating agents without outside registration or standardization. The original text continues from here in the next part ๐
- New standard values must be documented, registered with, and approved by IANA, as described in Appendix F, bestie ๐ no shortcuts. And if they're meant for public use, the formats they point to must also be defined by a published specification, and possibly offered for standardization ๐ธ
There are seven standard initial predefined Content-Types ๐, and the rest of the doc goes deep on each one. Here they are:
- text: textual information ๐. The primary subtype, "plain", indicates plain (unformatted) text. No special software is required to get the full meaning of the text, aside from support for the indicated character set. Subtypes are to be used for enriched text in forms where application software may enhance the appearance of the text, but such software must not be required in order to get the general idea of the content. Possible subtypes thus include any readable word processor format. A very simple and portable subtype, richtext, is defined in this document ๐
- multipart: data made of multiple parts of independent data types ๐งฉ. Four initial subtypes are defined, including the primary "mixed" subtype, "alternative" for representing the same data in multiple formats, "parallel" for parts intended to be viewed simultaneously, and "digest" for multipart entities in which each part is of type "message" โจ
- message: an encapsulated message ๐. A body of Content-Type "message" is itself a fully formatted RFC 822 conformant message, which may contain its own different Content-Type header field. The primary subtype is "rfc822". The "partial" subtype is defined for partial messages, so bodies that are thought to be too large to pass through mail transport facilities can be sent in fragments ๐ง. Another subtype, "External-body", is defined for specifying large bodies by reference to an external data source ๐
- image: image data ๐ผ๏ธ. Image requires a display device (such as a graphical display, a printer, or a FAX machine) to view the information. Initial subtypes are defined for two widely-used image formats, jpeg and gif ๐ฆ
- audio: audio data ๐ง, with initial subtype "basic". Audio requires an audio output device (such as a speaker or a telephone) to "display" the contents ๐
- video: video data ๐ฌ. Video requires the capability to display moving images, typically including specialized hardware and software. The initial subtype is "mpeg" ๐ฟ
- application: some other kind of data ๐ผ, typically either uninterpreted binary data or information to be processed by a mail-based application. The primary subtype, "octet-stream", is to be used in the case of uninterpreted binary data, in which case the simplest recommended action is to offer to write the information into a file for the user ๐. Two additional subtypes, "ODA" and "PostScript", are defined for transporting ODA and PostScript documents in bodies. Other expected uses for "application" include spreadsheets, data for mail-based scheduling systems, and languages for "active" (computational) email ๐ . (Note that active email entails several securityconsiderations, which are discussed later in this memo, particularly in the context of application/PostScript. Be careful with this one, it's serious ๐)
Default RFC 822 messages are typed by this protocol as plain text in the US-ASCII character set, which can be explicitly specified as Content-type: text/plain; charset=us-ascii ๐. If no Content-Type is specified, either by error or by an older user agent, this default is assumed. In the presence of a MIME-Version header field, a receiving User Agent can also assume that plain US-ASCII text was the sender's intent. In the absence of a MIME-Version specification, plain US-ASCII text must still be assumed, but the sender's intent might have been otherwise ๐คทโโ๏ธ
RATIONALE: In the absence of any Content-Type header field or MIME-Version header field, it is impossible to be certain that a message is actually text in the US-ASCII character set ๐ญ, since it might well be a message that, using the conventions that predate this document, includes text in another character set or non-textual data in a manner that cannot be automatically recognized (e.g., a uuencoded compressed UNIX tar file). Although there is no fully acceptable alternative to treating such untyped messages as "text/plain; charset=us-ascii", implementors should remain aware that if a message lacks both the MIME-Version and the Content-Type header fields, it may in practice contain almost anything ๐
It should be noted that the list of Content-Type values given here may be augmented in time, via the mechanisms described above, and that the set of subtypes is expected to grow substantially ๐ฑ
When a mail reader encounters mail with an unknown Content-type value, it should generally treat it as equivalent to "application/octet-stream", as described later in this document ๐ง
5. The Content-Transfer-Encoding Header Field โจ
Many Content-Types that could usefully be transported via email are represented, in their "natural" format, as 8-bit character or binary data ๐ค. Such data cannot be transmitted over some transport protocols. For example, RFC 821 restricts mail messages to 7-bit US-ASCII data with 1000 character lines ๐.
So it's necessary to define a standard mechanism for re-encoding such data into a 7-bit short-line format ๐ช. This document specifies that such encodings will be indicated by a new "Content-Transfer-Encoding" header field. The Content-Transfer-Encoding field is used to indicate the type of transformation that has been used in order to represent the body in an acceptable manner for transport ๐
Unlike Content-Types, a proliferation of Content-Transfer-Encoding values is undesirable and unnecessary ๐ โโ๏ธ. However, establishing only a single Content-Transfer-Encoding mechanism does not seem possible. There is a tradeoff between the desire for a compact and efficient encoding of largely-binary data and the desire for a readable encoding of data that is mostly, but not entirely, 7-bit data โ๏ธ. For this reason, at least two encoding mechanisms are necessary: a "readable" encoding and a "dense" encoding ๐
The Content-Transfer-Encoding field is designed to specify an invertible mapping between the "native" representation of a type of data and a representation that can be readily exchanged using 7 bit mail transport protocols, such as those defined by RFC 821 (SMTP). This field has not been defined by any previous standard ๐. The field's value is a single token specifying the type of encoding, as enumerated below. Formally:
Content-Transfer-Encoding := "BASE64" / "QUOTED-PRINTABLE" /
"8BIT" / "7BIT" /
"BINARY" / x-token
These values are not case sensitive. That is, Base64 and BASE64 and bAsE64 are all equivalent ๐. An encoding type of 7BIT requires that the body is already in a seven-bit mail-ready representation. This is the default value -- that is, Content-Transfer-Encoding: 7BIT is assumed if the Content-Transfer-Encoding header field is not present ๐ซถ
The values "8bit", "7bit", and "binary" all imply that NO encoding has been performed. However, they are potentially useful as indications of the kind of data contained in the object, and therefore of the kind of encoding that might need to be performed for transmission in a given transport system ๐. "7bit" means that the data is all represented as short lines of US-ASCII data. "8bit" means that the lines are short, but there may be non-ASCII characters (octets with the high-order bit set). "Binary" means that not only may non-ASCII characters be present, but also that the lines are not necessarily short enough for SMTP transport ๐ฅ
The difference between "8bit" (or any other conceivable bit-width token) and the "binary" token is that "binary" does not require adherence to any limits on line length or to the SMTP CRLF semantics, while the bit-width tokens do require such adherence. If the body contains data in any bit-width other than 7-bit, the appropriate bit-width Content-Transfer-Encoding token must be used (e.g., "8bit" for unencoded 8 bit wide data). If the body contains binary data, the "binary" Content-Transfer-Encoding token must be used ๐ฏ
NOTE: The distinction between the Content-Transfer-Encoding values of "binary," "8bit," etc. may seem unimportant, in that all of them really mean "none" -- that is, there has been no encoding of the data for transport ๐. However, clear labeling will be of enormous value to gateways between future mail transport systems with differing capabilities in transporting data that do not meet the restrictions of RFC 821 transport ๐
As of today there are no standardized Internet transports where it's legit to send unencoded 8-bit or binary data in mail bodies ๐ญ So the 8bit and binary Content-Transfer-Encoding values are literally never legal on the Internet right now. BUT if 8-bit or binary mail transport ever becomes a thing, or this doc gets used with any other 8-bit or binary-capable transport, those bodies should be labeled with this mechanism ๐ซถ
NOTE: the five values for the Content-Transfer-Encoding field tell you nothing about the Content-Type, except which algorithm was used to encode it or what the transport needs if it's unencoded ๐
Implementors may, if they really need to, define new Content-Transfer-Encoding values, but they have to use an x-token: a name that starts with "X-" so everyone knows it's non-standard, like Content-Transfer-Encoding: x-my-new-encoding ๐ง Unlike Content-Types and subtypes, though, making new encoding values is explicitly and strongly discouraged, because it seems likely to hurt interoperability for very little benefit ๐ฅฒ They're only allowed when cooperating user agents have agreed to them.
If a Content-Transfer-Encoding header field shows up in a message header, it covers the whole body of that message. If it shows up in a body part's headers, it only covers that body part ๐ธ And if an entity is of type "multipart" or "message", the Content-Transfer-Encoding can only be a bit width (like "7bit", "8bit", etc.) or "binary" ๐
It's worth knowing that email is character-oriented, so these mechanisms are for encoding arbitrary byte streams, not bit streams ๐ฆ If you've got a bit stream and want to encode it with one of these, you first have to turn it into an 8-bit byte stream using the network standard bit order ("big-endian"), where the earlier bits become the higher-order bits in a byte. A bit stream that doesn't end on an 8-bit boundary has to be padded with zeroes. This document gives a way to note that padding was added, for the application Content-Type, which has a "padding" parameter โจ
The encoding mechanisms here explicitly encode all data in ASCII ๐ So if an entity has header fields like these:
Content-Type: text/plain; charset=ISO-8859-1
Content-transfer-encoding: base64
that means the body is a base64 ASCII encoding of data that started out in ISO-8859-1, and it'll be in that same character set again after decoding ๐
The next sections define the two standard encoding mechanisms ๐ Defining new content-transfer-encodings is explicitly discouraged and should only happen when it's absolutely necessary. Everything in the content-transfer-encoding namespace except values starting with "X-" is explicitly reserved to the IANA for future use. Private agreements about content-transfer-encodings are also explicitly discouraged ๐
Some Content-Transfer-Encoding values can only be used with certain Content-Types. Specifically, it is expressly forbidden to use any encoding other than "7bit", "8bit", or "binary" with any Content-Type that recursively includes other Content-Type fields, like "multipart" and "message" ๐ Any encodings wanted for multipart or message bodies have to happen at the innermost level, by encoding the actual body that needs it โจ
NOTE ON ENCODING RESTRICTIONS: I know banning encodings on multipart or message data might seem super restrictive ๐ But it's there to stop nested encodings, where data goes through an encoding algorithm multiple times and then has to be decoded multiple times before anyone can read it. Nested encodings add a lot of complexity for user agents. Aside from the obvious efficiency problems, they can hide the basic structure of a message, and they can imply that you need several decoding steps just to figure out what kinds of objects a message contains. Banning nested encodings might make life harder for some mail gateways, but that's way less of a problem than what nested encodings do to user agents ๐ซถ
NOTE ON THE RELATIONSHIP BETWEEN CONTENT-TYPE AND CONTENT-TRANSFER-ENCODING: You might think the Content-Transfer-Encoding could be inferred from the Content-Type being encoded, or at least that certain encodings could be required for certain Content-Types. There are a few reasons it doesn't work like that ๐ First, mail uses lots of different transports, so some encodings may fit some Content-Type/transport combos and not others. (For example, on an 8-bit transport no encoding is needed for text in certain character sets, but those encodings are clearly required for 7-bit SMTP.) Second, some Content-Types need different transfer encodings in different situations. Lots of PostScript bodies are just short lines of 7-bit data and need little or no encoding, but others (especially ones using Level 2 PostScript's binary encoding mechanism) can only really be represented with a binary transport encoding โญ Finally, Content-Type is meant to be an open-ended specification mechanism, so tying Content-Types to specific encodings would couple an application protocol to a specific lower-level transport. That's not great, because Content-Type developers shouldn't have to know every transport in use and what its limits are ๐ง
NOTE ON TRANSLATING ENCODINGS: The quoted-printable and base64 encodings are designed so you can convert between them. The only tricky part is line breaks. When converting from quoted-printable to base64, a line break has to become a CRLF sequence. Likewise, a CRLF sequence in base64 data should become a quoted-printable line break, but ONLY when you're converting text data ๐ฆ
NOTE ON CANONICAL ENCODING MODEL: Earlier drafts of this memo were kind of confusing about when email data should be converted to canonical form and encoded, and especially how that affects CRLFs, since newline representation varies a lot from system to system ๐ Because of that, the canonical encoding model is presented in Appendix H ๐
5.1 Quoted-Printable Content-Transfer-Encoding
The Quoted-Printable encoding is meant for data that mostly consists of octets matching printable ASCII characters ๐ It encodes the data so the resulting octets are unlikely to get changed by mail transport. If the data is mostly ASCII text, the encoded form stays pretty recognizable to humans ๐ A body that's entirely ASCII can also be encoded in Quoted-Printable, to protect the data's integrity if the message goes through a character-translating and/or line-wrapping gateway ๐ซถ
In this encoding, octets are represented according to these rules:
- Rule #1 (General 8-bit representation): Any octet, except those marking a line break under the newline convention of the canonical form of the data being encoded, may be represented as an "=" followed by a two-digit hexadecimal representation of the octet's value. The hexadecimal digits for this purpose are "0123456789ABCDEF". Uppercase letters must be used when sending hexadecimal data, though a robust implementation may choose to recognize lowercase letters on receipt ๐
For example, the value 12 (ASCII form feed) can be represented as
=0C, and the value 61 (ASCII EQUAL SIGN) can be represented as=3D. Unless one of the following rules allows an alternative encoding, this rule is mandatory ๐ฅ - Rule #2 (Literal representation): Octets with decimal values 33 through 60 inclusive, and 62 through 126 inclusive, MAY be represented as the ASCII characters that match those octets (EXCLAMATION POINT through LESS THAN, and GREATER THAN through TILDE, respectively) โจ
Rule #3: (White Space) ๐ซง Octets with values of 9 and 32 MAY be represented as ASCII TAB (HT) and SPACE characters, respectively, but MUST NOT be so represented at the end of an encoded line. So any TAB (HT) or SPACE characters on an encoded line MUST be followed on that line by a printable character. An "=" at the end of an encoded line, which marks a soft line break (see rule #5), can come after one or more TAB (HT) or SPACE characters. That means an octet with value 9 or 32 at the end of an encoded line has to be represented according to Rule #1. This rule exists because 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 of text with SPACEs, and others are known to strip "white space" characters from the end of a line. So when you decode a Quoted-Printable body, any trailing white space on a line must be deleted, since intermediate transport agents will have added it. ๐
Rule #4 (Line Breaks) ๐ A line break in a text body part, whatever its representation is under the canonical representation of the data being encoded, must be represented by a (RFC 822) line break, which is a CRLF sequence, in the Quoted-Printable encoding. If isolated CRs and LFs, or LF CR and CR LF sequences, are allowed to appear in binary data under the canonical form, they must be represented using the "=0D", "=0A", "=0A=0D" and "=0D=0A" notations respectively. ๐ฆ
Many implementations may choose to encode the local representation of various content types directly. This can apply especially to plain text on systems that use newline conventions other than CRLF delimiters. That kind of implementation is permissible, but the generation of line breaks must be generalized to account for the case where alternate representations of newline sequences are used. โจ
Rule #5 (Soft Line Breaks) ๐ The Quoted-Printable encoding REQUIRES that encoded lines be no more than 76 characters long. If longer lines need to be encoded with Quoted-Printable, "soft" line breaks must be used. An equal sign as the last character on an encoded line signals a non-significant ("soft") line break in the encoded text. So if the "raw" form of the line is a single unencoded line that says:
Now's the time for all folk to come to the aid of
their country.
It can be represented in the Quoted-Printable encoding as:
Now's the time =
for all folk to come=
to the aid of their country.
This gives us a way to encode long lines so that the user agent can restore them. The 76 character limit does not count the trailing CRLF, but it does count all other characters, including any equal signs. ๐
Since the hyphen character ("-") is represented as itself in the Quoted-Printable encoding, you have to be careful when you wrap a quoted-printable encoded body in a multipart entity. Make sure the encapsulation boundary doesn't appear anywhere in the encoded body. (A good strategy is to pick a boundary that includes a character sequence such as "=_", which can never appear in a quoted-printable body. See the definition of multipart messages later in this document.) ๐ง
NOTE: The quoted-printable encoding is a bit of a compromise between readability and reliability in transport. Bodies encoded with quoted-printable will work reliably over most mail gateways, but may not work perfectly over a few gateways, notably those involving translation into EBCDIC. (In theory, an EBCDIC gateway could decode a quoted-printable body and re-encode it using base64, but such gateways do not yet exist.) A higher level of confidence is offered by the base64 Content-Transfer-Encoding. A way to get reasonably reliable transport through EBCDIC gateways is to also quote the ASCII characters !"#$@[\]^`{|}~ according to rule #1. See Appendix B for more information. ๐
Because quoted-printable data is generally assumed to be line-oriented, it is expected that the breaks between the lines of quoted-printable data may be altered in transport. This is the same way plain text mail has always been altered in Internet mail when it passes between systems with different newline conventions. If such alterations are likely to corrupt the data, it is probably more sensible to use the base64 encoding rather than the quoted-printable encoding. ๐ญ
5.2. Base64 Content-Transfer-Encoding ๐
The Base64 Content-Transfer-Encoding is designed to represent arbitrary sequences of octets in a form that is not humanly readable. The encoding and decoding algorithms are simple, but the encoded data is consistently only about 33 percent larger than the unencoded data. This encoding is based on the one used in Privacy Enhanced Mail applications, as defined in RFC 1113. The base64 encoding is adapted from RFC 1113, with one change: base64 eliminates the "*" mechanism for embedded clear text. ๐
A 65-character subset of US-ASCII is used, which lets you represent 6 bits per printable character. (The extra 65th character, "=", is used to signify a special processing function.) ๐ธ
NOTE: This subset has the important property that it is represented identically in all versions of ISO 646, including US ASCII, and all characters in the subset are also represented identically in all versions of EBCDIC. Other popular encodings, such as the encoding used by the UUENCODE utility and the base85 encoding specified as part of Level 2 PostScript, do not share these properties, and so they do not fulfill the portability requirements a binary transport encoding for mail must meet. ๐
The encoding process represents 24-bit groups of input bits as output strings of 4 encoded characters. Going from left to right, a 24-bit input group is formed by concatenating 3 8-bit input groups. These 24 bits are then treated as 4 concatenated 6-bit groups, and each of those is translated into a single digit in the base64 alphabet. When you encode a bit stream with base64, the bit stream must be presumed to be ordered with the most-significant-bit first. That means the first bit in the stream is the high-order bit in the first byte, the eighth bit is the low-order bit in the first byte, and so on. ๐ฅ
Each 6-bit group is used as an index into an array of 64 printable characters. The character the index points to goes into the output string. These characters, listed in Table 1 below, were picked so they can be represented universally. The set also excludes characters with particular significance to SMTP (e.g., ".", "CR", "LF") and to the encapsulation boundaries defined in this document (e.g., "-"). โญ
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 output stream (encoded bytes) must be represented in lines of no more than 76 characters each. All line breaks or other characters not found in Table 1 must be ignored by decoding software. In base64 data, characters other than those in Table 1, line breaks, and other white space probably indicate a transmission error. A warning message, or even a message rejection, might be appropriate under some circumstances. ๐ท
Okay so, special processing kicks in when fewer than 24 bits are left at the end of the data being encoded ๐. A full encoding quantum is always completed at the end of a body โจ. When there are fewer than 24 input bits in an input group, zero bits get tacked on (on the right) so you end up with a whole number of 6-bit groups ๐ธ. Any output character positions that aren't needed for real input data get set to the character = ๐
. Since all base64 input is a whole number of octets, only 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, or - 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.
Care must be taken to use the proper octets for line breaks if base64 encoding is applied directly to text material that has not been converted to canonical form ๐. In particular, text line breaks should be converted into CRLF sequences prior to base64 encoding ๐. The important thing to note is that this may be done directly by the encoder, rather than in a prior canonicalization step, in some implementations โจ.
NOTE: There is no need to worry about quoting apparent encapsulation boundaries within base64-encoded parts of multipart entities, because no hyphen characters are used in the base64 encoding ๐.
6. Additional Optional Content- Header Fields โจ
6.1. Optional Content-ID Header Field
So when you're building a high-level user agent, it can be super useful to let one body reference another ๐ฆ. Bodies can be labeled with the "Content-ID" header field, which is syntactically identical to the "Message-ID" header field:
Content-ID := msg-id
Like the Message-ID values, Content-ID values must be generated to be as unique as possible ๐ฅ.
6.2. Optional Content-Description Header Field
Attaching some descriptive info to a body is often a must-have ๐. For example, you could mark an "image" body as "a picture of the Space Shuttle Endeavor." ๐ Such text goes in the Content-Description header field ๐.
Content-Description := *text
The description is presumed to be given in the US-ASCII character set, although the mechanism specified in [RFC-1342] may be used for non-US-ASCII Content-Description values ๐ง.
7. The Predefined Content-Type Values ๐
This document defines seven initial Content-Type values and an extension mechanism for private or experimental types ๐ . Further standard types must be defined by new published specifications. It's expected that most innovation in new types of mail will happen as subtypes of the seven types defined here ๐ธ. The most essential characteristics of the seven content-types are summarized in Appendix G โจ.
7.1. The Text Content-Type
The text Content-Type is for sending material that's principally textual in form ๐. It's the default Content-Type ๐. A "charset" parameter may be used to indicate the character set of the body text. The primary subtype of text is "plain", meaning plain (unformatted) text ๐. The default Content-Type for Internet mail is text/plain; charset=us-ascii ๐ฆ.
Beyond plain text, there are many formats for representing what might be known as "extended text": text with embedded formatting and presentation information ๐. An interesting thing about lots of these is that they're somewhat readable even without the software that interprets them ๐. So it's useful to tell them apart, at the highest level, from unreadable data like images, audio, or text represented in an unreadable form ๐. Without the right interpreting software, it's reasonable to show text subtypes to the user, but not reasonable to do so with most nontextual data ๐.
Formatted textual data should be represented using subtypes of text ๐ซถ. Plausible subtypes of text are typically named after the common name of the representation format, e.g., text/richtext โจ.
7.1.1. The charset parameter
The character set is a critical parameter that may be specified in the Content-Type field for text data ๐ค. It's specified with a "charset" parameter, like this:
Content-type: text/plain; charset=us-ascii
Unlike some other parameter values, the values of the charset parameter are NOT case sensitive ๐ฅ. The default character set, which must be assumed when there's no charset parameter, is US-ASCII ๐ .
An initial list of predefined character set names is at the end of this section ๐. Additional character sets may be registered with IANA as described in Appendix F, although standardizing their use requires the usual IAB review and approval ๐. Note that if the specified character set includes 8-bit data, a Content-Transfer-Encoding header field and a corresponding encoding on the data are required in order to transmit the body via some mail transfer protocols, such as SMTP ๐ฆ.
The default character set, US-ASCII, has been the subject of some confusion and ambiguity in the past ๐ญ. Not only were there ambiguities in the definition, there have been wide variations in practice ๐. To eliminate that ambiguity and those variations going forward, it is strongly recommended that new user agents explicitly specify a character set via the Content-Type header field ๐ธ. "US-ASCII" does not indicate an arbitrary seven-bit character code; it specifies that the body uses character coding with the exact correspondence of codes to characters specified in ASCII โจ. National use variations of ISO 646 [ISO-646] are NOT ASCII, and their use in Internet mail is explicitly discouraged ๐ซ. The omission of the ISO 646 character set is deliberate in this regard ๐. The character set name of "US-ASCII" explicitly refers to ANSI X3.4-1986 [US-ASCII] only ๐. The character set name "ASCII" is reserved and must not be used for any purpose ๐ซถ.
NOTE: RFC 821 explicitly specifies "ASCII", and references an earlier version of the American Standard. Insofar as one of the purposes of specifying a Content-Type and character set is to let the receiver unambiguously determine how the sender intended the coded message to be interpreted, assuming anything other than "strict ASCII" as the default would risk unintentional and incompatible changes to the semantics of messages now being transmitted ๐ง. This also implies that messages containing characters coded according to national variations on ISO 646, or using code-switching procedures (e.g., those of ISO 2022), as well as 8-bit or multiple octet character encodings MUST use an appropriate character set specification to be consistent with this specification ๐ฅ.
The complete US-ASCII character set is listed in [US-ASCII]. Note that the control characters, including DEL (0-31, 127), have no defined meaning apart from the combination CRLF (ASCII values 13 and 10) indicating a new line ๐. Two of the characters have de facto meanings in wide use: FF (12) often means "start subsequent text on the beginning of a new page"; and TAB or HT (9) often (though not always) means "move the cursor to the next available column after the current position where the column number is a multiple of 8 (counting the first column as column 0)." ๐ Apart from this, any use of the control characters or DEL in a body must be part of a private agreement between the sender and recipient ๐. Such private agreements are discouraged and should be replaced by the other capabilities of this document ๐.
NOTE: Beyond US-ASCII, an enormous proliferation of character sets is possible. It is the opinion of the IETF working group that a large number of character sets is NOT a good thing ๐ค. We would prefer to specify a single character set that can be used universally for representing all of the world's languages in electronic mail ๐. Unfortunately, existing practice in several communities seems to point to the continued use of multiple character sets in the near future ๐. For this reason, we define names for a small number of character sets for which a strong constituent base exists ๐ซถ. It is our hope that ISO 10646 or some other effort will eventually define a single world character set which can then be specified for use in Internet mail, but in the advance of that definition we cannot specify the use of ISO 10646, Unicode, or any other character set whose definition is, as of this writing, incomplete โจ.
The defined charset values are:
US-ASCII -- as defined in [US-ASCII].
ISO-8859-X -- where "X" is to be replaced, as
necessary, for the parts of ISO-8859 [ISO-
8859]. Note that the ISO 646 character sets
have deliberately been omitted in favor of
their 8859 replacements, which are the
designated character sets for Internet mail.
As of the publication of this document, the
legitimate values for "X" are the digits 1
through 9.
Note that the character set used, if anything other than US-ASCII, must always be explicitly specified in the Content-Type field ๐.
Okay so the rule is no other character set name may be used in Internet mail unless it has a formal spec published and gets registered with IANA (see Appendix F). The other option is a private agreement, and then the name has to start with X-. ๐
Implementors are discouraged from making up new character sets for mail unless it's absolutely, 100% necessary ๐
The charset parameter was mainly made for textual data, which is why it lives in this section ๐ But non-textual data could also want a charset value for something, and if it does, the same syntax and values should be used ๐ฆ
Now the big tip: mail-sending software should always go for the "lowest common denominator" character set it can ๐ธ For example, if a body only has US-ASCII characters, label it as US-ASCII, NOT ISO-8859-1. ISO-8859-1 (and the whole ISO-8859 family) is a superset of US-ASCII, so it's giving extra and not needed ๐ More generally, if a widely-used character set is a subset of another one, and your body only has characters from that smaller widely-used subset, label it as that subset. This boosts the chances that the recipient can view the mail correctly โจ
7.1.2. The Text/plain subtype
The primary subtype of text is "plain" ๐ This means plain, unformatted text. The default Content-Type for Internet mail, text/plain; charset=us-ascii, is basically describing what already happens on the Internet, since it's the type of body defined by RFC 822 ๐
7.1.3. The Text/richtext subtype
So to help simple formatted text play nicely across systems ๐ง this document defines a super simple subtype of "text" called "richtext" โจ It was designed to hit these criteria:
- The syntax must be extremely simple to parse, so that even teletype-oriented mail systems can easily strip away the formatting information and leave only the readable text.
- The syntax must be extensible to allow for new formatting commands that are deemed essential.
- The capabilities must be extremely limited, to ensure that it can represent no more than is likely to be representable by the user's primary word processor. While this limits what can be sent, it increases the likelihood that what is sent can be properly displayed.
- The syntax must be compatible with SGML, so that, with an appropriate DTD (Document Type Definition, the standard mechanism for defining a document type using SGML), a general SGML parser could be made to parse richtext. However, despite this compatibility, the syntax should be far simpler than full SGML, so that no SGML knowledge is required in order to implement it.
Okay the syntax of richtext is very chill ๐ It's assumed, at the top level, to be US-ASCII, unless a different charset parameter was specified in the Content-type field. Every character represents itself, except for the < character (ASCII 60), which marks the start of a formatting command ๐
Formatting instructions are formatting commands wrapped in angle brackets (<>, ASCII 60 and 62). Each formatting command may be no more than 40 characters long, all in US-ASCII, and restricted to alphanumeric characters and the hyphen (-). Formatting commands may be preceded by a forward slash or solidus (/, ASCII 47), which makes them negations. Negations must always exist to balance the initial opening commands, except as noted below. So if <bold> shows up somewhere, there must later be a </bold> to balance it ๐
There are only three exceptions to this balancing rule ๐ซถ
- First, the command
<lt>is used to represent a literal<character. - Second, the command
<nl>is used to represent a required line break. (Otherwise, CRLFs in the data are treated as equivalent to a single SPACE character.) - Finally, the command
<np>is used to represent a page break. (NOTE: The 40 character limit on formatting commands does not include the<,>, or/characters that might be attached to such commands.)
Here are the initially defined formatting commands. Not every richtext implementation will support all of them ๐ญ
Bold-- causes the subsequent text to be in a bold font.Italic-- causes the subsequent text to be in an italic font.Fixed-- causes the subsequent text to be in a fixed width font.Smaller-- causes the subsequent text to be in a smaller font.Bigger-- causes the subsequent text to be in a bigger font.Underline-- causes the subsequent text to be underlined.Center-- causes the subsequent text to be centered.FlushLeft-- causes the subsequent text to be left justified.FlushRight-- causes the subsequent text to be right justified.Indent-- causes the subsequent text to be indented at the left margin.IndentRight-- causes the subsequent text to be indented at the right margin.Outdent-- causes the subsequent text to be outdented at the left margin.OutdentRight-- causes the subsequent text to be outdented at the right margin.SamePage-- causes the subsequent text to be grouped, if possible, on one page.Subscript-- causes the subsequent text to be interpreted as a subscript.Superscript-- causes the subsequent text to be interpreted as a superscript.Heading-- causes the subsequent text to be interpreted as a page heading.Footing-- causes the subsequent text to be interpreted as a page footing.ISO-8859-X(for any value of X that is legal as acharsetparameter) -- causes the subsequent text to be interpreted as text in the appropriate character set.US-ASCII-- causes the subsequent text to be interpreted as text in the US-ASCII character set.Excerpt-- causes the subsequent text to be interpreted as a textual excerpt from another source. Typically this will be displayed using indentation and an alternate font, but such decisions are up to the viewer.Paragraph-- causes the subsequent text to be interpreted as a single paragraph, with appropriate paragraph breaks (typically blank space) before and after.Signature-- causes the subsequent text to be interpreted as a "signature". Some systems may wish to display signatures in a smaller font or otherwise set them apart from the main text of the message.Comment-- causes the subsequent text to be interpreted as a comment, and hence not shown to the reader.No-op-- has no effect on the subsequent text.lt--<lt>is replaced by a literal<character. No balancing</lt>is allowed.nl--<nl>causes a line break. No balancing</nl>is allowed.np--<np>causes a page break. No balancing</np>is allowed.
Each positive formatting command affects all subsequent text until its matching negative formatting command shows up. These pairs must be properly balanced and nested โจ So a proper way to do bold italics is:
<bold><italic>the-text</italic></bold>
or, alternately:
<italic><bold>the-text</bold></italic>
But, in particular, the following is illegal richtext ๐ซ
<bold><italic>the-text</bold></italic>
NOTE: The nesting requirement for formatting commands makes life a bit harder for the people writing richtext bodies, but it can make richtext displayers simpler by letting them be stack-based. The main goal of richtext is to be simple enough that multifont, formatted email is widely readable, so people who can send it can do so with confidence. So a little extra complexity for the composing software was seen as a fair tradeoff for simpler reading software. Still, implementors of richtext readers are encouraged to follow the general Internet guideline of being conservative in what you send and liberal in what you accept. Implementations that can do so are encouraged to deal reasonably with improperly nested richtext. ๐
Implementations must treat any unrecognized formatting command as equivalent to "No-op", which makes future extensions to "richtext" way easier to add ๐ฆ Private extensions can be defined using formatting commands that begin with X-, which is the same idea as the X- prefix for Internet mail header field names ๐
Okay so, the TAB (HT) character gets no special behavior, bestie ๐
nobody's forced to do anything fancy with it. BUT it is recommended (lowkey a strong suggestion ๐ซถ) that, at least when fixed-width fonts are in use, the common semantics of TAB (HT) should be observed. That means it jumps to the next column position that is a multiple of 8. ๐ Like, if a TAB (HT) lands in column n (leftmost column is column 0), then that TAB (HT) should be replaced by 8-(n mod 8) SPACE characters. Math ate, no crumbs ๐
Richtext also has "hard" and "soft" line breaks, and this is where it gets iconic โจ A line break (CRLF) in the richtext data stream is a "soft" line break. It only exists for mail transport, so richtext interpreters treat it as white space ๐ฆ If you want a "hard" line break (one that must be displayed as such), you use the <nl> or <paragraph> formatting constructs. In general a soft line break is white space, BUT when soft line breaks immediately follow a <nl> or a </paragraph> tag, they should be ignored rather than treated as white space. Not me getting a sneaky extra space ๐
Putting all this together, here's a "text/richtext" body fragment ๐
<bold>Now</bold> is the time for
<italic>all</italic> good men
<smaller>(and <lt>women>)</smaller> to
<ignoreme></ignoreme> come
to the aid of their
<nl>
beloved <nl><nl>country. <comment> Stupid
quote! </comment> -- the end
And it represents this formatted text (which will, no doubt, look cryptic in the text-only version of this document ๐):
Now is the time for all good men (and <women>) to
come to the aid of their
beloved
country. -- the end
Richtext conformance time ๐ A minimal richtext implementation is one that simply converts <lt> to <, converts CRLFs to SPACE, converts <nl> to a newline according to local newline convention, removes everything between a <comment> command and the next balancing </comment> command, and removes all other formatting commands (all text enclosed in angle brackets). That's it, that's the whole vibe โจ
NOTE ON THE RELATIONSHIP OF RICHTEXT TO SGML: Richtext is decidedly not SGML ๐
โโ๏ธ and it must not be used to transport arbitrary SGML documents. If you want to use SGML document types as a mail transport format, you have to define a new text or application subtype, e.g., text/sgml-dtd-whatever or application/sgml-dtd-whatever, depending on the perceived readability of the DTD in use. Richtext is designed to be compatible with SGML, specifically so it'll be possible to define a richtext DTD if one is needed. BUT this does not imply that arbitrary SGML can be called richtext, nor that richtext implementors have any need to understand SGML. The description in this document is a complete definition of richtext, which is far simpler than complete SGML ๐ง
NOTE ON THE INTENDED USE OF RICHTEXT: It's recognized that implementors of future mail systems will want rich text functionality far beyond what's currently defined for richtext. The intent of richtext is to provide a common format for expressing that functionality in a form that much of it, at least, will be understood by interoperating software ๐ธ So software with a richer notion of formatted text can still use richtext as its basic representation, and extend it with new formatting commands and by hiding system-specific information in richtext comments. As these systems evolve, the definition of richtext is expected to be further refined by future published specifications, but richtext as defined here provides a platform that evolutionary refinements can be built on ๐
IMPLEMENTATION NOTE: In some environments it might be impossible to combine certain richtext formatting commands, whereas in others they might be combined easily. For example, the combination of <bold> and <italic> might produce bold italics on systems that support such fonts, but there exist systems that can make text bold or italicized, but not both. In such cases, the most recently issued recognized formatting command should be preferred ๐ฅ
One of the major goals in designing richtext was to make it so simple that even text-only mailers will implement richtext-to-plain-text translators. That makes multifont text more likely to become "safe" to use very widely ๐ To prove how simple it is, an extremely simple 35-line C program that converts richtext input into plain text output is included in Appendix D. Main character energy ๐
7.2 The Multipart Content-Type โจ
In the case of multiple part messages, where one or more different sets of data are combined in a single body, a "multipart" Content-Type field must appear in the entity's header. The body must then contain one or more "body parts," each preceded by an encapsulation boundary, with the last one followed by a closing boundary. Each part starts with an encapsulation boundary, and then contains a body part made of a header area, a blank line, and a body area. So a body part is similar to an RFC 822 message in syntax, but different in meaning ๐ฆ
A body part is NOT to be interpreted as actually being an RFC 822 message ๐ โโ๏ธ To begin with, NO header fields are actually required in body parts. A body part that starts with a blank line is allowed, and it's a body part where all default values are to be assumed. In that case, the absence of a Content-Type header field implies the encapsulation is plain US-ASCII text. The only header fields with defined meaning for body parts are the ones whose names begin with "Content-". All other header fields are generally to be ignored in body parts. Although they should generally be retained in mail processing, they may be discarded by gateways if necessary. Those other fields are permitted to appear in body parts but should not be depended on. "X-" fields may be created for experimental or private purposes, with the recognition that the information they contain may be lost at some gateways ๐
The distinction between an RFC 822 message and a body part is subtle, but important ๐ซถ A gateway between Internet and X.400 mail, for example, must be able to tell the difference between a body part that contains an image and a body part that contains an encapsulated message whose body is an image. To represent the latter, the body part must have "Content-Type: message", and its body (after the blank line) must be the encapsulated message, with its own "Content-Type: image" header field. The similar syntax makes it easier to convert messages to body parts and back again, but implementors have to understand the difference between the two. (For the special case where all parts actually are messages, a "digest" subtype is also defined ๐)
As stated previously, each body part is preceded by an encapsulation boundary. The encapsulation boundary MUST NOT appear inside any of the encapsulated parts. So it's crucial that the composing agent can choose and specify the unique boundary that will separate the parts ๐ญ
All present and future subtypes of the "multipart" type must use an identical syntax. Subtypes may differ in their semantics, and may impose additional restrictions on syntax, but must conform to the required syntax for the multipart type. This requirement ensures that all conformant user agents will at least be able to recognize and separate the parts of any multipart entity, even of an unrecognized subtype ๐
As stated in the definition of the Content-Transfer-Encoding field, no encoding other than "7bit", "8bit", or "binary" is permitted for entities of type "multipart". The multipart delimiters and header fields are always 7-bit ASCII in any case, and data within the body parts can be encoded on a part-by-part basis, with Content-Transfer-Encoding fields for each appropriate body part ๐
Mail gateways, relays, and other mail handling agents are commonly known to alter the top-level header of an RFC 822 message. In particular, they frequently add, remove, or reorder header fields. Such alterations are explicitly forbidden for the body part headers embedded in the bodies of messages of type "multipart" ๐ซ๐
7.2.1 Multipart: The common syntax ๐ง
All subtypes of "multipart" share a common syntax, defined in this section. A simple example of a multipart message also appears in this section, and a more complex one is given in Appendix C ๐ธ
The Content-Type field for multipart entities requires one parameter, "boundary", which is used to specify the encapsulation boundary. The encapsulation boundary is defined as a line consisting entirely of two hyphen characters ("-", decimal code 45) followed by the boundary parameter value from the Content-Type header field ๐ซถ Okay bestie, that's the boundary energy, periodt โจ
NOTE, bestie: the hyphens are there for rough compatibility with the older RFC 934 way of encapsulating messages, and so it's easier to spot the boundaries in some implementations ๐. But multipart messages are not fully compatible with RFC 934 encapsulations ๐. In particular, they don't follow RFC 934 quoting rules for embedded lines that start with hyphens. This mechanism was picked over RFC 934 because the RFC 934 one makes lines grow with every level of quoting, and SMTP implementations sometimes wrap long lines. Put those two together and RFC 934 just isn't up for deeply-nested multipart structures ๐.
So a typical multipart Content-Type header field might look like this ๐:
Content-Type: multipart/mixed;
boundary=gc0p4Jq0M2Yt08jU534c0p
This tells you the entity has several parts โจ. Each part has its own structure that's syntactically identical to an RFC 822 message, except the header area can be completely empty. Every part is preceded by the line:
--gc0p4Jq0M2Yt08jU534c0p
The encapsulation boundary has to start at the beginning of a line, which means right after a CRLF. That initial CRLF counts as part of the encapsulation boundary, not part of the previous part ๐ง. After the boundary, you either get another CRLF and the header fields for the next part, or two CRLFs, which means there are no header fields for that part. In that second case, it's assumed to be Content-Type text/plain ๐.
NOTE: The CRLF before the encapsulation line counts as part of the boundary, so a part is allowed to not end with a CRLF (line break) ๐. So if a body part should be seen as ending with line breaks, put two CRLFs before the encapsulation line. The first one belongs to the body part before it, and the second one belongs to the encapsulation boundary.
The fact that the encapsulation boundary starts with a CRLF also means the body of a multipart entity has to begin with a CRLF before the first encapsulation line ๐ซถ. So if you're not using the "preamble" area, the entity headers need to be followed by two CRLFs. This is how these entities should be composed ๐ . A tolerant mail reading program might treat a multipart body that starts with an encapsulation line without a leading CRLF as a boundary anyway. But a compliant mail sending program must not generate entities like that ๐ โโ๏ธ.
Encapsulation boundaries must not show up inside the encapsulations, and they must be no longer than 70 characters, not counting the two leading hyphens ๐.
The encapsulation boundary after the last body part is a special delimiter that says no more body parts are coming ๐. It looks exactly like the earlier delimiters, except it has two extra hyphens at the end of the line:
--gc0p4Jq0M2Yt08jU534c0p--
There seems to be room for extra information before the first encapsulation boundary and after the final boundary ๐ธ. Those areas should generally be left blank, and implementations should ignore anything that shows up before the first boundary or after the last one ๐.
NOTE: These "preamble" and "epilogue" areas aren't used, because these parts aren't properly typed, and there aren't clear semantics for handling these areas at gateways, especially X.400 gateways ๐ญ.
NOTE: Encapsulation boundaries must not appear in the body parts being encapsulated, so a user agent has to be careful to pick a unique boundary ๐. The boundary in the example above could have come from an algorithm that makes boundaries with a very low chance of already existing in the data, without needing to scan the data first โจ. Other algorithms might make boundaries that are more 'readable' for a recipient with an old user agent, but they'd need more attention to make sure the boundary doesn't show up in the encapsulated part ๐ค. The simplest boundary possible is something like "---", with a closing boundary of "-----".
Here's a super simple example ๐ฆ. This multipart message has two parts, both plain text. One is explicitly typed and one is implicitly typed:
From: Nathaniel Borenstein <nsb@bellcore.com>
To: Ned Freed <ned@innosoft.com>
Subject: Sample message
MIME-Version: 1.0
Content-type: multipart/mixed; boundary="simple
boundary"
This is the preamble. It is to be ignored, though it
is a handy place for mail composers to include an
explanatory note to non-MIME compliant readers.
--simple boundary
This is implicitly typed plain ASCII text.
It does NOT end with a linebreak.
--simple boundary
Content-type: text/plain; charset=us-ascii
This is explicitly typed plain ASCII text.
It DOES end with a linebreak.
--simple boundary--
This is the epilogue. It is also to be ignored.
Using a Content-Type of multipart inside a body part that's already in another multipart entity is totally allowed ๐ช. But then, obviously, you have to be careful that each nested multipart entity uses a different boundary delimiter ๐ง . See Appendix C for an example of nested multipart entities ๐.
Using the multipart Content-Type with only a single body part is also explicitly permitted. It can be useful in certain contexts ๐.
The only mandatory parameter for the multipart Content-Type is the boundary parameter ๐. It's 1 to 70 characters from a set of characters known to be super robust through email gateways, and it doesn't end with white space ๐. (If a boundary looks like it ends with white space, that white space has to be presumed to have been added by a gateway, and it should be deleted ๐งน.) It's formally specified by the following BNF:
boundary := 0*69<bchars> bcharsnospace
bchars := bcharsnospace / " "
bcharsnospace := DIGIT / ALPHA / "'" / "(" / ")" / "+" /
"_"
/ "," / "-" / "." / "/" / ":" / "=" / "?"
Overall, the body of a multipart entity looks like this ๐งโโ๏ธ:
multipart-body := preamble 1*encapsulation
close-delimiter epilogue
encapsulation := delimiter CRLF body-part
delimiter := CRLF "--" boundary ; taken from Content-Type
field.
; when content-type is
multipart
; There must be no space
; between "--" and boundary.
close-delimiter := delimiter "--" ; Again, no space before
"--"
preamble := *text ; to be ignored upon
receipt.
epilogue := *text ; to be ignored upon
receipt.
body-part = <"message" as defined in RFC 822,
with all header fields optional, and with the
specified delimiter not occurring anywhere in
the message body, either on a line by itself
or as a substring anywhere. Note that the
semantics of a part differ from the semantics
of a message, as described in the text.>
NOTE: The multipart type is missing one big thing: structured, related body parts ๐คทโโ๏ธ. In general, it seems too early to try to standardize how parts are structured with each other yet. If you want a more structured or integrated multipart messaging facility, the recommended move is to define a subtype of multipart that's syntactically identical. That subtype should always expect a special part that specifies the structure and integration of the other parts, probably by referring to them through their Content-ID field ๐. If you go this route, other implementations won't recognize the new subtype. They'll treat it as the primary subtype (multipart/mixed) instead, so they can still show the user the parts they do recognize ๐.
7.2.2 The Multipart/mixed (primary) subtype ๐
The primary subtype for multipart, "mixed", is meant for body parts that are independent and should be displayed one after another ๐. Any multipart subtypes that an implementation doesn't recognize should be treated as being of subtype "mixed" ๐ซถ.
7.2.3 The Multipart/alternative subtype ๐ฆ
The multipart/alternative type is syntactically identical to multipart/mixed, but the semantics are different ๐ท. Each part is an "alternative" version of the same information, so user agents should recognize that the content of the various parts is interchangeable ๐ก. The user agent should either pick the "best" type based on the user's environment and preferences, or offer the user the available alternatives ๐ฏ. Usually, picking the best type means displaying only the LAST part that can be displayed ๐. This can be used, for example, to send mail in a fancy text format in a way that can easily be displayed anywhere ๐ญ:
From: Nathaniel Borenstein <nsb@bellcore.com>
To: Ned Freed <ned@innosoft.com>
Subject: Formatted text mail
MIME-Version: 1.0
Content-Type: multipart/alternative; boundary=boundary42
--boundary42
Content-Type: text/plain; charset=us-ascii
...plain text version of message goes here....
--boundary42
Content-Type: text/richtext
Okay so the richtext and fancy versions are both just sitting there in one message, bestie ๐ Here's how the whole multipart/alternative thing plays out:
.... richtext version of same message goes here ...
--boundary42
Content-Type: text/x-whatever
.... fanciest formatted version of same message goes here
...
--boundary42--
So in this example, anyone whose mail app understands text/x-whatever only sees the fancy version ๐. Everyone else sees the richtext or plain text version, depending on what their system can handle ๐ฆ
Now, the ordering rule. When user agents compose a multipart/alternative, they SHOULD put the parts in increasing order of preference, so the favorite format goes last ๐ For fancy text, the sending agent SHOULD put the plainest format first and the richest format last โจ Receiving agents SHOULD pick and display the last format they can actually show. And if one alternative is itself a "multipart" with bits they don't recognize, the user agent MAY show that alternative, an earlier one, or both ๐
NOTE: From an implementor's point of view, it might seem more sensible to flip this and make the plainest alternative last ๐ But putting the plainest one first is the friendliest option when multipart/alternative entities get viewed in a non-MIME-compliant mail reader. Yes, this does put a bit of extra work on compliant readers, but interoperability with older mail readers was judged more important here ๐
It may be the case that some user agents, if they can recognize more than one format, will want to let the user pick which one to view. That totally makes sense if a mail has both a nicely formatted image version and an easy-to-edit text version ๐ The biggest thing, though, is that the user should NOT automatically be shown multiple copies of the same data. Like, either the user SHOULD be shown the last recognized version, or SHOULD explicitly get to choose ๐
7.2.4 The Multipart/digest subtype ๐
This document defines a "digest" subtype of the multipart Content-Type. It's syntactically identical to multipart/mixed, but the semantics are different. The big change is that in a digest, the default Content-Type for a body part switches from "text/plain" to "message/rfc822". That's on purpose, so the digest is more readable and still mostly compatible with RFC 934 (the only real difference is the quoting convention) ๐ธ
A digest in this format might look something like this:
From: Moderator-Address
MIME-Version: 1.0
Subject: Internet Digest, volume 42
Content-Type: multipart/digest;
boundary="---- next message ----"
------ next message ----
From: someone-else
Subject: my opinion
...body goes here ...
------ next message ----
From: someone-else-again
Subject: my different opinion
... another body goes here...
------ next message ------
7.2.5 The Multipart/parallel subtype โจ
This document also defines a "parallel" subtype of multipart. Same story: it's syntactically identical to multipart/mixed, but the semantics are different ๐ฆ In a parallel entity, all the parts are meant to be presented in parallel, meaning simultaneously, on hardware and software that can actually do that. Composing agents SHOULD be aware that lots of mail readers can't do this and will just show the parts one after another anyway ๐ซถ
7.3 The Message Content-Type ๐
Sending mail often means wrapping up another mail message inside yours, so there's a special Content-Type for that: "message" ๐ The primary subtype, message/rfc822, has no required parameters in its Content-Type field. The additional subtypes, "partial" and "External-body", DO have required parameters. Those subtypes get explained below ๐ง
NOTE: People have suggested making message subtypes for forwarded or rejected messages ๐ But forwarded and rejected messages can already be handled as multipart messages, where the first part holds any control or descriptive info, and a second part of type message/rfc822 holds the forwarded or rejected message. Composing rejections and forwards this way keeps the type info on the original message and lets it show up correctly for the recipient, so it's strongly encouraged ๐
As the Content-Transfer-Encoding field definition says, no encoding besides "7bit", "8bit", or "binary" is allowed for messages or parts of type "message" ๐ โโ๏ธ The message header fields are always US-ASCII no matter what, but the data inside the body can still be encoded, and if it is, the Content-Transfer-Encoding header field in the encapsulated message reflects that. Non-ASCII text in the headers of an encapsulated message can be specified using the mechanisms described in [RFC-1342] ๐
Mail gateways, relays, and other mail handling agents are notorious for messing with the top-level header of an RFC 822 message. They add, remove, and reorder header fields all the time ๐ญ Those changes are explicitly forbidden for the encapsulated headers inside the bodies of "message" type messages. Hands off!! ๐
7.3.1 The Message/rfc822 (primary) subtype ๐ฆ
A Content-Type of "message/rfc822" means the body contains an encapsulated message, using the syntax of an RFC 822 message ๐
7.3.2 The Message/Partial subtype ๐ง
The "partial" subtype of message exists so big objects can get delivered as several separate pieces of mail, then automatically reassembled by the receiving user agent ๐งฉ It's kind of like IP fragmentation and reassembly in the basic Internet Protocols. This comes in handy when intermediate transport agents limit how big each message can be. So a Content-Type of "message/partial" means the body holds a fragment of a larger message ๐
Three parameters MUST be specified in the Content-Type field of a message/partial. The first is "id", a unique identifier that's as close to world-unique as possible, used to match the parts together. (Usually the identifier is basically a message-id. If it's wrapped in double quotes, it can be any message-id, following the BNF for "parameter" given earlier in this specification.) The second is "number", an integer for the part number, which tells you where this piece fits in the sequence of fragments. The third is "total", another integer, giving the total number of parts. That third one is REQUIRED on the final part and OPTIONAL on the earlier parts. Also, these parameters MAY be given in any order ๐
So if part 2 of a 3-part message, you can use either of these header fields:
Content-Type: Message/Partial;
number=2; total=3;
id="oc=jpbe0M2Yt4s@thumper.bellcore.com";
Content-Type: Message/Partial;
id="oc=jpbe0M2Yt4s@thumper.bellcore.com";
number=2
But part 3 MUST specify the total number of parts:
Content-Type: Message/Partial;
number=3; total=3;
id="oc=jpbe0M2Yt4s@thumper.bellcore.com";
Quick reminder: part numbering starts at 1, not 0 ๐ข
When you put the parts of a message back together like this, the result is a complete RFC 822 format message. That message can have its own Content-Type header field, so it can contain any other data type at all โจ
Message fragmentation and reassembly: The semantics of a reassembled partial message MUST be those of the "inner" message, not of a message containing the inner message. So you could send a big audio message as several partial messages and it still shows up for the recipient as a simple audio message, not as an encapsulated message holding an audio message. The encapsulation is considered "transparent" ๐ง
When you're generating and reassembling the parts of a message/partial message, the headers of the encapsulated message MUST be merged with the headers of the enclosing entities. While doing that, these rules MUST be observed:
- All of the headers from the initial enclosing entity (part one), except those starting with "Content-" and "Message-ID", MUST be copied, in order, to the new message.
- Only the headers in the enclosed message that start with "Content-" and "Message-ID" MUST be appended, in order, to the headers of the new message. Any headers in the enclosed message that don't start with "Content-" (except for "Message-ID") will be ignored.
- All of the headers from the second and any subsequent messages will be ignored.
For example, if an audio message gets broken into two parts, the first part might look something like this:
X-Weird-Header-1: Foo
From: Bill@host.com
To: joe@otherhost.com
Subject: Audio mail
Message-ID: id1@host.com
MIME-Version: 1.0
Content-type: message/partial;
id="ABC@host.com";
number=1; total=2
X-Weird-Header-1: Bar
X-Weird-Header-2: Hello
Message-ID: anotherid@foo.com
Content-type: audio/basic
Content-transfer-encoding: base64
The second half of this audio example picks up next, bestie ๐ฆ
and the second half might look something like this:
... first half of encoded audio data goes here...
Okay bestie, the second piece is the one that finishes the audio, and it looks like this ๐ง
From: Bill@host.com
To: joe@otherhost.com
Subject: Audio mail
MIME-Version: 1.0
Message-ID: id2@host.com
Content-type: message/partial;
id="ABC@host.com"; number=2; total=2
... second half of encoded audio data goes here...
Then, once the fragmented message gets put back together, the message the user actually sees should look something like this ๐
X-Weird-Header-1: Foo
From: Bill@host.com
To: joe@otherhost.com
Subject: Audio mail
Message-ID: anotherid@foo.com
MIME-Version: 1.0
Content-type: audio/basic
Content-transfer-encoding: base64
... first half of encoded audio data goes here...
... second half of encoded audio data goes here...
โ ๏ธ Heads up: some message transfer agents automatically chop up big messages, and they don't all use the same chop size ๐ช So the pieces can end up being a partial message all over again once they're reassembled. This is explicitly permitted, so don't panic!
It's also worth knowing that putting a "References" field in the headers of the second and later pieces, pointing back at the Message-Id of the piece before, can help mail readers that understand and track references ๐งต Generating those "References" fields is totally optional though, so it's your call โจ
7.3.3. The Message/External-Body subtype
Okay this one is so cute ๐ฆ The external-body subtype says the actual body data is NOT in the message. It's just referenced, like a little pointer ๐ In this case the parameters describe how to go grab the external data.
When a message body or body part is of type "message/external-body", it has a header, then two consecutive CRLFs, then the message header for the encapsulated message. If another pair of consecutive CRLFs shows up, that ends the message header for the encapsulated message ๐ But since the encapsulated message's body is also external, it does not appear in the area that follows. Here's an example:
Content-type: message/external-body; access-
type=local-file;
name=/u/nsb/Me.gif
Content-type: image/gif
THIS IS NOT REALLY THE BODY!
That last area is called the "phantom body" ๐ป It gets ignored for most external-body messages. Honestly though, it can hold auxiliary information for some of them, and it does exactly that when the access-type is "mail-server" ๐ Out of the access-types defined in this document, the phantom body is only used for "mail-server". For every other case, it's ignored.
The only parameter that's always mandatory for message/external-body is "access-type" ๐ Everything else can be mandatory or optional depending on what the access-type is.
- ACCESS-TYPE -- One or more case-insensitive words, separated by commas, that tell you which access mechanisms can get the file or data. Values include, but aren't limited to,
FTP,ANON-FTP,TFTP,AFS,LOCAL-FILE, andMAIL-SERVER. Future values have to be registered with IANA, as described in Appendix F, except for experimental ones that start withX-๐ง
These two parameters are optional for ALL access-types, so no pressure ๐ธ
- EXPIRATION -- The date (in the RFC 822 "date-time" syntax, as extended by RFC 1123 to permit 4 digits in the date field) after which the existence of the external data is not guaranteed. It's giving "use it before it's gone" energy โณ
- SIZE -- The size (in octets) of the data. The point of this one is to help the recipient decide whether it's worth spending the resources to retrieve the external data ๐ง
- PERMISSION -- A field that shows whether clients are expected to possibly overwrite the data too. By default, or if permission is
read, the assumption is that they won't, and once the data is retrieved it's never needed again. If PERMISSION isread-write, that assumption is invalid, and any local copy has to be treated as nothing more than a cache ๐๏ธReadandRead-writeare the only defined values of permission.
The precise semantics of the access-types defined here are described in the sections that follow ๐
7.3.3.1. The "ftp" and "tftp" access-types
An access-type of FTP or TFTP means the message body is accessible as a file using the FTP [RFC-959] or TFTP [RFC-783] protocols, respectively ๐ For these access-types, the following additional parameters are mandatory:
- NAME -- The name of the file that holds the actual body data.
- SITE -- A machine the file can be obtained from, using the given protocol.
Before the data gets retrieved using these protocols, the user will usually need to be asked for a login id and a password for the machine named by the site parameter ๐
These optional parameters can also show up when the access-type is FTP or ANON-FTP:
- DIRECTORY -- A directory the data named by NAME should be retrieved from.
- MODE -- A transfer mode for retrieving the information, e.g.
"image"๐ผ๏ธ
7.3.3.2. The "anon-ftp" access-type
The "anon-ftp" access-type is identical to "ftp", except the user doesn't need to be asked for a name and password for the specified site ๐ Instead, the ftp protocol is used with login "anonymous" and a password that matches the user's email address ๐ง
7.3.3.3. The "local-file" and "afs" access-types
An access-type of "local-file" means the actual body is accessible as a file on the local machine ๐ An access-type of "afs" means the file is accessible through the global AFS file system ๐ In both cases, only one parameter is required:
- NAME -- The name of the file that holds the actual body data.
This optional parameter can describe the locality of reference for the data, meaning the site or sites where the file is expected to be visible ๐
- SITE -- A domain specifier for a machine or set of machines that are known to have access to the data file. You can use asterisks as wildcards for part of a domain name, like "*.bellcore.com", to mean a set of machines where the data should be directly visible ๐ A single asterisk means the file is expected to be universally available, like through a global file system ๐
7.3.3.4. The "mail-server" access-type
The "mail-server" access-type means the actual body is available from a mail server ๐ฌ The one mandatory parameter for this access-type is:
- SERVER -- The email address of the mail server the actual body data can be obtained from.
Mail servers accept a bunch of different syntaxes, and some of them are multiline ๐ So the full command that gets sent to a mail server isn't included as a parameter on the content-type line. Instead, it goes in the "phantom body" when the content-type is message/external-body and the access-type is mail-server โจ
MIME doesn't define a mail server syntax, btw. It just lets you include arbitrary mail server commands in the phantom body ๐ Implementations should include the phantom body in the body of the message they send to the mail server address to get the relevant data.
7.3.3.5. Examples and Further Explanations
With wide-area file systems becoming a thing, it gets really hard to know in advance which machines a file will and won't be directly accessible from ๐ญ So it can make sense to provide both a file name to try directly and the name of one or more sites where the file is known to be accessible ๐บ๏ธ An implementation can try to retrieve remote files using FTP or any other protocol, either with anonymous retrieval or by prompting the user for the necessary name and password ๐ If an external body is accessible through multiple mechanisms, the sender can include multiple parts of type message/external-body inside an entity of type multipart/alternative ๐งฉ
But the external-body mechanism isn't limited to file retrieval, and the mail-server access-type proves that ๐ You could also imagine, for example, using a video server for external references to video clips ๐ฌ
If an entity is of type message/external-body, then the body of the entity will contain the header fields of the encapsulated message ๐ฌ. The actual body lives in the external location ๐ฆ. So if the body of a message/external-body message has two consecutive CRLFs, everything after those pairs is NOT part of the message itself ๐ญ. For most message/external-body messages, this trailing area must simply be ignored. BUT it's a super convenient spot for extra data that can't fit in the content-type header field โจ. In particular, if access-type is mail-server, then the trailing area must contain commands to be sent to the mail server at the address NAME@SITE, where NAME and SITE are the values of the NAME and SITE parameters, respectively. ๐
The embedded message header fields in the body of the message/external-body data can be used to declare the Content-type of the external body ๐. So a complete message/external-body message, referring to a document in PostScript format, might look like this:
From: Whomever
Subject: whatever
MIME-Version: 1.0
Message-ID: id1@host.com
Content-Type: multipart/alternative; boundary=42
--42
Content-Type: message/external-body;
name="BodyFormats.ps";
site="thumper.bellcore.com";
access-type=ANON-FTP;
directory="pub";
mode="image";
expiration="Fri, 14 Jun 1991 19:13:14 -0400 (EDT)"
Content-type: application/postscript
--42
Content-Type: message/external-body;
name="/u/nsb/writing/rfcs/RFC-XXXX.ps";
site="thumper.bellcore.com";
access-type=AFS
expiration="Fri, 14 Jun 1991 19:13:14 -0400 (EDT)"
Content-type: application/postscript
--42
Content-Type: message/external-body;
access-type=mail-server
server="listserv@bogus.bitnet";
expiration="Fri, 14 Jun 1991 19:13:14 -0400 (EDT)"
Content-type: application/postscript
get rfc-xxxx doc
--42--
Like the message/partial type, the message/external-body type is intended to be transparent ๐ฆ. That means it conveys the data type in the external body, rather than conveying a message with a body of that type. So the headers on the outer and inner parts must be merged using the same rules as for message/partial. In particular, the Content-type header is overridden, but the From and Subject headers are preserved ๐.
Note that since the external bodies are not transported as mail, they need not conform to the 7-bit and line length requirements, and they might in fact be binary files ๐ค. So a Content-Transfer-Encoding is not generally necessary, though it is permitted โจ.
Note that the body of a message of type message/external-body is governed by the basic syntax for an RFC 822 message ๐. Anything before the first consecutive pair of CRLFs is header information, while anything after it is body information, which is ignored for most access-types ๐.
7.4 The Application Content-Type ๐
The "application" Content-Type is for data that don't fit in any of the other categories, and especially for data to be processed by mail-based uses of application programs ๐ฅ. This is information which must be processed by an application before it is viewable or usable to a user. Expected uses for Content-Type application include mail-based file transfer, spreadsheets, data for mail-based scheduling systems, and languages for "active" (computational) email ๐ง. (The latter, in particular, can pose security problems which should be understood by implementors, and are considered in detail in the discussion of the application/PostScript content-type ๐.)
For example, a meeting scheduler might define a standard representation for information about proposed meeting dates ๐ . An intelligent user agent would use this information to hold a dialog with the user, and might then send further mail based on that dialog ๐ฌ. More generally, several "active" messaging languages have been developed, in which programs written in a suitably specialized language are sent through the mail and automatically run in the recipient's environment ๐.
Such applications may be defined as subtypes of the "application" Content-Type. This document defines three subtypes: octet-stream, ODA, and PostScript ๐.
In general, the subtype of application will often be the name of the application for which the data are intended ๐ธ. This does not mean, however, that any application program name may be used freely as a subtype of application. Such usages must be registered with IANA, as described in Appendix F ๐.
7.4.1 The Application/Octet-Stream (primary) subtype ๐ซถ
The primary subtype of application, "octet-stream", may be used to indicate that a body contains binary data ๐. The set of possible parameters includes, but is not limited to:
NAME: a suggested name for the binary data if stored as a file.TYPE: the general type or category of binary data. This is intended as information for the human recipient rather than for any automatic processing.CONVERSIONS: the set of operations that have been performed on the data before putting it in the mail (and before any Content-Transfer-Encoding that might have been applied). If multiple conversions have occurred, they must be separated by commas and specified in the order they were applied. That is, the leftmost conversion must have occurred first, and conversions are undone from right to left. Note that NO conversion values are defined by this document. Any conversion values that that do not begin with "X-" must be preceded by a published specification and by registration with IANA, as described in Appendix F.PADDING: the number of bits of padding that were appended to the bitstream comprising the actual contents to produce the enclosed byte-oriented data. This is useful for enclosing a bitstream in a body when the total number of bits is not a multiple of the byte size.
The values for these attributes are left undefined at present, but may require specification in the future ๐ฎ. An example of a common (though UNIX-specific) usage might be:
Content-Type: application/octet-stream;
name=foo.tar.Z; type=tar;
conversions="x-encrypt,x-compress"
However, it should be noted that the use of such conversions is explicitly discouraged due to a lack of portability and standardization ๐ โโ๏ธ. The use of uuencode is particularly discouraged, in favor of the Content-Transfer-Encoding mechanism, which is both more standardized and more portable across mail boundaries ๐ฆ.
The recommended action for an implementation that receives application/octet-stream mail is to simply offer to put the data in a file, with any Content-Transfer-Encoding undone, or perhaps to use it as input to a user-specified process ๐พ.
To reduce the danger of transmitting rogue programs through the mail, it is strongly recommended that implementations NOT implement a path-search mechanism whereby an arbitrary program named in the Content-Type parameter (e.g., an "interpreter=" parameter) is found and executed using the mail body as input. ๐จ
7.4.2 The Application/PostScript subtype ๐จ๏ธ
A Content-Type of "application/postscript" indicates a PostScript program ๐. The language is defined in [POSTSCRIPT]. It is recommended that PostScript sent through email should use PostScript document structuring conventions if at all possible, and correctly ๐.
The execution of general-purpose PostScript interpreters entails serious security risks, so implementors are discouraged from simply sending PostScript email bodies to "off-the-shelf" interpreters ๐ฌ. While it is usually safe to send PostScript to a printer, where the potential for harm is greatly constrained, implementors should consider all of the following before they add interactive display of PostScript bodies to their mail readers ๐.
The remainder of this section outlines some, though probably not all, of the possible problems with sending PostScript through the mail ๐.
7.4.2. Security considerations (cont.) ๐
okay so the scary part of PostScript is the dangerous operators ๐ The big ones are deletefile, renamefile, filenameforall, and file. file is only dangerous when it's aimed at something other than standard input or output. Implementations can also make their own nonstandard file operators, and those can be a threat to security too ๐ญ
filenameforall is the sneaky one. It's the wildcard file search, so it looks totally harmless, but it can reveal which files the recipient has access to, and that info might be sensitive itself ๐ Message senders should avoid potentially dangerous file operators, because they're quite likely to be unavailable in secure PostScript implementations anyway. Message-receiving and -displaying software should either completely disable all potentially dangerous file operators, or take special care not to hand any special authority to their operation. Treat these operators like they're being run by an outside agency when interpreting PostScript documents ๐ต๏ธโโ๏ธ That disabling and/or checking should happen completely outside the reach of the PostScript language itself, and you need to make sure there's no way to re-enable full-function versions of these operators. No sneaking them back in ๐
โโ๏ธ
PostScript also lets you exit the normal interpreter loop (or server loop). Changes made in this "outer" environment are usually kept across documents, and some may even stick around semipermanently in nonvolatile memory. So the operators that exit the loop can seriously mess with later document processing, and unrestrained use is a threat of service denial ๐ค The operators that exit the interpreter loop include, but aren't limited to, exitserver and startjob. Message-sending software should not generate PostScript that depends on exiting the loop to work. The ability to exit will probably be unavailable in secure PostScript implementations. Message-receiving and -displaying software should, if possible, disable the ability to make retained changes to the PostScript environment. Eliminate the startjob and exitserver commands ๐ซ
If those commands can't be eliminated, at least set the password tied to them to a hard-to-guess value ๐
PostScript has operators for setting system-wide and device-specific parameters ๐๏ธ These settings can be kept across jobs and could potentially mess with the correct operation of the interpreter. The operators that set system and device parameters include, but aren't limited to, setsystemparams and setdevparams. Message-sending software should not generate PostScript that depends on the setting of system or device parameters to work correctly. The ability to set these parameters will probably be unavailable in secure PostScript implementations. Message-receiving and -displaying software should, if possible, disable the ability to change system and device parameters. If these operators can't be disabled, at least set the password associated with them to a hard-to-guess value ๐
Some PostScript implementations have nonstandard facilities for directly loading and running machine code ๐ค Those are obviously wide open to serious abuse. Message-sending software should not make use of such features. Besides being totally hardware-specific, they're also likely to be unavailable in secure implementations of PostScript. Message-receiving and -displaying software should not allow such operators to be used if they exist ๐ท
PostScript is an extensible language, and most implementations come with a bunch of their own extensions ๐งฉ This document doesn't deal with those extensions explicitly, since they're an unknown factor. Message-sending software should not use nonstandard extensions, because they're likely to be missing from some implementations. Message-receiving and -displaying software should make sure that any nonstandard PostScript operators are secure and don't pose any kind of threat ๐ก๏ธ
It's possible to write PostScript that eats up huge amounts of system resources ๐ It's also possible to write PostScript programs that loop forever โพ๏ธ Both kinds have the potential to cause damage when sent to unsuspecting recipients. Message-sending software should avoid building and spreading such programs, which is antisocial ๐ โโ๏ธ Message-receiving and -displaying software should provide appropriate mechanisms to abort processing of a document after a reasonable amount of time has passed โฑ๏ธ On top of that, PostScript interpreters should be limited to using only a reasonable amount of any given system resource.
Last but not least, bugs may exist in some PostScript interpreters that could be exploited to gain unauthorized access to a recipient's system ๐ฑ Apart from noting that this is possible, there's no specific action to take to prevent it, other than the timely correction of any such bugs that are found ๐
7.4.3. The Application/ODA subtype ๐
The "ODA" subtype of application is used to say that a body contains information encoded according to the Office Document Architecture [ODA] standards, using the ODIF representation format โจ For application/oda, the Content-Type line should also specify an attribute/value pair that indicates the document application profile (DAP), using the key word "profile". So an appropriate header field might look like this:
Content-Type: application/oda; profile=Q112
Check the ODA standard [ODA] for more info ๐ค
7.5. The Image Content-Type ๐ผ๏ธ
A Content-Type of "image" says that the body contains an image. The subtype names the specific image format, and these names are case insensitive ๐ Two initial subtypes are "jpeg" for the JPEG format, JFIF encoding, and "gif" for GIF format [GIF] ๐
The list of image subtypes given here is neither exclusive nor exhaustive. It's expected to grow as more types get registered with IANA, as described in Appendix F ๐
7.6. The Audio Content-Type ๐ง
A Content-Type of "audio" says that the body contains audio data ๐ถ There isn't a consensus yet on an "ideal" audio format for computers, but there's a pressing need for a format that can give interoperable behavior ๐ซถ
The initial subtype "basic" is specified to meet this need by providing an absolutely minimal, lowest common denominator audio format ๐ Richer formats for higher quality and/or lower bandwidth audio are expected to be defined by a later document ๐ฎ
The content of the "audio/basic" subtype is audio encoded using 8-bit ISDN u-law [PCM]. When this subtype is present, a sample rate of 8000 Hz and a single channel are assumed ๐๏ธ
7.7. The Video Content-Type ๐ฌ
A Content-Type of "video" says that the body contains a time-varying-picture image, possibly with color and coordinated sound ๐ฟ The term "video" is used super generically, rather than referring to any particular technology or format. It's not meant to rule out subtypes like animated drawings encoded compactly ๐จ The subtype "mpeg" refers to video coded according to the MPEG standard [MPEG] ๐๏ธ
Now, this document strongly discourages mixing multiple media in a single body ๐ โโ๏ธ BUT it's recognized that lots of so-called "video" formats include a representation for synchronized audio, and that is explicitly permitted for subtypes of "video" ๐ฅฐ
7.8. Experimental Content-Type Values ๐งช
A Content-Type value starting with the characters "X-" is a private value, meant for consenting mail systems to use by mutual agreement ๐ค Any format without a rigorous and public definition must be named with an "X-" prefix, and publicly specified values shall never begin with "X-". (Older versions of the widely-used Andrew system use the X-BE2 name, so new systems should probably pick a different name ๐)
In general, using "X-" top-level types is strongly discouraged ๐ซ Implementors should invent subtypes of the existing types whenever possible ๐ก Inventing new types is meant to be restricted mainly to developing new media types for email, like digital odors or holography ๐๐ฌ, and not for new data formats in general. In many cases, a subtype of application will be more appropriate than a new top-level type ๐
The Summary above is the same content the Abstract covered, so I'm picking up right where that left off. ๐
Using the MIME-Version, Content-Type, and Content-Transfer-Encoding header fields, you can include arbitrary types of data objects in a standardized way with RFC 822 conformant mail messages ๐ฌโจ No restrictions from RFC 821 or RFC 822 get broken, and care has been taken to avoid problems from the extra limits some Internet mail transport mechanisms have (see Appendix B) ๐ซถ The "multipart" and "message" Content-Types let you mix and nest objects of different types in one single message ๐งฉ Further Content-Types give you a standardized way to tag messages or body parts as audio, image, or several other kinds of data ๐ต๐ผ๏ธ A distinguished parameter syntax lets you specify data format details, especially alternate character sets ๐ Additional optional header fields offer extensions that lots of implementors find desirable ๐
Finally, a bunch of useful Content-Types are defined for general use by consenting user agents, notably text/richtext, message/partial, and message/external-body ๐ฆ
Acknowledgements ๐ซถ
This document is the result of a huge group effort from loads of people, across several IETF meetings, on the IETF-SMTP and IETF-822 mailing lists, and elsewhere ๐ธ Any list of names is basically doomed to have embarrassing gaps, but here are some of the amazing contributors who helped make this happen ๐
Harald Tveit Alvestrand Timo Lehtinen
Randall Atkinson John R. MacMillan
Philippe Brandon Rick McGowan
Kevin Carosso Leo Mclaughlin
Uhhyung Choi Goli Montaser-Kohsari
Cristian Constantinof Keith Moore
Mark Crispin Tom Moore
Dave Crocker Erik Naggum
Terry Crowley Mark Needleman
Walt Daniels John Noerenberg
Frank Dawson Mats Ohrman
Hitoshi Doi Julian Onions
Kevin Donnelly Michael Patton
Keith Edwards David J. Pepper
Chris Eich Blake C. Ramsdell
Johnny Eriksson Luc Rooijakkers
Craig Everhart Marshall T. Rose
Patrik Faeltstroem Jonathan Rosenberg
Erik E. Fair Jan Rynning
Roger Fajman Harri Salminen
Alain Fontaine Michael Sanderson
James M. Galvin Masahiro Sekiguchi
Philip Gladstone Mark Sherman
Thomas Gordon Keld Simonsen
Phill Gross Bob Smart
James Hamilton Peter Speck
Steve Hardcastle-Kille Henry Spencer
David Herron Einar Stefferud
Bruce Howard Michael Stein
Bill Janssen Klaus Steinberger
Olle Jaernefors Peter Svanberg
Risto Kankkunen James Thompson
Phil Karn Steve Uhler
Alan Katz Stuart Vance
Tim Kehres Erik van der Poel
Neil Katin Guido van Rossum
Kyuho Kim Peter Vanderbilt
Anders Klemets Greg Vaudreuil
John Klensin Ed Vielmetti
Valdis Kletniek Ryan Waldron
Jim Knowles Wally Wedel
Stev Knowles Sven-Ove Westberg
Bob Kummerfeld Brian Wideen
Pekka Kytolaakso John Wobus
Stellan Lagerstr.m Glenn Wright
Vincent Lau Rayan Zachariassen
Donald Lindsay David Zimmerman
The authors apologize for any omissions from this list, which are certainly unintentional ๐
Appendix A -- Minimal MIME-Conformance ๐
The mechanisms in this document are open-ended ๐ It is definitely not expected that every implementation will support all of the Content-Types described, or that they'll all share the same extensions ๐ To promote interoperability, though, it's useful to define the concept of "MIME-conformance", which sets a certain level of implementation that allows useful interworking of messages with content that differs from US ASCII text โจ In this section, we specify the requirements for that conformance ๐
A mail user agent that is MIME-conformant MUST:
- Always generate a
MIME-Version: 1.0header field. ๐ฆ - Recognize the
Content-Transfer-Encodingheader field, and decode all received data encoded with either the quoted-printable or base64 implementations. Encode any data sent that is not in seven-bit mail-ready representation using one of these transformations and include the appropriateContent-Transfer-Encodingheader field, unless the underlying transport mechanism supports non-seven-bit data, as SMTP does not. ๐ฆ - Recognize and interpret the
Content-Typeheader field, and avoid showing users raw data with aContent-Typefield other than text. Be able to send at leasttext/plainmessages, with the character set specified as a parameter if it is not US-ASCII. ๐ - Explicitly handle the following Content-Type values, to at least the following extents: ๐ซง
- Text:
- Recognize and display "text" mail with the character set "US-ASCII."
- Recognize other character sets at least to the extent of being able to inform the user about what character set the message uses.
- Recognize the "ISO-8859-" character sets to the extent of being able to display those characters that are common to ISO-8859- and US-ASCII, namely all characters represented by octet values 0-127.
- For unrecognized subtypes, show or offer to show the user the "raw" version of the data. An ability at least to convert "text/richtext" to plain text, as shown in Appendix D, is encouraged, but not required for conformance.
- Message:
- Recognize and display at least the primary (822) encapsulation.
- Multipart:
- Recognize the primary (mixed) subtype. Display all relevant information on the message level and the body part header level and then display or offer to display each of the body parts individually.
- Recognize the "alternative" subtype, and avoid showing the user redundant parts of multipart/alternative mail.
- Treat any unrecognized subtypes as if they were "mixed".
- Application:
- Offer the ability to remove either of the two types of Content-Transfer-Encoding defined in this document and put the resulting information in a user file.
- Text:
- Upon encountering any unrecognized Content-Type, an implementation must treat it as if it had a Content-Type of "application/octet-stream" with no parameter sub-arguments. How such data are handled is up to an implementation, but likely options for handling such unrecognized data include offering the user to write it into a file (decoded from its mail transport format) or offering the user to name a program to which the decoded data should be passed as input. Unrecognized predefined types, which in a MIME-conformant mailer might still include audio, image, or video, should also be treated in this way. ๐ต๏ธโโ๏ธ
A user agent that meets the above conditions is said to be MIME-conformant ๐ The meaning of this phrase is that it is assumed to be "safe" to send virtually any kind of properly-marked data to users of such mail systems, because such systems will at least be able to treat the data as undifferentiated binary, and will not simply splash it onto the screen of unsuspecting users ๐ There is another sense in which it is always "safe" to send data in a MIME-conformant format, which is that such data will not break or be broken by any known systems that are conformant with RFC 821 and RFC 822 ๐ง User agents that are MIME-conformant have the additional guarantee that the user will not be shown data that were never intended to be viewed as text ๐
Appendix B -- General Guidelines For Sending Email Data ๐
Okay bestie, internet email is NOT a perfect, uniform system ๐ญ A message can get corrupted at several stages on its way to the final destination. It can travel across loads of different networking technologies, and lots of those networking and mail technologies don't support everything SMTP can do. So mail that goes through them is likely to get changed so it can be transported at all ๐ซ
There are also tons of widely deployed non-conformant MTAs out there. These speak SMTP, but they alter messages on the fly to take advantage of the internal data structures of the hosts they run on, or they're just plain broken ๐
So if you're designing a data format (Content-Type) and you want it to survive the widest range of networking technologies and known broken MTAs unscathed, these guidelines are your bestie โจ Anything encoded in base64 will satisfy these rules, but the UNIX uuencode facility won't, so don't use it. Quoted-printable encoding will survive most gateways intact, though it might not survive some gateways to systems that use the EBCDIC character set.
(1) Under some circumstances, the encoding used for data may change as part of normal gateway or user agent operation. In particular, converting from base64 to quoted-printable and back may be necessary. This can cause CRLF sequences to get confused with line breaks in text body parts. So the persistence of CRLF as something other than a line break should not be relied on ๐
(2) Lots of systems represent and store text data using local newline conventions, and those may not match the RFC822 CRLF convention. Some systems use plain CR, some use plain LF, some use CRLF, and some use counted records. The result is that isolated CR and LF characters aren't well tolerated in general. They may get lost or turned into delimiters on some systems, so they should not be relied on ๐ธ
(3) TAB (HT) characters may be misinterpreted or automatically converted into variable numbers of spaces. This is unavoidable in some environments, especially ones not based on the ASCII character set. This conversion is STRONGLY DISCOURAGED, but it may still happen, so mail formats should not rely on TAB (HT) characters persisting ๐ฆ
(4) Lines longer than 76 characters may be wrapped or truncated in some environments. Line wrapping and line truncation are STRONGLY DISCOURAGED, but in some cases they're unavoidable. Applications that need long lines should somehow tell soft line breaks apart from hard ones. (A simple way to do this is to use quoted-printable encoding ๐)
(5) Trailing "white space" characters (SPACE, TAB (HT)) on a line may be discarded by some transport agents, while other transport agents may pad lines with these characters so that every line in a mail file is the same length. So the persistence of trailing white space should not be relied on ๐
(6) Lots of mail domains use variations on the ASCII character set, or use character sets like EBCDIC that contain most but not all of the US-ASCII characters. The correct translation of characters outside the "invariant" set can't be depended on across character converting gateways. For example, this is a problem when sending uuencoded information across BITNET, which is an EBCDIC system. Similar problems can happen without crossing a gateway, since many Internet hosts use character sets other than ASCII internally. The definition of Printable Strings in X.400 adds further restrictions in certain special cases. In particular, the only characters known to be consistent across all gateways are the 73 characters that correspond to the upper and lower case letters A-Z and a-z, the 10 digits 0-9, and the following eleven special characters:
"'" (ASCII code 39)
"(" (ASCII code 40)
")" (ASCII code 41)
"+" (ASCII code 43)
"," (ASCII code 44)
"-" (ASCII code 45)
"." (ASCII code 46)
"/" (ASCII code 47)
":" (ASCII code 58)
"=" (ASCII code 61)
"?" (ASCII code 63)
A maximally portable mail representation, like the base64 encoding, will stick to relatively short lines of text where the only meaningful characters come from this set of 73 characters ๐ง
Please note that the above list is NOT a list of recommended practices for MTAs. RFC 821 MTAs are prohibited from altering the character of white space or wrapping long lines. These BAD and illegal practices are known to occur on established networks, so implementions should be robust in dealing with the bad effects they can cause ๐จ
Appendix C -- A Complex Multipart Example ๐งฉ
Okay so this is the outline of a complex multipart message, and it's giving full main character energy ๐ It has five parts to be displayed serially: two introductory plain text parts, an embedded multipart message, a richtext part, and a closing encapsulated text message in a non-ASCII character set. The embedded multipart message has two parts to be displayed in parallel, a picture and an audio fragment ๐ฆ
MIME-Version: 1.0
From: Nathaniel Borenstein <nsb@bellcore.com>
Subject: A multipart example
Content-Type: multipart/mixed;
boundary=unique-boundary-1
This is the preamble area of a multipart message.
Mail readers that understand multipart format
should ignore this preamble.
If you are reading this text, you might want to
consider changing to a mail reader that understands
how to properly display multipart messages.
--unique-boundary-1
...Some text appears here...
[Note that the preceding blank line means
no header fields were given and this is text,
with charset US ASCII. It could have been
done with explicit typing as in the next part.]
--unique-boundary-1
Content-type: text/plain; charset=US-ASCII
This could have been part of the previous part,
but illustrates explicit versus implicit
typing of body parts.
--unique-boundary-1
Content-Type: multipart/parallel;
boundary=unique-boundary-2
--unique-boundary-2
Content-Type: audio/basic
Content-Transfer-Encoding: base64
... base64-encoded 8000 Hz single-channel
u-law-format audio data goes here....
--unique-boundary-2
Content-Type: image/gif
Content-Transfer-Encoding: Base64
... base64-encoded image data goes here....
--unique-boundary-2--
--unique-boundary-1
Content-type: text/richtext
This is <bold><italic>richtext.</italic></bold>
<nl><nl>Isn't it
<bigger><bigger>cool?</bigger></bigger>
--unique-boundary-1
Content-Type: message/rfc822
From: (name in US-ASCII)
Subject: (subject in US-ASCII)
Content-Type: Text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: Quoted-printable
... Additional text in ISO-8859-1 goes here ...
--unique-boundary-1--
Appendix D -- A Simple Richtext-to-Text Translator in C โจ
okay so one of the big goals behind the richtext subtype of text was making formatted text so simple that even text-only mailers would bother writing richtext-to-plain-text translators ๐ that way multifont text is way more likely to become "safe" to send everywhere ๐ to prove how simple it is, here's an extremely tiny 44-line C program that turns richtext input into plain text output ๐
#include <stdio.h>
#include <ctype.h>
main() {
int c, i;
char token[50];
while((c = getc(stdin)) != EOF) {
if (c == '<') {
for (i=0; (i<49 && (c = getc(stdin)) != '>'
&& c != EOF); ++i) {
token[i] = isupper(c) ? tolower(c) : c;
}
if (c == EOF) break;
if (c != '>') while ((c = getc(stdin)) !=
'>'
&& c != EOF) {;}
if (c == EOF) break;
token[i] = '\0';
if (!strcmp(token, "lt")) {
putc('<', stdout);
} else if (!strcmp(token, "nl")) {
putc('\n', stdout);
} else if (!strcmp(token, "/paragraph")) {
fputs("\n\n", stdout);
} else if (!strcmp(token, "comment")) {
int commct=1;
while (commct > 0) {
while ((c = getc(stdin)) != '<'
&& c != EOF) ;
if (c == EOF) break;
for (i=0; (c = getc(stdin)) != '>'
&& c != EOF; ++i) {
token[i] = isupper(c) ?
tolower(c) : c;
}
if (c== EOF) break;
token[i] = NULL;
if (!strcmp(token, "/comment")) --
commct;
if (!strcmp(token, "comment"))
++commct;
}
} /* Ignore all other tokens */
} else if (c != '\n') putc(c, stdout);
}
putc('\n', stdout); /* for good measure */
}
ngl you can do WAY better than this when showing richtext on a dumb terminal ๐ฅ๏ธ๐ for example, you can swap font stuff like "bold" for textual emphasis, like *this* or _T_H_I_S_ ๐ you can also properly handle the richtext formatting commands for indentation, justification, and other stuff too ๐ฆ but honestly? the program above is all that's needed to show richtext on a dumb terminal ๐
โจ
Appendix E -- Collected Grammar ๐ง
this appendix has the complete BNF grammar for all the syntax in this document ๐
BUT (and it's a big but) the grammar on its own is incomplete ๐ญ it refers to a bunch of entities defined in RFC 822. instead of copying those definitions here and risking them drifting apart, this document just points you to RFC 822 for the rest. anywhere a term is undefined here, it means the RFC 822 definition ๐ซถ
attribute := token
body-part = <"message" as defined in RFC 822,
with all header fields optional, and with the
specified delimiter not occurring anywhere in
the message body, either on a line by itself
or as a substring anywhere.>
boundary := 0*69<bchars> bcharsnospace
bchars := bcharsnospace / " "
bcharsnospace := DIGIT / ALPHA / "'" / "(" / ")" / "+" /
"_"
/ "," / "-" / "." / "/" / ":" / "=" / "?"
close-delimiter := delimiter "--"
Content-Description := *text
Content-ID := msg-id
Content-Transfer-Encoding := "BASE64" / "QUOTED-
PRINTABLE" /
"8BIT" / "7BIT" /
"BINARY" / x-token
Content-Type := type "/" subtype *[";" parameter]
delimiter := CRLF "--" boundary ; taken from Content-Type
field.
; when content-type is
multipart
; There should be no space
; between "--" and boundary.
encapsulation := delimiter CRLF body-part
epilogue := *text ; to be ignored upon
receipt.
MIME-Version := 1*text
multipart-body := preamble 1*encapsulation close-delimiter
epilogue
parameter := attribute "=" value
preamble := *text ; to be ignored upon
receipt.
subtype := token
token := 1*<any CHAR except SPACE, CTLs, or tspecials>
tspecials := "(" / ")" / "<" / ">" / "@" ; Must be in
/ "," / ";" / ":" / "\" / <"> ; quoted-string,
/ "/" / "[" / "]" / "?" / "." ; to use within
/ "=" ; parameter values
type := "application" / "audio" ; case-
insensitive
/ "image" / "message"
/ "multipart" / "text"
/ "video" / x-token
value := token / quoted-string
x-token := <The two characters "X-" followed, with no
intervening white space, by any token>
Appendix F -- IANA Registration Procedures ๐ธ
okay so MIME was designed to have extensible mechanisms, and the set of content-type/subtype pairs and their parameters is expected to grow a LOT over time ๐ other MIME fields are also gonna get new values eventually: character set names, access-type parameters for the message/external-body type, conversions parameters for the application type, and possibly even Content-Transfer-Encoding values ๐ฆ so to keep all of that orderly, well-specified, and public, MIME sets up a registration process that uses the Internet Assigned Numbers Authority (IANA) as a central registry ๐
in general, parameters in the content-type header field are used to pass along supplemental info for various content types, and how they're used gets defined when the content-type and subtype get defined. new parameters should not be defined as a way to introduce new functionality ๐
to make registration simpler and more standardized, this appendix gives templates for registering new values with IANA. each one is an email message template for the registering party to fill in ๐
F.1 Registration of New Content-type/subtype Values
note that MIME is generally expected to be extended by subtypes ๐ if a new fundamental top-level type is needed, its specification should be published as an RFC or submitted in a form suitable to become an RFC, and be subject to the Internet standards process ๐
To: IANA@isi.edu
Subject: Registration of new MIME content-type/subtype
MIME type name:
(If the above is not an existing top-level MIME type,
please explain why an existing type cannot be used.)
MIME subtype name:
Required parameters:
Optional parameters:
Encoding considerations:
Security considerations:
Published specification:
(The published specification must be an Internet RFC or
RFC-to-be if a new top-level type is being defined, and
must be a publicly available specification in any
case.)
Person & email address to contact for further
information:
F.2 Registration of New Character Set Values
To: IANA@isi.edu
Subject: Registration of new MIME character set value
MIME character set name:
Published specification:
(The published specification must be an Internet RFC or
RFC-to-be or an international standard.)
Person & email address to contact for further
information:
F.3 Registration of New Access-type Values for Message/external-body
To: IANA@isi.edu
Subject: Registration of new MIME Access-type for
Message/external-body content-type
MIME access-type name:
Required parameters:
Optional parameters:
Published specification:
(The published specification must be an Internet RFC or
RFC-to-be.)
Person & email address to contact for further
information:
F.4 Registration of New Conversions Values for Application
To: IANA@isi.edu
Subject: Registration of new MIME Conversions value
for Application content-type
MIME Conversions name:
Published specification:
(The published specification must be an Internet RFC or
RFC-to-be.)
Person & email address to contact for further
information:
Appendix G -- Summary of the Seven Content-types โจ
okay bestie, this is the cheat sheet ๐๐ seven content-types, one little card each, with the subtypes, important parameters, encoding notes, and any security warnings. Read the warnings extra carefully ๐
Content-type: text ๐
- Subtypes defined by this document: plain, richtext
- Important Parameters: charset
- Encoding notes: quoted-printable generally preferred if an encoding is needed and the character set is mostly an ASCII superset.
Security considerations: Rich text formats such as TeX and Troff often contain mechanisms for executing arbitrary commands or file system operations, and should not be used automatically unless these security problems have been addressed. Even plain text may contain control characters that can be used to exploit the capabilities of "intelligent" terminals and cause security violations. User interfaces designed to run on such terminals should be aware of and try to prevent such problems. ๐
Content-type: multipart ๐ง
- Subtypes defined by this document: mixed, alternative, digest, parallel.
- Important Parameters: boundary
- Encoding notes: No content-transfer-encoding is permitted.
Content-type: message ๐
- Subtypes defined by this document: rfc822, partial, external-body
- Important Parameters: id, number, total
- Encoding notes: No content-transfer-encoding is permitted.
Content-type: application ๐ฅ
- Subtypes defined by this document: octet-stream, postscript, oda
- Important Parameters: profile
- Encoding notes: base64 generally preferred for octet-stream or other unreadable subtypes.
Security considerations: This type is intended for the transmission of data to be interpreted by locally-installed programs. If used, for example, to transmit executable binary programs or programs in general-purpose interpreted languages, such as LISP programs or shell scripts, severe security problems could result. In general, authors of mail-reading agents are cautioned against giving their systems the power to execute mail-based application data without carefully considering the security implications. While it is certainly possible to define safe application formats and even safe interpreters for unsafe formats, each interpreter should be evaluated separately for possible security problems. ๐ญ
Content-type: image ๐ธ
- Subtypes defined by this document: jpeg, gif
- Important Parameters: none
- Encoding notes: base64 generally preferred
Content-type: audio ๐ง
- Subtypes defined by this document: basic
- Important Parameters: none
- Encoding notes: base64 generally preferred
Content-type: video ๐ฆ
- Subtypes defined by this document: mpeg
- Important Parameters: none
- Encoding notes: base64 generally preferred
Appendix H -- Canonical Encoding Model ๐งผ
okay so this part is about the order of operations when you build a MIME body part, and why CRLFs were causing drama ๐ค earlier drafts were confusing about when email data gets converted to canonical form and encoded, and how that affects CRLF handling, since every system writes newlines a little differently. so here's a canonical model, lowkey the official timeline โจ
The process of composing a MIME message part can be modelled as being done in a number of steps. Note that these steps are roughly similar to those steps used in RFC1113:
Step 1. Creation of local form. ๐ก
The body part to be transmitted is created in the system's native format. The native character set is used, and where appropriate local end of line conventions are used as well. The may be a UNIX-style text file, or a Sun raster image, or a VMS indexed file, or audio data in a system-dependent format stored only in memory, or anything else that corresponds to the local model for the representation of some form of information.
Step 2. Conversion to canonical form. ๐
The entire body part, including "out-of-band" information such as record lengths and possibly file attribute information, is converted to a universal canonical form. The specific content type of the body part as well as its associated attributes dictate the nature of the canonical form that is used. Conversion to the proper canonical form may involve character set conversion, transformation of audio data, compression, or various other operations specific to the various content types.
For example, in the case of text/plain data, the text must be converted to a supported character set and lines must be delimited with CRLF delimiters in accordance with RFC822. Note that the restriction on line lengths implied by RFC822 is eliminated if the next step employs either quoted-printable or base64 encoding.
Step 3. Apply transfer encoding. ๐
A Content-Transfer-Encoding appropriate for this body part is applied. Note that there is no fixed relationship between the content type and the transfer encoding. In particular, it may be appropriate to base the choice of base64 or quoted-printable on character frequency counts which are specific to a given instance of body part.
Step 4. Insertion into message. ๐
The encoded object is inserted into a MIME message with appropriate body part headers and boundary markers.
It is vital to note that these steps are only a model; they are specifically not a blueprint for how an actual system would be built. In particular, the model fails to account for two common designs:
- In many cases the conversion to a canonical form prior to encoding will be subsumed into the encoder itself, which understands local formats directly. For example, the local newline convention for text bodyparts might be carried through to the encoder itself along with knowledge of what that format is.
- The output of the encoders may have to pass through one or more additional steps prior to being transmitted as a message. As such, the output of the encoder may not be compliant with the formats specified by RFC822. In particular, once again it may be appropriate for the converter's output to be expressed using local newline conventions rather than using the standard RFC822 CRLF delimiters.
Other implementation variations are conceivable as well. The only important aspect of this discussion is that the resulting messages are consistent with those produced by the model described here. ๐ฆโจ
References โจ
okay bestie, here's the full reading list ๐ every single source the spec leans on, with all the details, no cuts ๐
- [US-ASCII] Coded Character Set--7-Bit American Standard Code for Information Interchange, ANSI X3.4-1986.
- [ATK] Borenstein, Nathaniel S., Multimedia Applications Development with the Andrew Toolkit, Prentice-Hall, 1990.
- [GIF] Graphics Interchange Format (Version 89a), Compuserve, Inc., Columbus, Ohio, 1990.
- [ISO-2022] International Standard--Information Processing--ISO 7-bit and 8-bit coded character sets--Code extension techniques, ISO 2022:1986.
- [ISO-8859] Information Processing -- 8-bit Single-Byte Coded Graphic Character Sets -- Part 1: Latin Alphabet No. 1, ISO 8859-1:1987. Part 2: Latin alphabet No. 2, ISO 8859-2, 1987. Part 3: Latin alphabet No. 3, ISO 8859-3, 1988. Part 4: Latin alphabet No. 4, ISO 8859-4, 1988. Part 5: Latin/Cyrillic alphabet, ISO 8859-5, 1988. Part 6: Latin/Arabic alphabet, ISO 8859-6, 1987. Part 7: Latin/Greek alphabet, ISO 8859-7, 1987. Part 8: Latin/Hebrew alphabet, ISO 8859-8, 1988. Part 9: Latin alphabet No. 5, ISO 8859-9, 1990.
- [ISO-646] International Standard--Information Processing--ISO 7-bit coded character set for information interchange, ISO 646:1983.
- [MPEG] Video Coding Draft Standard ISO 11172 CD, ISO IEC/TJC1/SC2/WG11 (Motion Picture Experts Group), May, 1991.
- [ODA] ISO 8613; Information Processing: Text and Office System; Office Document Architecture (ODA) and Interchange Format (ODIF), Part 1-8, 1989.
- [PCM] CCITT, Fascicle III.4 - Recommendation G.711, Geneva, 1972, "Pulse Code Modulation (PCM) of Voice Frequencies".
- [POSTSCRIPT] Adobe Systems, Inc., PostScript Language Reference Manual, Addison-Wesley, 1985.
- [X400] Schicker, Pietro, "Message Handling Systems, X.400", Message Handling Systems and Distributed Applications, E. Stefferud, O-j. Jacobsen, and P. Schicker, eds., North-Holland, 1989, pp. 3-41.
- [RFC-783] Sollins, K.R. TFTP Protocol (revision 2). June, 1981, MIT, RFC-783.
- [RFC-821] Postel, J.B. Simple Mail Transfer Protocol. August, 1982, USC/Information Sciences Institute, RFC-821.
- [RFC-822] Crocker, D. Standard for the format of ARPA Internet text messages. August, 1982, UDEL, RFC-822.
- [RFC-934] Rose, M.T.; Stefferud, E.A. Proposed standard for message encapsulation. January, 1985, Delaware and NMA, RFC-934.
- [RFC-959] Postel, J.B.; Reynolds, J.K. File Transfer Protocol. October, 1985, USC/Information Sciences Institute, RFC-959.
- [RFC-1049] Sirbu, M.A. Content-Type header field for Internet messages. March, 1988, CMU, RFC-1049.
- [RFC-1113] Linn, J. Privacy enhancement for Internet electronic mail: Part I - message encipherment and authentication procedures. August, 1989, IAB Privacy Task Force, RFC-1113.
- [RFC-1154] Robinson, D.; Ullmann, R. Encoding header field for Internet messages. April, 1990, Prime Computer, Inc., RFC-1154.
- [RFC-1342] Moore, Keith, Representation of Non-Ascii Text in Internet Message Headers. June, 1992, University of Tennessee, RFC-1342.
Security Considerations ๐
okay, this part is SERIOUS, so pay attention ๐ security issues get covered in Section 7.4.2 and in Appendix G, no skipping ๐ and implementors should pay special attention to the security implications of any mail content-types that can cause the remote execution of any actions in the recipient's environment. that's a whole big deal ๐
in those cases, the discussion of the applicaton/postscript content-type in Section 7.4.2 can serve as a model for thinking about other content-types with remote execution capabilities. so basically, if a content-type can make things run on someone's machine, look at how the PostScript one is handled and do the same kind of careful thinking ๐ง โจ
Authors' Addresses ๐
for more info, the authors of this document can be contacted via Internet mail:
Nathaniel S. Borenstein
MRE 2D-296, Bellcore
445 South St.
Morristown, NJ 07962-1910
Phone: +1 201 829 4270
Fax: +1 201 829 7019
Email: nsb@bellcore.com
Ned Freed
Innosoft International, Inc.
250 West First Street
Suite 240
Claremont, CA 91711
Phone: +1 714 624 7907
Fax: +1 714 621 5319
Email: ned@innosoft.com
THIS PAGE INTENTIONALLY LEFT BLANK.
Please discard this page and place the following table of contents after the title page.
Table of Contents ๐
1 Introduction....................................... 1
2 Notations, Conventions, and Generic BNF Grammar.... 3
3 The MIME-Version Header Field...................... 5
4 The Content-Type Header Field...................... 6
5 The Content-Transfer-Encoding Header Field......... 10
5.1 Quoted-Printable Content-Transfer-Encoding......... 14
5.2 Base64 Content-Transfer-Encoding................... 17
6 Additional Optional Content- Header Fields......... 19
6.1 Optional Content-ID Header Field................... 19
6.2 Optional Content-Description Header Field.......... 19
7 The Predefined Content-Type Values................. 20
7.1 The Text Content-Type.............................. 20
7.1.1 The charset parameter.............................. 20
7.1.2 The Text/plain subtype............................. 23
7.1.3 The Text/richtext subtype.......................... 23
7.2 The Multipart Content-Type......................... 29
7.2.1 Multipart: The common syntax...................... 30
7.2.2 The Multipart/mixed (primary) subtype.............. 34
7.2.3 The Multipart/alternative subtype.................. 34
7.2.4 The Multipart/digest subtype....................... 36
7.2.5 The Multipart/parallel subtype..................... 36
7.3 The Message Content-Type........................... 37
7.3.1 The Message/rfc822 (primary) subtype............... 37
7.3.2 The Message/Partial subtype........................ 37
7.3.3 The Message/External-Body subtype.................. 40
7.4 The Application Content-Type....................... 46
7.4.1 The Application/Octet-Stream (primary) subtype..... 46
7.4.2 The Application/PostScript subtype................. 47
7.4.3 The Application/ODA subtype........................ 50
7.5 The Image Content-Type............................. 51
7.6 The Audio Content-Type............................. 51
7.7 The Video Content-Type............................. 51
7.8 Experimental Content-Type Values................... 51
Summary............................................ 53
Acknowledgements................................... 54
Appendix A -- Minimal MIME-Conformance............. 56
Appendix B -- General Guidelines For Sending Email Data59
Appendix C -- A Complex Multipart Example.......... 62
Appendix D -- A Simple Richtext-to-Text Translator in C64
Appendix E -- Collected Grammar.................... 66
Appendix F -- IANA Registration Procedures......... 68
F.1 Registration of New Content-type/subtype Values..68
F.2 Registration of New Character Set Values...... 69
F.3 Registration of New Access-type Values for Message/external-body69
F.4 Registration of New Conversions Values for Application69
Appendix G -- Summary of the Seven Content-types... 71
Appendix H -- Canonical Encoding Model............. 73
References......................................... 75
Security Considerations............................ 76
Authors' Addresses................................. 77
๐ฆ where this page comes from
- ietf: rfc1341 1992-06
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms