Chapter 9 Using the MIME Package
9.1 Preparing Data
Although the MIME specification allows a message to contain nearly any content, MIME messages are typically transmitted over protocols that have stricter requirements. By following a few simple guidelines, you can easily construct message bodies that meet the requirements of nearly all protocols.
To create a message body, follow these steps:
1. Create an RWCString containing the data.
2. Convert text to canonical form.
3. Encode the string, if necessary.
Each step is discussed in more detail below. Section 9.3, “Program: Creating a Simple MIME Message,” presents a complete example program that creates a simple MIME message.
9.1.1 Create an RWCString
The exact process for creating the data depends on the specific application. No matter how the data is originally created, store the data for the body in an RWCString. Since an RWCString can efficiently store any sequence of bytes, including embedded nulls, the class works well to represent a message body regardless of the content.
9.1.2 Convert Text to Canonical Form
Data within a MIME message should always be converted to the format defined by MIME for that datatype, the canonical form (see Section 10.2.1). For most data formats, the canonical form is identical to the normal format of the data.
One common case where the canonical form may not be identical to the normal data format is text. For text, the canonical form represents a line break as a carriage return (ASCII 13) followed by a line feed (ASCII 10). RWMimeUtils provides a static replaceLineDelim() function for translating text to and from canonical form. When provided with only an RWCString as an argument, the function returns a copy of the string converted to canonical form. To convert text to canonical form:
 
RWCString text;
 
// ... fill the RWCString with text in a platform-specific format
 
RWCString canonText = RWMimeUtils::replaceLineDelim(text);
When a second argument is provided, the function translates each line break in the original string to the character sequence in the second argument. For example, UNIX platforms use a single newline character for a line break. To translate the line breaks in a canonical form string to UNIX line breaks, provide a newline as the second argument to replaceLineDelim(), as shown in the following code:
 
RWCString canonText;
 
// ... fill the RWCString with text in canonical form
 
RWCString text = RWMimeUtils::replaceLineDelim(canonText, "\n");
9.1.3 Encode the Data
If the message is 7-bit ASCII text or the transport protocol preserves binary messages, it’s most efficient to use an identity encoding – an encoding that describes the data but does not alter the data. Otherwise, the best encoding depends on the data.
*If the transport protocol preserves binary data (for example, HTTP), then do not encode the message. Use an identity transfer encoding that describes the data:
*Use 7bit for text that contains only ASCII characters 0-127.
*Use 8bit for other text messages.
*Use binary for binary data.
*If the data contains only 7-bit ASCII text with lines less than 76 characters, do not encode the content. Use a Content-Transfer-Encoding of 7bit. This is the default encoding, so in this case, the part does not require a Content-Transfer-Encoding header.
*Otherwise, encode the data:
*Use quoted-printable encoding for text that is mostly 7-bit ASCII characters.
*Use base64 encoding for binary data or text that is mostly 8-bit characters.
Notice that base 64 encoding is the only safe choice for transmitting binary data over a protocol that does not preserve binary data, such as SMTP.
For text messages, the best encoding depends on the number of 8-bit characters. Quoted-printable encoding preserves 7-bit ASCII characters, while base 64 more efficiently encodes 8-bit characters. The practical result is that base 64 encoding is a good choice for text with a relatively large number of 8-bit characters, whereas quoted-printable encoding produces shorter, mostly human-readable messages for text that contains mostly 7-bit characters.
Convert data to canonical form before encoding the data (see Section 9.1.2). To encode the data, use the static encode() function from RWMimeUtils. For example, to encode binary data using the base64 encoding:
 
RWCString binaryData;
 
// ... fill binaryData with the binary data
 
RWCString encoded = RWMimeUtils::encode(binaryData,
RWMimeUtils::Base64);
Encodings are discussed in detail in Section 10.3, “Transfer Encodings,”