Trying to send "alternative" with MIME but it also shows up in capable mail client

2.1k views Asked by At

I'm trying to send nice MIME emails, where html will be displayed whenever possible, and when not possible it should have a textual fallback.

That is, when html contains an image, the "alternative" part should show "img ... should be here".

The problem is that I see everything, also the alternative, in gmail.

Is there something wrong with my MIME message?

Here's the content:

Content-Type: multipart/mixed; boundary="===============9061258228856181354=="
MIME-Version: 1.0
From: [email protected] <[email protected]>
To: [email protected]

--===============9061258228856181354==
Content-Type: multipart/alternative; boundary="===============2889524977048828163=="
MIME-Version: 1.0

--===============2889524977048828163==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit

img 1043833786270341319 should be here
--===============2889524977048828163==--

--===============9061258228856181354==
Content-Type: image/jpeg; name="sky.jpg"
MIME-Version: 1.0
Content-ID: <1043833786270341319>
Content-Transfer-Encoding: base64

/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsK
CwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQU
FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wAARCAEbAakDASIA
AhEBAxEB/8QAHQAAAgIDAQEBAAAAAAAAAAAAAgQBAwUGBwAICf/EADoQAAEEAQMDAwIFAgYBBAMB

--===============9061258228856181354==
Content-Type: multipart/related; boundary="===============7011550496984103126=="
MIME-Version: 1.0

--===============7011550496984103126==
Content-Type: text/html; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit

<div><h1>bla</h1></div><img src="cid:1043833786270341319" title="1043833786270341319"/>
--===============7011550496984103126==--

--===============9061258228856181354==--

Notes: The image code was cut just so its not huge code. Again, simply the goal is to show a fallback for non-html readers, which should have a different message than the html message. A capable mailer should NOT show the alternative message, right?

1

There are 1 answers

2
RealSkeptic On BEST ANSWER

Basically, your mail is not arraged correctly. There are a few ways to arrange the parts in a MIME message so that they make sense to a mail agent. Let's start from the simple and go through to the complicated option:


The simplest of all is text with a few attachments. For example, you want to send your CV to someone, So you write a few words of introduction and attach one or more document (cover letter, CV):

mime───multipart/mixed─┬─text
                       ├─attachment1
                       └─attachment2

Multipart/mixed means that the e-mail agent will show the parts serially - one after the other.

  • If the attachments' content-disposition is inline, and the e-mail agent is capable to show the given attachment type, then it will be shown inside the message itself - at its end.
  • If the attachments' content-disposition is attachment, they will usually be shown as some sort of icons or links for saving the attachments.

If you want to send a pretty HTML message, it is customary to include both a plaintext version and an HTML version. This is so that the recipient may be able to read it even in an e-mail reader that doesn't support HTML. You need to use multipart/alternative:

mime───multipart/mixed─┬─multipart/alternative─┬─text/plain
                       │                       └─text/html
                       ├─attachment1
                       └─attachment2

So, again, the message content includes three parts, the body and the two attachments. But the body itself is a multipart/alternative, and it contains the plaintext version and the HTML version. Remember to put the plaintext first, and the HTML second, as the convention is for the mail agent to pick the last alternative that it knows how to display.

The attachments are going to be displayed serially after the body, just like before, because they are the next parts in the main level, which is multipart/mixed.


Now let's look at a mail that doesn't have "attachments", but it does have images that are supposed to be embedded inside the HTML. In this case, the mail agent needs to know that the attachments are not just files sent over to the reader to be downloaded, but that it should display them in association with the HTML. So the correct mime type for that is multipart/related, to show that the parts are related. In this case, you also need to give them proper content IDs, and use those content IDs in the HTML. This is not part of the MIME standard, but it's how HTML mail is usually done these days.

As far as MIME is concerned, such a message will look like:

mime───multipart/alternative─┬─text/plain
                             └─multipart/related─┬─text/html
                                                 ├─embedded image 1
                                                 └─embedded image 2

This time we don't have attachments, so we can put the multipart/alternative as our top level content. It has the plaintext alternative first, like before, but the second alternative is itself a MimeMultipart("related").

Inside it, you have the HTML part, and the two images. The HTML and its images must always be parts of the same multipart/related object.


Now, what if you wanted to attach your document to such a message, one that has HTML and images inside it? Then you would be using something like this:

mime───multipart/mixed─┬─multipart/alternative─┬─text/plain
                       │                       └─multipart/related─┬─text/html
                       │                                           ├─embedded image 1
                       │                                           └─embedded image 2
                       ├─attachment1
                       └─attachment2

So your top level object is multipart/mixed, allowing you to add attachments serially to your message. The message "body" (the first part of the multipart/mixed) is the complex structure of multipart/alternative with an embedded multipart/related. And then the other attachments follow that.


In summary:

  • A multipart/mixed message has a first part which is supposed to be your readable message, and the rest are attachments. All parts will be shown by the reader's mail agent.
  • A multipart/alternative message gives different display alternatives of the same content, ordered from most common denominator to most rare presentation type (e.g. plain text→HTML→rich text→proprietary formatting) and the recipient's mail program picks the last one that it knows how to display. You see only one of the alternatives.
  • A multipart/related message is usually used to combine an HTML body with its inline messages. The first part is the HTML, the other parts have Content-IDs that the HTML uses for its <img src="..." /> tags.

Now let's look at your own hierarchy, based on the boundary strings. Your outermost level is a multipart/mixed with the boundary ===============9061258228856181354==. If you look for all the places that this border appears, you'll see that there are three parts to this multipart/alternative.

The first part is:

Content-Type: multipart/alternative; boundary="===============2889524977048828163=="
MIME-Version: 1.0

--===============2889524977048828163==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit

img 1043833786270341319 should be here
--===============2889524977048828163==--

This part is a multipart/alternative, but it only has one alternative part - whose content type is text/plain.

The second part is:

Content-Type: image/jpeg; name="sky.jpg"
MIME-Version: 1.0
Content-ID: <1043833786270341319>
Content-Transfer-Encoding: base64

/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsK
CwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQU
FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wAARCAEbAakDASIA
AhEBAxEB/8QAHQAAAgIDAQEBAAAAAAAAAAAAAgQBAwUGBwAICf/EADoQAAEEAQMDAwIFAgYBBAMB

So it's an image.

The third part is:

Content-Type: multipart/related; boundary="===============7011550496984103126=="
MIME-Version: 1.0

--===============7011550496984103126==
Content-Type: text/html; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit

<div><h1>bla</h1></div><img src="cid:1043833786270341319" title="1043833786270341319"/>
--===============7011550496984103126==--

Well, it's a multipart/related. But it only has one part - the text/html message. The image is not part of it.

So instead of having the following hierarchy, which is the appropriate one for what you described (text plain and html alternatives, the html part having an embedded image)

mime───multipart/alternative─┬─text/plain
                             └─multipart/related─┬─text/html
                                                 └─embedded image

You have this wrong hierarchy:

mime───multipart/mixed─┬─multipart/alternative───text/plain
                       ├─image
                       └─multipart/related───text/html

Because all the parts are in a multipart/mixed, they are displayed serially, not as alternatives. Because the text/plain and the multipart/related are not parts of the same multipart/alternative, the mail agent is not aware that they are alternatives to each other. It sees no other alternative to the text/plain, there is only one part in that multipart/alternative.

Because the multipart/related part does not contain the images, there will be mail agents which will fail to put the image inside the HTML properly. Also, because of this, the image is probably shown to you serially or as an attachment - it stands alone and not related to anything else.

So you have to rearrange your message to conform to the proper hierarchy for the alternatives to work and for the image to be properly related to the HTML.