RFC 1523

The text/enriched MIME Content-type

๐Ÿ“… published September 1993, from ietf

The text/enriched MIME Content-type ๐ŸŽ€

Bestie, okay, this is RFC 1523 and it is giving formatted text for email ๐Ÿ’…โœจ

Network Working Group ๐ŸŒธ

  • Request for Comments: 1523
  • Author: N. Borenstein, from Bellcore
  • Category: Informational
  • Date: September 1993
  • Obsoletes / Updates: the title block doesn't list any ๐Ÿงš

Status of this Memo ๐Ÿฆ‹

This memo is here to give information to the Internet community. It does not specify an Internet standard, and distribution of this memo is unlimited ๐Ÿซถ

Abstract โœจ

MIME [RFC-1341, RFC-1521] defines a format and general framework for representing a wide variety of data types in Internet mail. This document defines one particular type of MIME data, the text/enriched type, which is a refinement of the "text/richtext" type defined in RFC 1341. The text/enriched MIME type is meant to make simple enriched text work across a wide variety of hardware and software platforms, so everyone can read it ๐Ÿ’œ

The Text/enriched MIME type ๐Ÿ’–

Okay so the goal here is wider interoperability of simple formatted text, and to get there this doc defines an extremely simple subtype of the MIME content-type "text", called "text/enriched". It was designed to meet these criteria:

  1. 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 ๐Ÿ–จ๏ธ
  2. The syntax must be extensible to allow for new formatting commands that are deemed essential for some application ๐Ÿงฉ
  3. If the character set in use is ASCII or an 8-bit ASCII superset, then the raw form of the data must be readable enough to be largely unobjectionable in the event that it is displayed on the screen of the user of a non-MIME-conformant mail reader ๐Ÿ‘€
  4. 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. Yes, this limits what can be sent, but it makes it way more likely that what is sent gets displayed properly ๐Ÿ’…

This document defines a new MIME content-type, "text/enriched". The content-type line for this type may have one optional parameter, the "charset" parameter, with the same values permitted for the "text/plain" MIME content-type ๐ŸŒˆ

The syntax of "text/enriched" is very simple. It represents text in a single character set -- US-ASCII by default, although a different character set can be specified with the "charset" parameter. (The semantics of text/enriched in non-ASCII character sets are discussed later in this document.) All characters represent themselves, with one exception: the "<" character (ASCII 60), which marks the beginning of a formatting command ๐ŸŽฏ

Formatting instructions are formatting commands surrounded by angle brackets (<>, ASCII 60 and 62). Each formatting command may be no more than 60 characters in length, all in US-ASCII, restricted to the alphanumeric and hyphen (-) characters. Formatting commands may be preceded by a solidus (/, ASCII 47), which makes them negations, and such negations must always exist to balance the initial opening commands. So if the formatting command <bold> appears at some point, there must later be a </bold> to balance it. (NOTE: The 60 character limit on formatting commands does NOT include the <, >, or / characters that might be attached to such commands.) ๐Ÿ“

Formatting commands are always case-insensitive. That means bold and BoLd are equivalent in effect, if not in good taste ๐Ÿ˜ญ

Beyond tokens delimited by < and >, there are two other special processing rules. First, a literal less-than sign (<) can be represented by a sequence of two such characters, <<. Second, line breaks (CRLF pairs in standard network representation) are handled specially. Isolated CRLF pairs are translated into a single SPACE character. Sequences of N consecutive CRLF pairs, however, are translated into N-1 actual line breaks. This lets long lines of data look natural even with all the line-wrapping that happens in Internet mailers ๐ŸŒธ When preparing the data for mail transport, isolated line breaks should be inserted wherever necessary to keep each line shorter than 80 characters. When preparing that data for the user, isolated line breaks should be replaced by a single SPACE character, and N consecutive CRLF pairs should be presented to the user as N-1 line breaks ๐Ÿงš

Thus text/enriched data that looks like this:

This is
a single
line

This is the
next line.

This is the
next paragraph.

should be displayed by a text/enriched interpreter as follows:

This is a single line
This is the next line.

This is the next paragraph.

The formatting commands, not all of which will be implemented by all implementations, are described in the following sections ๐Ÿฆ‹

Formatting Commands ๐Ÿ’…

The text/enriched formatting commands all begin with <commandname> and end with </commandname>, and they affect the formatting of the text between those two tokens. The commands are grouped by type below ๐ŸŽ€

Font-Alteration Commands

The following formatting commands are meant to alter the font the text is displayed in, but not the indentation or justification state of the text โœจ

  • Bold -- causes the affected text to be in a bold font. Nested bold commands have the same effect as a single bold command.
  • Italic -- causes the affected text to be in an italic font. Nested italic commands have the same effect as a single italic command.
  • Fixed -- causes the affected text to be in a fixed width font. Nested fixed commands have the same effect as a single fixed command.
  • Smaller -- causes the affected text to be in a smaller font. It is recommended that the font size be changed by two points, but other amounts may be more appropriate in some environments. Nested smaller commands produce ever-smaller fonts, up to the limits of the implementation's capacity to reasonably display them, after which further smaller commands have no incremental effect. ๐Ÿ”
  • Bigger -- causes the affected text to be in a bigger font. It is recommended that the font size be changed by two points, but other amounts may be more appropriate in some environments. Nested bigger commands produce ever-bigger fonts, up to the limits of the implementation's capacity to reasonably display them, after which further bigger commands have no incremental effect. ๐Ÿ”Ž
  • Underline -- causes the affected text to be underlined. Nested underline commands have the same effect as a single underline command. ๐Ÿ’ซ

While the "bigger" and "smaller" operators are effectively inverses, it is not recommended, for example, that <smaller> be used to end the effect of <bigger>. That is properly done with </bigger> ๐Ÿ™ˆ

Justification Commands

Initially, text/enriched text is meant to be displayed fully-justified, with appropriate fill, kerning, and letter-tracking as suits the capabilities of the receiving user agent software. The actual line width is left to the discretion of the receiver, which is expected to fold lines intelligently (preferring soft line breaks) to the best of its ability ๐ŸŒˆ

The following commands change that state. Each of these commands force a line break before and after the formatting command if there is not otherwise a line break already. So if one of these commands shows up anywhere other than the beginning of a line of text as presented, a new line is started ๐Ÿ“

  • Center -- causes the affected text to be centered.
  • FlushLeft -- causes the affected text to be left-justified with a ragged right margin.
  • FlushRight -- causes the affected text to be right-justified with a ragged left margin.

The center, flushleft, and flushright commands are mutually exclusive, and when nested, the inner command takes precedence ๐Ÿ‘‘

Note that for some non-ASCII character sets, full justification may be inappropriate. In these cases, a user agent may choose not to justify such data ๐ŸŒธ

Indentation Commands

Initially, text/enriched text is displayed using the maximum available margins. Two formatting commands may be used to affect the margins ๐Ÿงถ

  • Indent -- causes the running left margin to be moved to the right. The recommended indentation change is the width of four characters, but this may differ among implementations.
  • IndentRight -- causes the running right margin to be moved to the left. The recommended indentation change is the width of four characters, but this may differ among implementations.

A line break is NOT forced by a change of the margin, which lets you describe "hanging" text. So for example, the following text:

Now <indent> is the time for all good horses to come to the aid of
their stable, assuming that </indent> any stable is really stable.

would be displayed in a 40-character-wide window as follows:

Now is the time for all good horses to
    come to the aid of their stable,
    assuming that any stable is
really stable.

Miscellaneous Commands ๐Ÿ’

  • Excerpt -- causes the affected text to be interpreted as a textual excerpt from another source, probably a message being responded to. Typically this is displayed using indentation and an alternate font, or by indenting lines and preceding them with "> ", but those decisions are up to the implementation. (Note that this is the only truly declarative markup construct in text/enriched. It doesn't fit very well with the other facilities, but it describes a type of markup that is very commonly used in email and has no procedural analogue.) As with the justification commands, the excerpt command implicitly begins and ends with a line break if one is not already there ๐Ÿ’ฌ
  • Verbatim -- causes the affected text to be displayed without filling, justification, any interpretation of embedded formatting commands, or the usual special rules for CRLF handling. Note, however, that the end token </verbatim> must still be recognized ๐Ÿ›‘
  • Nofill -- causes the affected text to be displayed without filling or justification, and hence without any special handling of CRLFs, but with all remaining text/enriched features continuing to apply ๐ŸŒŠ
  • Param -- marks the affected text as command parameters, to be interpreted or ignored by the text/enriched interpreter, but NOT to be shown to the reader ๐Ÿ™ˆ

Note that while the absence of a quoting mechanism makes it slightly challenging to include the literal string <verbatim> inside of a verbatim environment, it can be done by breaking up the verbatim segment into two verbatim segments as follows:

          <verbatim>
          ...slightly challenging to include the literal string
          "</</verbatim><verbatim>verbatim>" inside of a verbatim
          environment...
          </verbatim>

Okay so that example is lowkey the whole point ๐Ÿ™ˆ It proves that it is not desirable for an implementation to break lines between tokens. Like, there SHOULD NOT be a line break inserted between the </verbatim> and the <verbatim> that follows it. Keep those two glued together, bestie ๐Ÿซถ

Balancing and Nesting of Formatting Commands

Pairs of formatting commands MUST be properly balanced and nested ๐Ÿ’– So a proper way to describe text in bold italics is:

           <bold><italic>the-text</italic></bold>

or, alternately,

           <italic><bold>the-text</bold></italic>

But, in particular, this one is illegal text/enriched ๐Ÿ’€:

           <bold><italic>the-text</bold></italic>

The nesting rule gives composers a slightly higher burden, ngl, but it potentially simplifies displayers by letting them be stack-based ๐Ÿฅž The whole main goal of text/enriched is to be simple enough that multifont, formatted email is widely readable, so that anyone who can send it will be able to do so with confidence โœจ So slightly more complexity in the composing software was deemed a reasonable tradeoff for simpler reading software. Nonetheless, implementors of text/enriched readers are encouraged to follow the general Internet guidelines of being conservative in what you send and liberal in what you accept. Those implementations that can do so are encouraged to deal reasonably with improperly nested text/enriched data ๐Ÿฆ‹

Unrecognized formatting commands

Implementations MUST regard any unrecognized formatting command as "no-op" commands, meaning commands with no effect at all. This is what keeps future extensions to "text/enriched" possible ๐Ÿงš Private extensions MAY be defined using formatting commands that begin with "X-", by analogy to Internet mail header field names.

In order to formally define extended commands, a new Internet document SHOULD be published ๐Ÿ“œ

"White Space" in text/enriched Data

No special behavior is REQUIRED for the SPACE or TAB (HT) character ๐ŸŒธ It is RECOMMENDED, however, that, at least when fixed-width fonts are in use, the common semantics of the TAB (HT) character SHOULD be observed. That means it moves to the next column position that is a multiple of 8. (In other words, if a TAB (HT) occurs in column n, where the leftmost column is column 0, then that TAB (HT) SHOULD be replaced by 8-(n mod 8) SPACE characters.) It SHOULD also be noted that some mail gateways are notorious for losing (or, less commonly, adding) white space at the end of lines. So reliance on SPACE or TAB characters at the end of a line is NOT RECOMMENDED ๐Ÿ’€

Initial State of a text/enriched interpreter

Text/enriched is assumed to begin with filled, fully justified text in a variable-width font, in a normal typeface, at a size that is average for the current display and user ๐Ÿ’… The left and right margins are assumed to be maximal, which means at the leftmost and rightmost acceptable positions.

Non-ASCII character sets

If the character set specified by the charset parameter on the Content-type line is anything other than "US-ASCII", the text being described by text/enriched formatting commands is in a non-ASCII character set ๐ŸŒ The commands themselves are still the same ASCII commands defined in this document, though. The only ambiguity is with the "<" character, the octet with numeric value 60. In single byte character sets, such as the ISO-8859 family, this is no big deal: the octet 60 can be quoted by including it twice, just like in ASCII. It gets messier in multi-byte character sets, where the octet 60 might show up at any point in the byte sequence for any of several characters ๐Ÿ˜ตโ€๐Ÿ’ซ

In practice, though, most multibyte character sets handle this internally. For example, the ISO-2022 family can switch back into ASCII at any moment โœจ So it is specified that, before text/enriched formatting commands, the prevailing character set SHOULD be "switched back" into ASCII, and that only those characters which would be interpreted as "<" in plain text SHOULD be interpreted as token delimiters in text/enriched.

What to do for hypothetical future character sets that do NOT subsume ASCII is not addressed in this memo ๐Ÿ”ฎ

Minimal text/enriched conformance

A minimal text/enriched implementation is one that just recognizes the beginning and ending of "verbatim" environments. Outside of them, it does the following:

  • converts << to <
  • removes everything between a <param> command and the next balancing </param> command
  • removes all other formatting commands (all text enclosed in angle brackets)
  • converts any series of n CRLFs to n-1 CRLFs
  • converts any lone CRLF pairs to SPACE

That's it, honestly the lowest bar ever and I'm here for it ๐Ÿ“

Notes for Implementors

Future mail systems are gonna want rich text functionality way beyond what text/enriched currently defines ๐Ÿš€ The intent is to give everyone a common format for that stuff, in a form that a lot of interoperating software will still understand. So software with a richer notion of formatted text can still use text/enriched as its basic representation. It can extend it with new formatting commands and hide system-specific info inside <param> constructs. As these systems evolve, the definition of text/enriched is expected to get further refined by future published specifications, but this version is a platform that evolutionary refinements can be built on ๐Ÿ—๏ธ

An expected common way that sophisticated mail programs will generate text/enriched data is as part of a multipart/alternative construct ๐Ÿ’Œ For example, a mail agent that can generate enriched mail in ODA format can make it more widely interoperable by generating both text/enriched and ODA versions of the same data, like this:

         Content-type: multipart/alternative; boundary=foo

         --foo
         Content-type: text/enriched

         [text/enriched version of data]
         --foo
         Content-type: application/oda

         [ODA version of data]
         --foo--

If a MIME-conformant mail reader that understands ODA reads this, the ODA version gets displayed. Otherwise, the text/enriched version shows up ๐Ÿ™Œ

In some environments it might be impossible to combine certain text/enriched formatting commands, whereas in others they combine easily ๐ŸŽจ For example, <bold> and <italic> might produce bold italics on systems that support those fonts. But there are systems that can make text bold or italicized, but not both. In those cases, the most recently issued (innermost) recognized formatting command SHOULD be preferred ๐Ÿ‘‘

One of the big goals for text/enriched was making it so simple that even text-only mailers would implement enriched-to-plain-text translators. That makes enriched text way more likely to be "safe" to use widely ๐Ÿ’œ To prove how simple it is, an extremely simple C program that converts text/enriched input into plain text output is included in Appendix A ๐Ÿง

Extensions to text/enriched

Lots of mail system authors are gonna want extensions to text/enriched, and that's the whole plan ๐Ÿคญ The simple syntax, plus the rule that unrecognized formatting commands SHOULD simply be ignored, are meant to make those extensions happen.

Beyond just defining new formatting commands, sometimes you need commands that take arguments. That's what the <param> construct is for ๐ŸŽ€ For example, software that wanted to extend text/enriched with colored text might define an "x-color" environment that always begins with a color name parameter, to indicate the desired color for the affected text ๐ŸŒˆ

An Example

Putting all this together, the following "text/enriched" body fragment:

         From: Nathaniel Borenstein <nsb@bellcore.com>
         To: Ned Freed <ned@innosoft.com>
         Content-type: text/enriched

         <bold>Now</bold> is the time for
         <italic>all</italic> good men
         <smaller>(and <<women>)</smaller> to
         <ignoreme>come</ignoreme>

         to the aid of their

         <x-color><param>red</param>beloved</x-color>country.
         <verbatim>
         By the way, I think that <smaller>
         should
         REALLY be called
         <tinier>
         and that I am always right.
         -- the end
         </verbatim>

represents the following formatted text (which will, no doubt, look somewhat 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.
         By the way, I think that <smaller>
         should
         REALLY be called
         <tinier>
         and that I am always right.
         -- the end

where the word "beloved" would be in red on a color display, if the receiving software implemented the "x-color" extension ๐Ÿ’–


Security Considerations

Security issues are not discussed in this memo, because the mechanism raises no security issues ๐Ÿ”’ Zero drama, zero risk, all vibes โœจ

Author's Address

For more information, the author of this document MAY 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 5963
EMail: nsb@bellcore.com

Acknowledgements

This document reflects the input of many contributors, readers, and implementors of the original MIME specification, RFC 1341 ๐Ÿซถ It also reflects particular contributions and comments from Terry Crowley and Rhys Weatherley, who are literal legends ๐Ÿ‘‘

Appendix A -- A Simple enriched-to-plain Translator in C ๐ŸŽ€

okay so one of the BIG goals behind text/enriched ๐Ÿ’– was making formatted text so simple that even text-only mailers would bother writing enriched-to-plain-text translators. if it's that easy, everyone does it, and then multifont text becomes actually "safe" to use pretty much everywhere ๐Ÿซถ. to prove how simple it is, here's a tiny C program that turns text/enriched input into plain text. heads up: it assumes the local newline convention (the single character written "\n"), but some systems might need special CRLF handling ๐ŸŒธ

                 #include <stdio.h>
                 #include <ctype.h>

                 main() {
                     int c, i, paramct=0, newlinect=0, verbatim=0,
                 nofill=0;
                     char token[62], *p;

                     while ((c=getc(stdin)) != EOF) {
                         if (c == '<') {
                             if (verbatim != 0) {
                                 for (i=0, p=token; (*p++ = getc(stdin))
                 != EOF
                                     && !lc2strncmp(token, "/verbatim>",
                 i+1) && i<9; i++) {}
                                 if (i==9) {
                                     verbatim = 0;
                                 } else {
                                     *p = '\0';
                                     putc('<', stdout);
                                     fputs(token, stdout);
                                 }
                                 continue;
                             } else {
                                 newlinect=0;
                                 c = getc(stdin);
                                 if (c == '<') {
                                     if (paramct <= 0) putc(c, stdout);
                                 } else {
                                     ungetc(c, stdin);
                                     for (i=0, p=token; (c=getc(stdin))
                 != EOF && c != '>'; i++) {
                                         if (i < sizeof(token)-1) *p++ =
                 isupper(c) ? tolower(c) : c;
                                     }
                                     *p = '\0';
                                     if (c == EOF) break;
                                     if (strcmp(token, "param") == 0)
                                         paramct++;
                                     else if (strcmp(token, "verbatim")
                 == 0)
                                         verbatim = 1;
                                     else if (strcmp(token, "nofill") ==
                 0)
                                         nofill++;
                                     else if (strcmp(token, "/param") ==
                 0)
                                         paramct--;
                                     else if (strcmp(token, "/nofill")
                 == 0)

                                         nofill--;
                                 }
                             }
                      } else {
                         if (paramct > 0)
                           ; /* ignore params */
                            else if (c == '\n' && verbatim == 0 &&
                 nofill <= 0)
                                if (++newlinect > 1) {
                                    putc(c, stdout);
                                } else {
                                    putc(' ', stdout);
                                }
                            else {
                                newlinect = 0;
                                putc(c, stdout);
                            }
                      }
                     }
                     /* The following line is only needed with line-
                 buffering */
                     putc('\n', stdout);
                     exit(0);
                 }

                 lc2strncmp(s1, s2, len)
                 char *s1, *s2;
                 int len;
                 {
                     if (!s1 || !s2) return (-1);
                     while (*s1 && *s2 && len > 0) {
                      if (*s1 != *s2 && (tolower(*s1) != *s2)) return(-

                 1);
                      ++s1; ++s2; --len;
                     }
                     if (len <= 0) return(0);
                     return((*s1 == *s2) ? 0 : -1);
                 }

ngl, you can do WAY better than this when you're showing text/enriched on a dumb terminal ๐Ÿ’…. you can swap font stuff like "bold" for textual emphasis, like *this* or _T_H_I_S_ ๐Ÿ“. you can also properly handle indentation, justification, and the other formatting commands. BUT the program above is all that's necessary to show text/enriched on a dumb terminal without the user seeing any formatting artifacts โœจ


Appendix B -- Differences from RFC 1341 text/richtext ๐Ÿฆ‹

bestie, text/enriched is basically a clarified, simplified, and refined version of the type RFC 1341 called text/richtext ๐Ÿ’œ. for anyone who already knows text/richtext (or wants to reuse those similarities so text/richtext data shows up in your text/enriched software), here's the rundown of the differences. heads up though: text/enriched is meant to make text/richtext obsolete, so it is not recommended that new software generate text/richtext ๐Ÿ™ˆ

0. The name "richtext" was changed to "enriched". The goal was to tell the two versions apart, and "richtext" caused a ton of confusion with Microsoft's Rich Text Format (RTF) ๐Ÿ˜ญ

1. Clarifications. A lot was ambiguous or unspecified in the text/richtext definition, especially the initial state and how richtext worked with multibyte character sets. But these differences are OPERATIONALLY irrelevant ๐Ÿ’…, since the clarifications in this document are at least reasonable interpretations of the text/richtext specification.

2. Newline semantics changed. In text/richtext, every CRLF got mapped to a space, and line breaks were marked with <nl>. That's been replaced by the "n-1" rule for CRLFs โœจ

3. A literal "<" character was written <lt> in text/richtext, but in text/enriched it's << ๐ŸŽ€

4. The verbatim and nofill commands didn't exist in text/richtext ๐ŸŒˆ

5. The param command didn't exist in text/richtext either ๐Ÿงš

6. The following commands from text/richtext have been REMOVED from text/enriched: <COMMENT>, <OUTDENT>, <OUTDENTRIGHT>, <SAMEPAGE>, <SUBSCRIPT>, <SUPERSCRIPT>, <HEADING>, <FOOTING>, <ISO-8859-[1-9]>, <US-ASCII>, <PARAGRAPH>, <SIGNATURE>, <NO-OP>, <LT>, <NL>, and <NP> ๐Ÿ’€

7. All claims of SGML compatibility were dropped. Except for the possible exceptions of the new CRLF semantics and <<, which can be implemented, text/enriched should be no less SGML-friendly than text/richtext was ๐Ÿซถ

8. In text/richtext, there were three commands (<NL>, <NP>, and <LT>) that did not use balanced closing delimiters. Since all of these have been eliminated, there are NO exceptions to the nesting/balancing rules in text/enriched ๐Ÿ™Œ

9. The limit on the size of formatting tokens went up from 40 to 60 characters ๐Ÿ“

References ๐Ÿ“š

[RFC-1341] Borenstein, N., and N. Freed, "MIME (Multipurpose Internet Mail Extensions): Mechanisms for Specifying and Describing the Format of Internet Message Bodies", RFC 1341, Bellcore, Innosoft, June 1992.

[RFC-1521] Borenstein, N., and N. Freed, "MIME (Multipurpose Internet Mail Extensions) Part One: Mechanisms for Specifying and Describing the Format of Internet Message Bodies", RFC 1521, September 1993.

๐Ÿ“ฆ where this page comes from