Programming

Mail multipartalternative vs multipartmixed

27 September 2026 · 11 min read

Mail multipartalternative vs multipartmixed

Navigating the complexities of email communication often brings us face-to-face with technical terms that, while crucial, can seem daunting. One such area of confusion for many developers and marketers alike revolves around the distinctions between Mail multipart/alternative vs multipart/mixed. Understanding these MIME (Multipurpose Internet Mail Extensions) types is fundamental to crafting emails that are not only delivered successfully but also rendered correctly across diverse email clients and devices. This guide will delve into the nuances of each, explaining their purpose, typical use cases, and how they contribute to a robust email experience, ensuring your messages are always presented as intended, whether they contain simple text, rich HTML, or vital attachments.

Understanding MIME and Email Structure

At its core, email is much more than just plain text. The internet mail system, as we know it today, relies heavily on MIME standards to describe the content type of a message. Before MIME, emails were largely restricted to ASCII text, making rich formatting, images, and attachments impossible. The introduction of MIME in the early 1990s revolutionized email, allowing for the transmission of virtually any kind of file or content, from HTML documents to images, audio, and video.

A “multipart” message is essentially an email that contains multiple distinct parts, each with its own content type and encoding. These parts are separated by a unique boundary string. The primary MIME type of the overall message dictates how these individual parts should be interpreted and presented by the email client. This foundational understanding is critical for anyone looking to optimize their email delivery and presentation, as the choice between multipart/alternative and multipart/mixed directly impacts how recipients interact with your message content and any included email attachments.

The flexibility offered by MIME types allows email creators to send highly sophisticated communications. For instance, an email could simultaneously offer a plain-text version for accessibility, an HTML version for visual appeal, and even include a calendar invitation. Without MIME, such versatility would be impossible, severely limiting the functionality and user experience of modern email. According to the Internet Engineering Task Force (IETF) RFC 2045, MIME provides a standardized way to describe the content type, encoding, and structure of email messages, forming the backbone of rich email protocols.

The Role of multipart/alternative

The multipart/alternative MIME type is designed to offer multiple versions of the same content, allowing the email client to choose the best representation for the user. Think of it as providing options for displaying a single piece of information. The most common application of multipart/alternative is to send both a plain text version and an HTML version of an email. The plain text part serves as a fallback for older clients, recipients who prefer text-only emails, or those with accessibility needs, while the HTML part provides rich formatting, images, and links.

When an email client receives a multipart/alternative message, it is instructed to display the “richest” part it understands. For example, if a client supports HTML, it will typically render the HTML part. If it only supports plain text, it will display the plain text part. This mechanism ensures maximum compatibility and a graceful degradation of the email experience across various platforms. Neglecting to include a plain text alternative can lead to poor email rendering for some users, or even prevent the email from being displayed at all.

To ensure your emails are universally accessible and render correctly for all recipients, always include both a plain text and an HTML version within a multipart/alternative container. Email clients will automatically prioritize the richest format they can display, typically the HTML version, while providing the plain text as a fallback. This practice significantly improves deliverability and user experience, especially for those using assistive technologies or older email software. This strategy is crucial for effective content negotiation between sender and receiver, ensuring the email client can select the most appropriate email formatting.

  1. Craft the Plain Text Content: Write the core message in simple, unformatted text. This ensures readability for all.
  2. Develop the HTML Content: Create the visually rich version with styling, images, and active links.
  3. Set the Content-Type Header: The parent header for the entire message will be Content-Type: multipart/alternative; boundary="YOUR_BOUNDARY_STRING".
  4. Define Parts with Boundaries: Each part (plain text, HTML) is introduced by your chosen boundary string, followed by its specific Content-Type (e.g., text/plain or text/html) and content.
  5. Order by Richness: It’s best practice to list the plain text part first, followed by the HTML part. This might seem counterintuitive, but some older clients process parts in order and stop at the first one they recognize. Modern clients typically scan all parts and pick the richest.

The Power of multipart/mixed

In contrast to multipart/alternative, the multipart/mixed MIME type is used when an email contains different types of content that are all intended to be displayed or accessed by the user. The most common use case for multipart/mixed is when you want to send an email with email attachments. Here, the main body of the message (which itself might be multipart/alternative with plain text and HTML versions) is one part, and each attachment is another distinct part.

When an email client receives a multipart/mixed message, it is instructed to display all the parts, generally in the order they appear. This means the recipient will see the email body and then typically a list of attachments that they can download or view. Each attachment will have its own Content-Type header, specifying its format (e.g., image/jpeg, application/pdf, application/zip), and often a Content-Disposition header indicating if it’s an attachment or inline content.

Consider a scenario where you’re sending a project update. Your email might include an HTML formatted message, a plain text fallback, and then a PDF report and a spreadsheet as attachments. This entire structure would fall under a multipart/mixed parent, where one of its parts is a multipart/alternative body, and the other parts are the PDF and spreadsheet files. This structure allows for comprehensive content delivery, ensuring all necessary information and files reach the recipient in a unified package.

According to email protocol standards, handling attachments via multipart/mixed ensures that binary data is correctly encoded (often using Base64) to be transmitted safely over text-based email systems. This robust mechanism is what allows users to send and receive documents, images, and other file uploads without corruption. For a deeper dive into the specifics of MIME types and their implementation, the IETF RFC 2046 offers comprehensive technical details.

Key Differences and When to Use Each

The core distinction between Mail multipart/alternative vs multipart/mixed lies in their intent: multipart/alternative offers choices for the same content, while multipart/mixed bundles different pieces of content together. If you’re providing different representations of the exact same message (e.g., plain text vs. HTML), multipart/alternative is the correct choice. It signals to the email client, “Here are several ways to show the user this message; pick the best one you support.” This is essential for ensuring robust email client compatibility and an optimal user experience.

Conversely, if you’re sending distinct items – like an email body plus one or more files – multipart/mixed is what you need. It tells the email client, “Here are multiple, different parts that should all be presented to the user.” A common real-world example is an invoice email that includes both the invoice details in the email body (potentially as a multipart/alternative HTML/plain text) and the actual PDF invoice attached Question & Answer :

When creating email messages you are supposed to set the Content-Type to multipart/alternative when sending HTML and TEXT or multipart/mixed when sending TEXT and attachments.

So what do you do if you want to send HTML, Text, and attachments? Use both?

I hit this challenge today and I found these answers useful but not quite explicit enough for me.

Edit: Just found the Apache Commons Email that wraps this up nicely, meaning you don’t need to know below.

If your requirement is an email with:

  1. text and html versions
  2. html version has embedded (inline) images
  3. attachments

The only structure I found that works with Gmail/Outlook/iPad is:

  • mixed
    • alternative
      • text
      • related
        • html
        • inline image
        • inline image
    • attachment
    • attachment

And the code is:

import javax.activation.DataHandler; import javax.activation.DataSource; import javax.activation.URLDataSource; import javax.mail.BodyPart; import javax.mail.MessagingException; import javax.mail.Multipart; import javax.mail.internet.MimeBodyPart; import javax.mail.internet.MimeMultipart; import java.net.URL; import java.util.HashMap; import java.util.List; import java.util.UUID; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Created by StrongMan on 25/05/14. */ public class MailContentBuilder { private static final Pattern COMPILED_PATTERN_SRC_URL_SINGLE = Pattern.compile("src='([^']*)'", Pattern.CASE_INSENSITIVE); private static final Pattern COMPILED_PATTERN_SRC_URL_DOUBLE = Pattern.compile("src=\"([^\"]*)\"", Pattern.CASE_INSENSITIVE); /** * Build an email message. * * The HTML may reference the embedded image (messageHtmlInline) using the filename. Any path portion is ignored to make my life easier * e.g. If you pass in the image C:\Temp\dog.jpg you can use <img src="dog.jpg"/> or <img src="C:\Temp\dog.jpg"/> and both will work * * @param messageText * @param messageHtml * @param messageHtmlInline * @param attachments * @return * @throws MessagingException */ public Multipart build(String messageText, String messageHtml, List<URL> messageHtmlInline, List<URL> attachments) throws MessagingException { final Multipart mpMixed = new MimeMultipart("mixed"); { // alternative final Multipart mpMixedAlternative = newChild(mpMixed, "alternative"); { // Note: MUST RENDER HTML LAST otherwise iPad mail client only renders the last image and no email addTextVersion(mpMixedAlternative,messageText); addHtmlVersion(mpMixedAlternative,messageHtml, messageHtmlInline); } // attachments addAttachments(mpMixed,attachments); } //msg.setText(message, "utf-8"); //msg.setContent(message,"text/html; charset=utf-8"); return mpMixed; } private Multipart newChild(Multipart parent, String alternative) throws MessagingException { MimeMultipart child = new MimeMultipart(alternative); final MimeBodyPart mbp = new MimeBodyPart(); parent.addBodyPart(mbp); mbp.setContent(child); return child; } private void addTextVersion(Multipart mpRelatedAlternative, String messageText) throws MessagingException { final MimeBodyPart textPart = new MimeBodyPart(); textPart.setContent(messageText, "text/plain"); mpRelatedAlternative.addBodyPart(textPart); } private void addHtmlVersion(Multipart parent, String messageHtml, List<URL> embeded) throws MessagingException { // HTML version final Multipart mpRelated = newChild(parent,"related"); // Html final MimeBodyPart htmlPart = new MimeBodyPart(); HashMap<String,String> cids = new HashMap<String, String>(); htmlPart.setContent(replaceUrlWithCids(messageHtml,cids), "text/html"); mpRelated.addBodyPart(htmlPart); // Inline images addImagesInline(mpRelated, embeded, cids); } private void addImagesInline(Multipart parent, List<URL> embeded, HashMap<String,String> cids) throws MessagingException { if (embeded != null) { for (URL img : embeded) { final MimeBodyPart htmlPartImg = new MimeBodyPart(); DataSource htmlPartImgDs = new URLDataSource(img); htmlPartImg.setDataHandler(new DataHandler(htmlPartImgDs)); String fileName = img.getFile(); fileName = getFileName(fileName); String newFileName = cids.get(fileName); boolean imageNotReferencedInHtml = newFileName == null; if (imageNotReferencedInHtml) continue; // Gmail requires the cid have <> around it htmlPartImg.setHeader("Content-ID", "<"+newFileName+">"); htmlPartImg.setDisposition(BodyPart.INLINE); parent.addBodyPart(htmlPartImg); } } } private void addAttachments(Multipart parent, List<URL> attachments) throws MessagingException { if (attachments != null) { for (URL attachment : attachments) { final MimeBodyPart mbpAttachment = new MimeBodyPart(); DataSource htmlPartImgDs = new URLDataSource(attachment); mbpAttachment.setDataHandler(new DataHandler(htmlPartImgDs)); String fileName = attachment.getFile(); fileName = getFileName(fileName); mbpAttachment.setDisposition(BodyPart.ATTACHMENT); mbpAttachment.setFileName(fileName); parent.addBodyPart(mbpAttachment); } } } public String replaceUrlWithCids(String html, HashMap<String,String> cids) { html = replaceUrlWithCids(html, COMPILED_PATTERN_SRC_URL_SINGLE, "src='cid:@cid'", cids); html = replaceUrlWithCids(html, COMPILED_PATTERN_SRC_URL_DOUBLE, "src=\"cid:@cid\"", cids); return html; } private String replaceUrlWithCids(String html, Pattern pattern, String replacement, HashMap<String,String> cids) { Matcher matcherCssUrl = pattern.matcher(html); StringBuffer sb = new StringBuffer(); while (matcherCssUrl.find()) { String fileName = matcherCssUrl.group(1); // Disregarding file path, so don't clash your filenames! fileName = getFileName(fileName); // A cid must start with @ and be globally unique String cid = "@" + UUID.randomUUID().toString() + "_" + fileName; if (cids.containsKey(fileName)) cid = cids.get(fileName); else cids.put(fileName,cid); matcherCssUrl.appendReplacement(sb,replacement.replace("@cid",cid)); } matcherCssUrl.appendTail(sb); html = sb.toString(); return html; } private String getFileName(String fileName) { if (fileName.contains("/")) fileName = fileName.substring(fileName.lastIndexOf("/")+1); return fileName; } } 

And an example of using it with from Gmail

/** * Created by StrongMan on 25/05/14. */ import com.sun.mail.smtp.SMTPTransport; import java.net.URL; import java.security.Security; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.activation.DataHandler; import javax.activation.DataSource; import javax.activation.URLDataSource; import javax.mail.*; import javax.mail.internet.*; /** * * http://stackoverflow.com/questions/14744197/best-practices-sending-javamail-mime-multipart-emails-and-gmail * http://stackoverflow.com/questions/3902455/smtp-multipart-alternative-vs-multipart-mixed * * * * @author doraemon */ public class GoogleMail { private GoogleMail() { } /** * Send email using GMail SMTP server. * * @param username GMail username * @param password GMail password * @param recipientEmail TO recipient * @param title title of the message * @param messageText message to be sent * @throws AddressException if the email address parse failed * @throws MessagingException if the connection is dead or not in the connected state or if the message is not a MimeMessage */ public static void Send(final String username, final String password, String recipientEmail, String title, String messageText, String messageHtml, List<URL> messageHtmlInline, List<URL> attachments) throws AddressException, MessagingException { GoogleMail.Send(username, password, recipientEmail, "", title, messageText, messageHtml, messageHtmlInline,attachments); } /** * Send email using GMail SMTP server. * * @param username GMail username * @param password GMail password * @param recipientEmail TO recipient * @param ccEmail CC recipient. Can be empty if there is no CC recipient * @param title title of the message * @param messageText message to be sent * @throws AddressException if the email address parse failed * @throws MessagingException if the connection is dead or not in the connected state or if the message is not a MimeMessage */ public static void Send(final String username, final String password, String recipientEmail, String ccEmail, String title, String messageText, String messageHtml, List<URL> messageHtmlInline, List<URL> attachments) throws AddressException, MessagingException { Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider()); final String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory"; // Get a Properties object Properties props = System.getProperties(); props.setProperty("mail.smtps.host", "smtp.gmail.com"); props.setProperty("mail.smtp.socketFactory.class", SSL_FACTORY); props.setProperty("mail.smtp.socketFactory.fallback", "false"); props.setProperty("mail.smtp.port", "465"); props.setProperty("mail.smtp.socketFactory.port", "465"); props.setProperty("mail.smtps.auth", "true"); /* If set to false, the QUIT command is sent and the connection is immediately closed. If set to true (the default), causes the transport to wait for the response to the QUIT command. ref : http://java.sun.com/products/javamail/javadocs/com/sun/mail/smtp/package-summary.html http://forum.java.sun.com/thread.jspa?threadID=5205249 smtpsend.java - demo program from javamail */ props.put("mail.smtps.quitwait", "false"); Session session = Session.getInstance(props, null); // -- Create a new message -- final MimeMessage msg = new MimeMessage(session); // -- Set the FROM and TO fields -- msg.setFrom(new InternetAddress(username + "@gmail.com")); msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(recipientEmail, false)); if (ccEmail.length() > 0) { msg.setRecipients(Message.RecipientType.CC, InternetAddress.parse(ccEmail, false)); } msg.setSubject(title); // mixed MailContentBuilder mailContentBuilder = new MailContentBuilder(); final Multipart mpMixed = mailContentBuilder.build(messageText, messageHtml, messageHtmlInline, attachments); msg.setContent(mpMixed); msg.setSentDate(new Date()); SMTPTransport t = (SMTPTransport)session.getTransport("smtps"); t.connect("smtp.gmail.com", username, password); t.sendMessage(msg, msg.getAllRecipients()); t.close(); } }