Search code examples
imagejakarta-mailinlinemime

Javamail multiparts not ordered correctly


I have an application that attempts to dynamically build a Javamail message, assembling Mime body parts that are available at mail time. Each image is to have a 'GPC' image at the top, followed by some HTML text(body), a closing constructed by HTML, a closing 'Brand' image, and final part of the closing, also in HTML. File attachments may or may not be included. An error disclaimer(HTML) may precede the first image if applicable.

The disclaimer, body, closing, & attachment(s) are body parts, while the images are nested multiparts, consisting of HTML containers holding CIDs, and the image body parts themselves. When the email is sent, it appears correct in Gmail & Lotus Notes, while in Outlook(Hotmail) the GPC image is overwritten at the top by the Brand image. The order of the body parts is preserved, with the exception of the images, which always seem to revert to the top.

I cannot figure this out. It seems to me that the 'parent' multipart should be subtype 'Mixed' as the order of the body parts is important, and they are relatively unrelated, whereas the nested multiparts are 'Related' as one body part references the other. My code:

public MimeMultipart email_content_builder() throws MessagingException {
   MimeMultipart mp = new MimeMultipart();
   MimeBodyPart txt_part = new MimeBodyPart(), att_part, err_part, gpc_img_location_part, gpc_img_part, brand_img_location_part, brand_img_part, closing_pt1_part, closing_pt2_part;
   DataSource att_source, gpc_img_src, brand_img_src;
   String gpc_img_container_html, brand_img_container_html;

  //Insert error disclaimer, if applicable:
   if (!error_disclaimer.isEmpty()) {
      err_part = new MimeBodyPart();
      err_part.setText(error_disclaimer, "ISO-8859-1", "html");
      mp.addBodyPart(err_part);
   }

  //Insert GPC logo image, if applicable:
   if (GPC_logo.length > 0) {
      MimeMultipart gpc_imagery_mp = new MimeMultipart("related");
      MimeBodyPart gpc_imagery_part = new MimeBodyPart();

     //When resizing the GPC image, the height should be roughly 23% of the width;  use this factor:  .2331
      gpc_img_container_html = "<html><body><img src='cid:gpc_logo' height=\"23px\" width=\"100px\"></body></html>";

      gpc_img_location_part = new MimeBodyPart();
      gpc_img_location_part.setContent(gpc_img_container_html, "text/html");

      gpc_imagery_mp.addBodyPart(gpc_img_location_part);

      gpc_img_part = new MimeBodyPart();
      gpc_img_src = new ByteArrayDataSource(GPC_logo, "image/jpeg");
      gpc_img_part.setDataHandler(new DataHandler(gpc_img_src));
      gpc_img_part.setHeader("Content-ID", "<gpc_logo>");
      gpc_img_part.setDisposition(MimeBodyPart.INLINE);

      gpc_imagery_mp.addBodyPart(gpc_img_part);
      gpc_imagery_part.setContent(gpc_imagery_mp);
      mp.addBodyPart(gpc_imagery_part);
   }

  //Insert main body of email:
   txt_part.setText(body, "ISO-8859-1", "html");
   mp.addBodyPart(txt_part);

  //Insert the first part of the closing, if applicable:
   if (!Closing_Part1.isEmpty()) {
      closing_pt1_part = new MimeBodyPart();
      closing_pt1_part.setText(Closing_Part1, "ISO-8859-1", "html");
      mp.addBodyPart(closing_pt1_part);
   }

  //Insert brand logo image, if applicable:
   if (brand_logo.length > 0) {
      MimeMultipart brand_imagery_mp = new MimeMultipart("related");
      MimeBodyPart brand_imagery_part = new MimeBodyPart();

     //When resizing the brand image, the height should be roughly 43% of the width;  use this factor:  .4294
      brand_img_container_html = "<html><body><img src='cid:brand_logo' height=\"64px\" width=\"150px\"></body></html>";

      brand_img_location_part = new MimeBodyPart();
      brand_img_location_part.setContent(brand_img_container_html, "text/html");

      brand_imagery_mp.addBodyPart(brand_img_location_part);

      brand_img_part = new MimeBodyPart();
      brand_img_src = new ByteArrayDataSource(brand_logo, "image/jpeg");
      brand_img_part.setDataHandler(new DataHandler(brand_img_src));
      brand_img_part.setHeader("Content-ID", "<brand_logo>");
      brand_img_part.setDisposition(MimeBodyPart.INLINE);

      brand_imagery_mp.addBodyPart(brand_img_part);
      brand_imagery_part.setContent(brand_imagery_mp);
      mp.addBodyPart(brand_imagery_part);
   }

  //Insert the second part of the closing, if applicable:
   if (!Closing_Part2.isEmpty()) {
      closing_pt2_part = new MimeBodyPart();
      closing_pt2_part.setText(Closing_Part2, "ISO-8859-1", "html");
      mp.addBodyPart(closing_pt2_part);
   }

  //Insert attachments, if applicable:
   if (attachments != null) {
      for (int j = 0; j < attachments.size(); j++) {
         att_part = new MimeBodyPart();

         att_source = new FileDataSource((attachments.get(j)).getPath());
         att_part.setDataHandler(new DataHandler(att_source));
         att_part.setFileName((attachments.get(j)).getPath());

         mp.addBodyPart(att_part);
      }
   }
   return mp;
}

Solution

  • You have very limited control over how different mail readers will display the multiple body parts in your message. You best bet is to put all of the non-attachment content into a single text/html body part, using html to format the message. You can include images in your message using multipart/related, but it's often simpler to reference images on the web.