How MIME Ordering Actually Works in Practice

Most people ship multipart email without thinking about the order of MIME parts. It works fine 90% of the time because everything just falls into place. The other 10%, something breaks in an obscure mail client and you spend three hours debugging why a perfectly valid message renders as garbled text in Outlook 2016 but looks perfect everywhere else. MIME stands for Multipurpose Internet Mail Extensions. When you send an email with both text and an attachment, or a text body plus an HTML version, the message gets broken into parts. Each part has a boundary string that separates it from the next one. The order of these parts matters more than most developers realize. The standard says the parts should be ordered from least complex to most complex. Plain text first, then HTML, then attachments. RFC 2046 is the governing document. But RFC 2046 is written in a way that leaves a lot of room for interpretation, which is exactly why you get those occasional edge cases where a corporate mail gateway reorders your parts and suddenly your HTML email shows as raw code in the inbox.

I learned this the hard way. A client was using a custom PHP mail generator that was writing the HTML part before the plain text fallback. Gmail accepted it fine. Apple Mail accepted it fine. But one particular email routing system at a mid-sized insurance company had a filter that grabbed the first text/plain part it found and used that as the preview snippet. Because the HTML part came first, the snippet extraction failed and their entire outbound newsletter showed up in user inboxes as a blank or garbage-looking message. No error. No bounce. Just broken previews for two weeks straight. The fix was straightforward. I added a plain text preamble before the HTML part and set the correct multipart/alternative content type with the boundary properly. The real lesson was that the order needs to match what the consumer expects, not just what the RFC technically allows.

The Practical Rules Nobody Tells You

There are a few things that most guides skip over. First, the boundary string must not appear anywhere inside the actual body content of any part. If your HTML contains a string that matches your boundary delimiter exactly, some parsers will truncate the message at that point. I once spent an afternoon tracking down a bug where a customer's email signature had a dashed line that happened to match the boundary string my code was generating. The signature contained four consecutive hyphens. My boundary was ----=_Part_12345. It never conflicted. But when I switched to a shorter auto-generated boundary for testing, it did. Always use a sufficiently unique boundary. ----=_Part_[random_string] with a long random suffix is the standard approach. Second, the Content-Type header for the overall message must come before any of the individual parts. The outer container declares what kind of multipart it is. Without that, some servers will refuse to parse the boundaries at all and just treat the whole thing as opaque binary data. This is more common than you would think with message queues and middleware that sits between your mail server and the recipient. Third, if you are including both plain text and HTML versions, the plain text version should come first. Most email clients are built to fall back from HTML to plain text. If HTML comes first, some clients will try to render the HTML and fail silently, showing nothing. Others will show a warning. A few will display the plain text after the HTML fails. But you are gambling with client behavior when you reverse the standard order.

Get the Full Details

The Mime Order: Author’s Preferred Text: The Bone Season Samantha Shannon Bloomsbury Publishing
The Mime Order: Author’s Preferred Text: The Bone Season Samantha Shannon Bloomsbury Publishing

What Happens When Ordering Goes Wrong

The most common symptom is a message that arrives but renders incorrectly. You might see raw MIME boundaries in the body text. You might see attachments listed inline as if they were part of the message content. Or you might see a completely blank message with no error. The last one is the worst because there is nothing to debug visually. I ran into this with a Python script that was building multipart messages using the mimemessage library. The script was generating the parts in the wrong order and not setting the Content-Disposition header on the attachment parts. Gmail showed the attachment as a downloadable file. Outlook showed it as inline content that looked like base64 garbage. And one internal corporate mail system just dropped the entire message silently. No NDR. Nothing. The workaround was to enforce a strict construction order: create the outer multipart/alternative container, add the plain text part first, then the HTML part, then switch to a multipart/mixed container and add the attachment with an explicit Content-Disposition: attachment header. That last part is critical. Without Content-Disposition set to attachment, some clients treat the file as part of the message body rather than as a downloadable attachment.

Common Pitfalls

Using a short or predictable boundary string. This causes parsing failures when the boundary appears in the message content. Keep it long and random. Forgetting to set the charset on text parts. If you omit the charset parameter, some clients assume ISO-8859-1 and turn your UTF-8 characters into question marks or gibberish. Always set charset="utf-8" explicitly on every text part. Mixing up multipart/alternative and multipart/mixed. These are not interchangeable. Use multipart/alternative when you are providing different versions of the same content (plain text and HTML). Use multipart/mixed when you are combining different types of content (body and attachments). Nesting them correctly is the key. The standard pattern is a multipart/mixed outer container with a multipart/alternative inner container for the body, followed by attachment parts.

Not using Base64 or quoted-printable encoding for non-ASCII content. Sending raw UTF-8 bytes inside a MIME part without proper encoding will corrupt the message on most older mail systems. Use base64 for binary content and quoted-printable for text that contains non-ASCII characters but is mostly readable.

The Mime Order - Tradebook for Courses
The Mime Order - Tradebook for Courses

When This Approach Fails Completely

If you are dealing with legacy systems that do not support multipart MIME at all, none of this helps. Some internal routing systems and archiving tools from the early 2000s still strip or ignore multipart boundaries. In those cases, the only reliable option is to send plain text only and include any rich content as a separate downloadable link. It is not elegant, but it works. Similarly, if you are generating MIME messages programmatically and the output needs to pass through multiple relay servers, each one might add its own headers or modify boundaries. There is no way to prevent this. The best you can do is keep your boundary strings long and unique, and validate the final output before sending by piping it through a MIME parser to check for structural integrity. The whole process usually takes about ten to fifteen minutes to set up correctly the first time if you know what you are doing. After that, it is mostly about maintaining the same structure across your email generation code and running a quick validation check before anything goes out. I run my messages through a basic MIME structure validator now before sending. It catches the obvious issues and saves me from another two-hour debugging session.