MH & nmh: Email for Users & Programmers

May, 2006

Multipart Messages

The Section MIME Header Fields introduced six content types: text, image, audio, video, message, and multipart. A multipart message is different from the other five. A multipart message has more than one part. Each part can have its own content type.

A Sample Multipart Message

Let's start by looking at an Example, a fairly simple multipart message. This shows the MIME message as it's sent to the recipient. Luckily, you don't have to enter all this stuff to send a multipart message! A lot of it is added automatically. But going through it will help you understand what MH is doing and how the message is structured. (If you want to look ahead to the next Example, you'll see how the decoded message might look.)

Example: Sample multipart message, encoded

    From: Laura Rios <laura@oara.sf.ca.us>
    To: steve@ntecom.za
    Subject: Sara is two!
    Mime-Version: 1.0
    Content-Type: multipart/mixed; boundary="Snip snip snip"
    
Prologue: any text here is ignored by MIME mail programs
    --Snip snip snip
    Content-Type: text/enriched; charset="us-ascii"

    Hi, Steve.  Sara had her second birthday yesterday.  Can you believe it?
    She is so <bold>big</bold>!  Now if we can just live through the
    "terrible twos" for a year, <italic>sigh</italic>.


    Here are a few words from her.  I've also scanned in a picture of her
    party.  Tell your boss thanks for letting us keep in touch by email.


    Laura

    --Snip snip snip
    Content-type: audio/basic
    Content-transfer-encoding: base64
    Content-description: Sara says "I love you, Steve" (awww)

    /Xr++/hoX2lqeXt8d/7z8/D5+PLw7/b+9fD09319/vz5f3j//Pz9fHp7fvrs9Wz/eH59d
    
   omitted...
    /////////////////y8=

    --Snip snip snip
    Content-type: image/gif
    Content-transfer-encoding: base64
    Content-description: Cutting the cake, sort of

    R0lGODdhQAHIAKMAAAAAAP+2bQAAACQAAAAASEgAAAAkSEgkJG0kJJEkAABIkZFIJCRttrZt
    
   omitted...
    l7Vry4B9aM+yKjifMosAADs=

    --Snip snip snip--
    
Epilogue: any text here is ignored by MIME mail programs

The sample message (above) has three parts. The parts are separated by a boundary, which is specified as a parameter in the main Content-type: header field. Each part boundary starts with two dashes ( -- ). The last boundary in a message also ends with two dashes. It's important to pick a boundary that won't appear anywhere in the parts. MH chooses unique (but ugly) boundaries automatically; in this example, I used "Snip snip snip."

You can put text (the preamble) before the first boundary and more text (epilogue) after the last boundary. MIME mail readers will ignore the preamble and the epilogue, but non-MIME programs show it. So the preamble is a good place to put explanation for people who don't have MIME readers.

Each part of the message has its own header fields, called body part header fields. A plain text ASCII part doesn't need a Content-type: field.

Usually, but not always, the first part of a multipart message is text that introduces or explains the rest of the message. You can also sprinkle text parts throughout the message -- to explain the following non-text parts, for instance. A part can also have a Content-description: header field that summarizes what's in that part.

The first part of this sample message has a text/enriched content-type. Enriched text gives you some of the features of a word processor -- like boldface and italic text -- in a plain-ASCII message. For instance, <bold> starts text that should be shown boldfaced; the same token with a slash, </bold>, ends the boldfacing. The recipient's mail program justifies the text to fit the display; they may not be formatted the way you type them.

Line and paragraph breaks are handled in a clever way. To break a line of text at a particular place, leave an empty line. To end a paragraph, leave two empty lines. The enriched text reader will "eat" single empty lines to give the formatted effect you want; people with non-MIME mail programs will see the extra blank lines but should still get the idea.

The next Example shows what would happen as Steve's MH setup displays that message. (What would happen on your MH system depends on your setup. See the Chapter Making MH Work Your Way.)

Example: Sample multipart message, decoded

    % show
    (Message inbox:34)
    From: Laura Rios <laura@oara.sf.ca.us>
    To: steve@ntecom.za
    Subject: Sara is two!
    (END)

    Part 1    text/plain     356
    Press <return> to show content...
    
Hi, Steve. Sara had her second birthday yesterday. Can you believe it? She is so big! Now if we can just live through the "terrible twos" for a year, sigh.

Here are a few words from her. I've also scanned in a picture of her party. Tell your boss thanks for letting us keep in touch by email.

Laura


    Part 2    audio/basic     7200 Sara says "I love you, Steve" (awww)
    Press <return> to show content...

    ...sound plays on Steve's workstation speaker...

    Part 3    image/gif    57600 Cutting the cake, sort of
    Press <return> to show content...

    ...Window with color picture pops up...

    %
    

Multipart/alternative Messages

Another important kind of multipart message is multipart/alternative. It presents the same information in two or more ways, and the recipient's MUA chooses the most faithful form it can process. So, unlike other multipart message subtypes (where all parts are displayed), only one part of a multipart/alternative message is shown.

For instance, a multipart/alternative message might contain the same words in plain text, enriched text, and PostScript formats. If the recipient's MUA can display PostScript (with its assorted fonts, figures, and so on), the MUA will show that part; otherwise it will display enriched or plain text. When you compose a multipart/alternative message, the simplest format (the one closest to plain text) must come first. This rule makes it easier for someone with a non-MIME MUA to find the plain text.

Here's an example:

    From: Jerry Peek <jerry@ora.com>
    To: mh-users@ics.uci.edu
    Subject: New edition of "MH & xmh" covers MIME and MH-E
    MIME-Version: 1.0
    Content-Type: multipart/alternative; boundary="----- =_aaaaaaaaaa0"
    Content-ID: <1283.780402430.1@ora.com>

    ------- =_aaaaaaaaaa0
    Content-Type: text/plain; charset="us-ascii"
    Content-ID: <1283.780402430.2@ora.com>

    We've just released the new third edition of "MH & xmh: Email for
    Users & Programmers."  Changes include:
        - MIME (Multimedia) mail
        - The popular MH-E GNU Emacs front-end to MH
            ...omitted...

    ------- =_aaaaaaaaaa0
    Content-Type: text/enriched; charset="us-ascii"
    Content-ID: <1283.780402430.3@ora.com>

    We've just released the new third edition of <italic>MH & xmh: Email
    for Users & Programmers</italic>. Changes include:

    <indent>
    - MIME (Multimedia) mail

    - The popular MH-E GNU Emacs front-end to MH
            ...omitted...

    ------- =_aaaaaaaaaa0
    Content-Type: application/postscript
    Content-ID: <1283.780402430.4@ora.com>
    Content-Transfer-Encoding: quoted-printable

    %!PS-Adobe-3.0
    %%Creator: groff version 1.09
            ...omitted...
    %%Trailer
    end
    %%EOF

    ------- =_aaaaaaaaaa0--

    
MH automatically created the boundaries. It added the first Content-Type: and all Content-ID: and Content-Transfer-Encoding: fields. This is the file I gave to MH to create the MIME message:
    From: Jerry Peek <jerry@ora.com>
    To: mh-users@ics.uci.edu
    Subject: New edition of "MH & xmh" covers MIME, exmh, and MH-E
    --------
    #begin alternative
    We've just released the new third edition of "MH & xmh: Email for
            ...omitted...
    #<text/enriched
    We've just released the new third edition of <italic>MH & xmh: Email
            ...omitted...
    #application/postscript /u/jerry/mh-book/3rd_edition.ps
    #end
    

To find out more about MIME message composition, read the introduction in Section Sending MIME Mail and the details in Section Composing and Sending MIME Messages.

Parts within Parts

Multipart MIME messages can have a hierarchical structure like trees or outlines or UNIX directories: each part can be made of more parts. When MH shows these messages, it will work through the parts from first to last. The command mhn -list (for MH) or mhlist (for nmh-1.0 and above) shows a message structure and assigns numbers to the parts. (mhn is the MH command that processes MIME. There's much more about mhn and the corresponding nmh commands later in this book.)

The first part of the example message below is an overview. Next are two comments from the company's President Parker -- about jobs and the budget. Here's the mhn listing of message number 91:

    % mhn -list 91
     msg part  type/subtype              size description
      91       multipart/mixed           272K
         1     text/plain                2168 Overview of this message
         2     multipart/alternative     113K
         2.1   audio/basic               110K Parker re: jobs (audio)
         2.2   text/plain                 937 Parker re: jobs (transcript)
         3     multipart/alternative     159K
         3.1   audio/basic               156K Parker re: budget (audio)
         3.2   text/plain                1029 Parker re: budget (transcript)
    
As explained above, part 1 is an overview (the description of the part comes from the Content-Description: field). Part 2 and Part 3 are each two separate multipart/alternative messages; each part has the same information, first as audio and then as text. The first subpart of each part (2.1 and 3.1) are audio versions; they'll be played if your MH setup can play sound. Otherwise, parts 2.2 and 3.2 will be displayed; they have plain-text versions of the audio parts. (Note that mhn -list and mhlist don't necessarily show the parts in the same order as the original message.)

You don't have to read all of a message; you can specify the parts you want to see with a part-showing command like mhn -part 3.2 (MH) or mhshow -part 3.2 (nmh-1.0+).

Making subparts is simple if you remember that each part should be able to stand on its own. A part that's divided into subparts needs its own boundary marker. You don't have to worry about the boundary markers, though; MH will choose the right ones. Here's a look at the multipart message number 91 from the example above:

    From: Clipping Service <audio@xxx.com>
    To: managers@xxx.com
    Subject: Parker on jobs and budget, 23 August 1994
    MIME-Version: 1.0
    Content-Type: multipart/mixed; boundary="----- =_aaaaaaaaaaA"
    Content-ID: <1458.780409280.0@xxx.com>

    ------- =_aaaaaaaaaaA
    Content-Type: text/plain; charset="us-ascii"
    
    Content-Description: Overview of this message

    This message has two sections of plain text and audio.  If your
    mail reader can play audio, you'll hear those parts; otherwise you'll
    see the plain-text transcripts.
            ...omitted...

    ------- =_aaaaaaaaaaA
    Content-Type: multipart/alternative; boundary="----- =_aaaaaaaaaaB"
    

    ------- =_aaaaaaaaaaB
    Content-Type: text/plain; charset="us-ascii"
    
    Content-Description: Parker re: jobs (transcript)
            ...omitted...
    
    

    ------- =_aaaaaaaaaaB
    Content-Type: audio/basic
    
    Content-Description: Parker re: jobs (audio)
            ...omitted...
    
    
    
    
    

    ------- =_aaaaaaaaaaB--

    ------- =_aaaaaaaaaaA
    Content-Type: multipart/alternative; boundary="----- =_aaaaaaaaaaC"
    

    ------- =_aaaaaaaaaaC
    Content-Type: text/plain; charset="us-ascii"
    
    Content-Description: Parker re: budget (transcript)
            ...omitted...
    
    
    

    ------- =_aaaaaaaaaaC
    Content-Type: audio/basic
    
    Content-Description: Parker re: budget (audio)
    
            ...omitted...
    
    
    
    

    ------- =_aaaaaaaaaaC--

    ------- =_aaaaaaaaaaA--
    
If you compare the boundaries to the mhn -list output above, you'll see how the parts and subparts are structured. The main parts (1, 2, and 3) are separated by a boundary that ends with aaaA. Parts 2 and 3, which have their own subparts, use subpart boundaries that end with aaaB and aaaC, respectively. These automatically generated boundaries also contain the string =_, which is guaranteed not to appear in any possible quoted-printable or base64 encodings.

That message was almost 300K bytes long. Sending it to 200 people around the company could use a big chunk of network capacity. MIME and MH have two ways to help with the problem of long message parts: