December 17th, 2012

Update – if you’re using Tomcat and want to use JNDI then follow this post instead

Sending email via Mandrill from a Java web server

We’ve decided to do a bit of experimentation of using Mandrill to send all our transactional emails from our Java web server.  We already use Mailchimp for our mailing list and it offers an integration with Mandrill.  I found it a little harder than I’d expected to use Javamail with SMTP authentication and so I thought I’d post a quick how to.

Connecting using an Authenticator

After running up against a bug in JavaMail when saving a PasswordAuthentication (see below) my preferred approach is now to use an javax.mail.Authenticator to connect. You must ensure you set the session property mail.smtp.auth=true first.

mailProperties.setProperty("mail.transport.protocol", "smtp"); mailProperties.setProperty("mail.smtp.host", host); mailProperties.setProperty("mail.smtp.port", String.valueOf(port)); mailProperties.setProperty("mail.smtp.user", username); mailProperties.setProperty("mail.smtp.auth", "true"); final Session session = Session.getInstance(mailProperties, new Authenticator() { @Override protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(username, password); } }); final MimeMessage msg = new MimeMessage(session); // set required message properties Transport.send(msg); 

Bug in JavaMail service for non standard SMTP ports?

The main reason I ran into difficultly was because Mandrill uses a non-standard SMTP port and I think there’s a bug in javax.mail.Service that is exposed in these circumstances.  One way to authenticate is to register a javax.mail.PasswordAuthentication for your connection’s javax.mail.URLName with your javax.mail.Session before calling javax.mail.Transport.send(msg). However if you use Transport.send() then the instance of URLName created to retrieve the PasswordAuthentication object will always use the standard port.  The version of JavaMail I discovered this in (by running a debuger) was 1.4.5.

Don’t specify a port in your URLName when registering your PasswordAuthentication

The solution is specify the default port in the URLName you build to register the PasswordAuthentication object, even if you’re actually connecting via a non-standard port.

mailProperties.setProperty("mail.transport.protocol", "smtp"); mailProperties.setProperty("mail.smtp.host", host); mailProperties.setProperty("mail.smtp.port", String.valueOf(port)); mailProperties.setProperty("mail.smtp.user", username); final Session session = Session.getInstance(mailProperties, null); session.setPasswordAuthentication(         new URLName("smtp", host, -1, null, username, null),         new PasswordAuthentication(username, password); final MimeMessage msg = new MimeMessage(session); // set required message properties Transport.send(msg);