Welcome

How to Attach Zipped Content While Sending Mail

One of the things I most like about Spring is its approach in bringing a high level, easy to understand and use interface and configurability to several gradually lower level APIs of Java, such as JavaMail, JMS, JNDI and so on. Several days ago, a collegue of mine asked me whether I had any experience with sending mails using JavaMail, but also attaching some runtime created content after zipping it.

Since I met with Spring Application Framework, I never attempt solving problems directly without first reviewing Spring Reference to see if it provides any solution for my problem at hand; and mostly it does!

This time it is about using JavaMail to send attached mails. Well, Spring has a nice layer on top of JavaMail API, to configure and send several types of mails, ranging from simple content, to html content with inline resources. To use JavaMail in your program via Spring support, you only need to configure a bean with class org.springframework.mail.javamail.JavaMailSenderImpl, and reference it either via its MailSender or JavaMailSender interfacein your code. MailSender interface is just for sending simple mail messages.If you need MIME support, for example, to attach file as in our case here, you will need to access the mailer bean through its JavaMailSender interface.

	
<bean id="javaMailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
    <property name="host">
        <value>localhost</value>
    </property>
    <property name="port">
        <value>25</value>
    </property>
    <property name="username">
        <value>ksevindik</value>
    </property>
    <property name="password">
        <value>secret</value>
    </property>
    <property name="javaMailProperties">
        <props>
            <prop key="mail.smtp.auth">false</prop>
        </props>
    </property>
</bean>	

I will show you a simple test case to send a mail using javaMailSender bean configured above. I like to inject beans using @Autowired annotation in my Spring integration tests. You don’t need any setter method at all. You can inject dependencies to private properties.

@Autowired
private JavaMailSender javaMailSender;

@Test
public void sendMailWithAttachmentContentPreparedOnTheFly() throws Exception {

MimeMessage message = javaMailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setFrom("ksevindik@ems.com");
helper.setTo("developers@ems.com");
helper.setSubject("on the fly attachment test");
helper.setText("this is normal message body text");

Up to here, all we did is creating a javax.mail.internet.MimeMessage object from javaMailSender bean, then wrapping it with org.springframework.mail.javamail.MimeMessageHelper, and setting its from, to, subject properties, and writing message body via this helper. This is very similar to sending simple mail messages. MimeMessageHelper does most of the hard work. Apart from attachments, it also has support for html content, and inline images etc. It provides with several methods for adding attachments to the current message. What we need to do here is to deliver attachment content as a stream which is created on the fly.

ByteArrayOutputStream bout = new ByteArrayOutputStream();
ZipOutputStream zout = new ZipOutputStream(bout);
zout.putNextEntry(new ZipEntry("test.txt"));
zout.write("this is zipped content".getBytes("utf-8"));
zout.closeEntry();
zout.close();
helper.addAttachment("test.zip", new ByteArrayResource(bout.toByteArray()));

First, we created zipped content using Java ByteArrayOutputStream and ZipOutputStream classes, then passed the content as org.springframework.core.io.ByteArrayResource to MimeMessageHelper. Content type is determined from given filename (“test.zip”) which actually for this case doesn’t exist physically.

SimpleSmtpServer mockSmtpServer = SimpleSmtpServer.start(25);
javaMailSender.send(message);
mockSmtpServer.stop();

I use Dumbster fake smtp server for testing purposes. After starting smtp server, I just send mail via javaMailSender, and then stop the server again.

TestCase.assertEquals("There should be one received message",1,smtpServer.getReceivedEmailSize());
SmtpMessage receivedMessage = (SmtpMessage) smtpServer.getReceivedEmail().next();
TestCase.assertTrue(receivedMessage.toString().contains("Content-Type: application/zip; name=test.zip"));

We can check Dumbster if any message is received, and check message headers, or body against what we expect to be in there. As you see, you are just isolated from all the hard work related with preparing MimeParts and other boring issues by using MimeMessageHelper. Is it rocket science? Definetely not, but you most probably are not paid for playing constantly with such middleware stuff either!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.