Why your multipart emails show up as plaintext

While building Electric Handshakes, a tool that connects job-hunters to employers via email, I spent days debugging an email problem. My code sent valid multipart emails – emails with both HTML and plaintext parts – but Gmail and showed the plaintext. Why?

I found my answer buried on page 35 of an RFC12. The order of the parts matters. Later parts override earlier ones. Your mail client will display the final part it understands. I’d placed my plaintext version after the HTML version. Swapping those sections fixed the problem.

Other common causes of errors include:

  • Sending an invalid multipart message. There’s a few online validators. Both of these declared my message to be invalid, but didn’t point out the ordering error above.
    • In particular, make sure you send a valid Content-Type header. The capitalisation matters, and the value should be multipart/alternative.
  • Sending invalid HTML. I expected a complete HTML document would be required - one with <html>, <head>, and <body> tags rather than just formatting. But there isn’t consensus on that. Microsoft Outlook sends full HTML documents, as does Yahoo Mail, Hotmail, and Apple’s But Gmail sends formatting only, with no document structure. I think such an email is technically invalid3, but every mail client renders it anyway. Gmail can send & store smaller emails by omitting the document structure.
    • Even without a fully-structured document, markup errors can still prevent your message from being displayed. Make sure all your tags are closed, you’ve closed them in the right order, and so on.

If you’re using Rails, you can take some email pain away by using the letter_opener gem to preview your mails in your browser, and the premailer-rails gem to inline your CSS. It can also generate your plaintext parts automatically, and generally does a decent job of it.

  1. “In general, user agents that compose multipart/alternative entities should place the body parts in increasing order of preference, that is, with the preferred format last. For fancy text, the sending user agent should put the plainest format first and the richest format last. Receiving user agents should pick and display the last format they are capable of displaying.”  ↩

  2. When you find yourself on page 35 of a standards document praying for answers, your day’s already blown.

  3. It’s invalid because the HTML part is declared as text/html, and you need the structural tags for your document to be valid HTML.  ↩