Send an email with attachements by JavaMailSender from SpringFramework

    This is a short “how to” article about sending emails with SpringFramework. I will provide couple examples and I will show a popular problem.

    It is an easy task could be implemented like this:

    publicvoidsend(String subject, String from, String to, File file)throws MessagingException {
       MimeMessage message = javaMailSender.createMimeMessage();
       MimeMessageHelper helper = new MimeMessageHelper(message, true);
       helper.setSubject(subject);
       helper.setFrom(from);
       helper.setTo(to);
       helper.setReplyTo(from);
       helper.setText("stub", false);
       helper.addAttachment("document.txt", file);
       javaMailSender.send(message);
    }

    But it is a not typical situation when the web application works with the file system directly. Let’s consider the example when we create the document in memory and we want to attach it to our email.

    There are couple of methods in the MimeMessageHelper class that could help us:

    publicclassMimeMessageHelper{
         ...
         publicvoidaddAttachment(String attachmentFilename, InputStreamSource inputStreamSource){ 
             ...
         }
         publicvoidaddAttachment(String attachmentFilename, DataSource dataSource)throws MessagingException {
             ...
         }
    }
    

    Let's see some examples.

    1. Attachment is an InputStreamSource interface

    It is a tricky one, because in that case the developer could get an IllegalArgumentException with a message:

    "Passed-in Resource contains an open stream: invalid argument. JavaMail requires an InputStreamSource that creates a fresh stream for every call."

    It happens because there is a special check in the method MimeMessageHelper#addAttachment():

    if (inputStreamSource instanceof Resource && ((Resource) inputStreamSource).isOpen()) {
       thrownew IllegalArgumentException(
             "Passed-in Resource contains an open stream: invalid argument. " +
             "JavaMail requires an InputStreamSource that creates a fresh stream for every call.");
    }
    

    For example, the implementation InputStreamResource always return true from the method isOpen() that makes impossible to use this implementation as an attachment:

    publicclassInputStreamResourceextendsAbstractResource{
       //...@OverridepublicbooleanisOpen(){
          returntrue;
       }
       //...
    }

    The working example is:

    publicvoidsend(){
       try {
          final ByteArrayOutputStream stream = createInMemoryDocument("test document text");
          final InputStreamSource attachment = new ByteArrayResource(stream.toByteArray());
          sendMimeMessageWithAttachments(
                "subject",
                "random@random.com",
                "random@random.com",
                attachment);
       } catch (IOException | MailException | MessagingException e) {
          logger.warn(e.getMessage(), e);
       }
    }
    privatevoidsendMimeMessageWithAttachments(String subject, String from, String to, InputStreamSource source)throws MessagingException {
       MimeMessage message = javaMailSender.createMimeMessage();
       MimeMessageHelper helper = new MimeMessageHelper(message, true);
       helper.setSubject(subject);
       helper.setFrom(from);
       helper.setTo(to);
       helper.setReplyTo(from);
       helper.setText("stub", false);
       helper.addAttachment("document.txt", source);
       javaMailSender.send(message);
    }
    private ByteArrayOutputStream createInMemoryDocument(String documentBody)throws IOException {
       ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
       outputStream.write(documentBody.getBytes());
       return outputStream;
    }
    

    2. Attachment is a DataSource interface

    This example does not contain pitfalls and pretty clear:

    publicvoidsend(){
       try {
          final ByteArrayOutputStream document = createInMemoryDocument("test document text");
          final InputStream inputStream = new ByteArrayInputStream(document.toByteArray());
          final DataSource attachment = new ByteArrayDataSource(inputStream, "application/octet-stream");
    sendMimeMessageWithAttachments(
                "subject",
                "anonymous@xyz-mail.com",
                "anonymous@xyz-mail.com",
                attachment);
       } catch (IOException | MailException | MessagingException e) {
          logger.warn(e.getMessage(), e);
       }
    }
    privatevoidsendMimeMessageWithAttachments(String subject, String from, String to, DataSource dataSource)throws MessagingException {
       MimeMessage message = javaMailSender.createMimeMessage();
       MimeMessageHelper helper = new MimeMessageHelper(message, true);
       helper.setSubject(subject);
       helper.setFrom(from);
       helper.setTo(to);
       helper.setReplyTo(from);
       helper.setText("stub", false);
       helper.addAttachment("document.txt", dataSource);
       javaMailSender.send(message);
    }
    

    It would be helpful to have a look at the spring reference chapter.

    Also popular now: