MIME Email Structure: How Alternative, Mixed, and Related Fit Together
Use multipart/alternative when two parts carry the same message in different formats. Use multipart/mixed when the parts are independent, usually a message body plus attachments. Use multipart/related when one part depends on the others, such as HTML that loads an inline image by Content-ID.
If one email needs plain text, HTML, an inline logo, and a CSV attachment, the reliable shape is:
multipart/mixed
├── multipart/alternative
│ ├── text/plain
│ └── multipart/related
│ ├── text/html
│ └── image/png (inline)
└── text/csv (attachment)
The outer container bundles independent things. The alternative container offers two renderings of the message. The related container keeps the HTML and its image together.
That nesting order is the useful part. MIME is recursive, so a clean message describes the relationship at each level instead of putting every body part in one flat list.
Read each layer as a relationship
Content-Type describes the media in one MIME entity. A multipart/* entity is a container whose children each have their own MIME headers and body. RFC 2045 defines those fields, and RFC 2046 defines the recursive multipart structure.
Alternative means interchangeable
Plain text and HTML are two representations of the same message, so they belong in multipart/alternative. The plain-text version comes first. The preferred rich version comes last.
RFC 2046, section 5.1.4 orders alternatives from the least faithful or simplest representation to the most faithful or richest. A receiving client should display the last format it understands.
The versions need to communicate the same information. Plain text does not need to reproduce the HTML layout, but it should not omit the account warning, payment detail, or action that makes the email useful.
Related means one compound object
HTML plus an embedded image is a compound object. The HTML references the image with a cid: URL:
<img src="cid:logo@example.com" alt="Example">
The image part carries the matching identifier:
Content-Type: image/png
Content-Transfer-Encoding: base64
Content-ID: <logo@example.com>
Content-Disposition: inline; filename="logo.png"
RFC 2387 lets the optional start parameter name the root by Content-ID. When start is absent, the first child is the root. Content-Disposition: inline is a presentation hint, but the related container is the structural relationship.
Mixed means separate items in one package
A CSV attachment is additional content, not another rendering of the message and not a resource needed to render the HTML. It becomes a sibling of the body container under an outer multipart/mixed.
This distinction fixes a common mistake. Putting plain text and HTML directly in multipart/mixed says they are separate items. Putting an attachment in multipart/alternative says it is another version of the message. Neither describes what the parts mean.
One exact message, parsed as a tree
The hypothetical message below contains all three relationships. The PNG is a real one-pixel image, and the CSV decodes to two short lines. I parsed this exact fixture with Python 3.14’s standard BytesParser.
From: sender@example.com
To: reader@example.net
Subject: Your monthly report
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="outer-6f3a"
--outer-6f3a
Content-Type: multipart/alternative; boundary="choice-22bd"
--choice-22bd
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: quoted-printable
Your report is ready.
--choice-22bd
Content-Type: multipart/related; boundary="html-90c1"; type="text/html"
--html-90c1
Content-Type: text/html; charset="utf-8"
Content-Transfer-Encoding: quoted-printable
<p>Your report is ready.</p><img src=3D"cid:logo@example.com" alt=3D"Example">
--html-90c1
Content-Type: image/png
Content-Transfer-Encoding: base64
Content-ID: <logo@example.com>
Content-Disposition: inline; filename="logo.png"
iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk
YAAAAAYAAjCB0C8AAAAASUVORK5CYII=
--html-90c1--
--choice-22bd--
--outer-6f3a
Content-Type: text/csv; charset="utf-8"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="report.csv"
bmFtZSx2YWx1ZQpyZXBvcnQsNDIK
--outer-6f3a--
The parser returned:
multipart/mixed
multipart/alternative
text/plain
multipart/related
text/html
image/png [inline]
text/csv [attachment]
defects: []
Zero parser defects does not promise identical rendering in every inbox. It confirms that the boundaries close, the containers nest as intended, and the parser sees the two resources in the roles I assigned.
Failure modes live at the boundaries
Every multipart delimiter starts at the beginning of a line. The closing delimiter adds two trailing hyphens. A nested multipart needs a boundary distinct from its parent, and RFC 2046, section 5.1.1 requires the chosen boundary not to occur as a delimiter inside a child part.
Content-Transfer-Encoding belongs on the leaf part containing the bytes. Text commonly uses quoted-printable or base64. Binary files usually use base64. RFC 2045, section 6.4 restricts composite entities such as multipart/* to identity encodings, so base64-encoding the outer container is the wrong layer.
When a message renders incorrectly, I would inspect these points in order:
- Does each container describe the relationship among its immediate children?
- Is the plain alternative first and the preferred rich alternative last?
- Does every
cid:reference match oneContent-IDinside the same related group? - Does every leaf declare the correct media type, charset where relevant, transfer encoding, and disposition?
- Are there two CRLF sequences between each part’s headers and body?
- Are all boundaries unique, non-colliding, and closed?
Serialization order also matters for signing. If a relay, template layer, or tracking system rewrites the MIME body after DKIM signing, the receiver can compute a different body hash. The DKIM body-hash guide shows how to locate that modifying hop.
Let the library serialize it, then inspect the result
A fair objection is that modern mail libraries already build MIME. Usually they should. A mature library generates boundaries, chooses transfer encodings, and serializes CRLF more safely than handwritten string templates.
The library still needs the right relationships. It cannot always infer whether an image is a true attachment or an inline resource, whether two bodies are alternatives, or which HTML part owns a Content-ID. Provider SDKs and downstream mail systems can also wrap or modify what the library produced.
Use the high-level methods for alternatives, inline resources, and attachments. Then inspect one raw message and reduce it to the tree. When an inline image becomes a download, both body versions appear, or an attachment vanishes, the tree shows which relationship was lost.