Sending html mails with embedded pictures, that Thunderbird can understand

Users of Thunderbird have for long known, that html messages with embedded content look “strange” – you see a list of attachments part1.1, part1.2 – when you click on one of them, you see the html text message, or the pictures that should have been embedded.

I have just discovered a way of sending html mails with embedded pictures, that Thunderbird can display correctly. I use Java 6, and the javax.mail package.

Basically, you need to build a mime message in the following format:

<multipart alternative>

<mimebodypart:empty text>

<multipart related>

<mimebodypart:html cid:picture_1, cid:picture_2, … >

<mimebodypart:content-id=picture_1>

</multipart related>

</multipart alternative>

Here is how to do it in Java code.

import javax.activation.DataHandler;
import javax.activation.URLDataSource;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

// ... some other stuff
public Message getAsMessage(Session session) {
try {
Message message = new MimeMessage(session);
// set subject
message.setSubject(subject);
// set the from and to address
InternetAddress addressFrom = new InternetAddress(from);
message.setFrom(addressFrom);

InternetAddress[] addressTo = new InternetAddress[to.length];
for (int i = 0; i < addressTo.length; i++) {
addressTo[i] = new InternetAddress(to[i]);
}
message.setRecipients(Message.RecipientType.TO, addressTo);

//create top multipart
MimeMultipart topMultipart = new MimeMultipart("alternative");
topMultipart.setSubType("mixed");

// prerprocess dynamic text

if( htmlTemplate != null ){
//create related multipart, wrap into bodypart, add html part
MimeMultipart relatedMultipart = new MimeMultipart("related");
MimeBodyPart relatedBodyPart = new MimeBodyPart();
relatedBodyPart.setContent(relatedMultipart);
topMultipart.addBodyPart(relatedBodyPart);

//load html part
BodyPart htmlBodyPart = loadPartContent(htmlTemplate, null);
preprocesText( htmlBodyPart, HTML);
// htmlBodyPart.setHeader("MIME-Version" , "1.0" );
// htmlBodyPart.setHeader("Content-Type" , htmlBodyPart.getContentType() );
relatedMultipart.addBodyPart(htmlBodyPart);

//fill up the related multipart with bodyparts for images
for (ImageContainer image : images) {
BodyPart imageBodyPart = loadPartContent(image.getUrl(), image.getContentId());
imageBodyPart.setDisposition("inline");
imageBodyPart.setFileName(image.getContentId());
relatedMultipart.addBodyPart(imageBodyPart);
}
}
if( textAlternative != null){
BodyPart alternativeTextBodyPart = loadPartContent(textAlternative, null);
preprocesText( alternativeTextBodyPart, PLAIN);
//add first poormans alternative, later the related part of the message
topMultipart.addBodyPart(alternativeTextBodyPart);
}

if( topMultipart.getCount() == 0){
MimeBodyPart emergency = new MimeBodyPart();
emergency.setText("No content");
topMultipart.addBodyPart(emergency);
}
message.setContent(topMultipart);
message.saveChanges();
return message;
} catch (MessagingException e) {
if (Optimization.LOG && LOG.isWarnEnabled()) {
LOG.warn("Could not create the mail message for session "
+ this);
}
return null;
}
}

Normally, alternative is used to enable mail-clients that do not understand html to select the text alternative. By setting the sub-type of the alternative multipart as “mixed”, this trick is forcing Thunderbird to display both (the empty) text message, and the html message.

Here follows the example in code:

Google interview

Well – it looks like I have passed the needles eye – and I am going to a personal interview at Google. Man, I am so excited about tomorrow. I can’t imagine a better place to work for a softwareengineer in 2008. Happy new year, everybody.