Messages and MIME

MIME types and transfer encodings

Describe message content with media types, character sets, and safe transfer encodings.

The original message format only knew plain ASCII text. No accents, no images, no PDFs. MIME fixed that by adding a few header fields that describe what the body contains and how it was packaged.

The fields are MIME-Version, Content-Type, and Content-Transfer-Encoding. Let’s see what each one does.

Content-Type says what it is

Content-Type: text/plain; charset=utf-8 tells the reader two things. The media type is plain text. The charset is UTF-8, so the reader knows how to turn bytes into characters.

Other media types you’ll see: text/html, image/png, application/pdf. Same idea as HTTP.

Content-Transfer-Encoding says how it travels

SMTP was built for 7-bit ASCII lines of limited length. Anything else has to be made safe for that channel. Two encodings do this.

quoted-printable keeps text readable. Normal ASCII stays as-is, and every other byte becomes = plus two hex digits. It’s great for text that’s mostly ASCII with a few accents.

base64 turns any bytes into ASCII letters, digits, + and /. It adds about 33% overhead, but it handles a PDF or a JPEG without caring what’s inside.

Here is a small part with both fields:

Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable

The caf=C3=A9 opens at 08:00.

To read it, the decoder works in two steps. First it undoes quoted-printable: =C3=A9 becomes the bytes C3 A9. Then it applies the charset: in UTF-8 those two bytes are é. The result is “The café opens at 08:00.”

Why the two jobs must stay separate

The transfer encoding is about transport. The charset is about meaning. Mix them up and you get mojibake, the garbled text you’ve seen in badly encoded emails.

Assume ISO-8859-1 instead of UTF-8 on the example above and C3 A9 becomes two characters, é. The bytes were fine. The interpretation was wrong.

Always decode in order: transfer encoding first, then charset.

Base64 is not encryption

I hear this confusion a lot. Base64 hides nothing. Anyone with the message can decode it instantly. If you need confidentiality, that’s a different tool entirely.

Don’t trust the label

Content-Type: image/png is a claim, not a fact. A sender can label an executable as an image. When your application receives attachments, inspect the actual bytes, enforce size limits, and never execute or render them in a privileged context because the label said so.

Try decoding caf=C3=A9 by hand in two steps: quoted-printable to bytes, then UTF-8 to text. Then redo the second step as ISO-8859-1 and see the garbage come out.

Lesson completed