JavaMail API: Message in EML format

JavaMail API: Message in EML format

Our application was already using JavaMail (javax.mail.*) as a way to inform our users. But for logging purposes we wanted to store all the emails we send in our database (and make them downloadable using our GUI).

It turns out this is pretty easy to do!

Let’s start with some very basic email code we already had in place:

    // Some method to construct a MimeMessage:
    Message message = createMailMessage(input);

    Transport.send(message);

What we need to do now is to ‘render’ the entire email in a binary format, including all the possible attachements, multipart things, from and to headers etc.

It turns out there is a convinient method for doing just that: message.writeTo(OutputStream)

    Message message = createMailMessage(input); // some method to construct a MimeMessage

    // Retrieve the entire message as byte[]:
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    message.writeTo(out);
    byte[] contents = out.toByteArray();

    // Next we store the byte[] in our database (JPA) entity:
    ArchivedMail archivedMail = new ArchivedMail(sender, contents, LocalDateTime.now());
    mailArchive.store(archivedMail);

    Transport.send(message);

Our own little POJO entity (ArchivedMail) is stored in the database with some additional information that allows us to search the messages. The final step is to make a download link and present the email in a readable format to the users.

We’re using Wicket and thus the following example is Wicket code, but you could just as easily create a Servlet to return the data:

    // Add the Wicket link-component to our page:
    add(new Link<ArchivedMail>("wicketLinkId", Model.of(somemail)) {

        @Override
        public void onClick() {
            IResourceStream resourceStream = new AbstractResourceStreamWriter() {
                @Override
                public void write(OutputStream output) throws IOException {
                    // When clicked output a stream which contains the raw byte[]:
                    output.write(getModelObject().getBytes());
                }

                @Override
                public String getContentType() {
                    // Add the content type for an EML file:
                    return "message/rfc822";
                }
            };

            // Schedule the handler to return our resource stream (with a fancy name):
            getRequestCycle().scheduleRequestHandlerAfterCurrent(
                new ResourceStreamRequestHandler(resourceStream).setFileName("mail.eml"));
        }
    });

Conclusion

Using JavaMail (javax.mail) it is very easy to get the ‘raw’ contents of an email when sending it.

This can be stored and downloaded in EML-format. It contains everything you need, mime, multipart, attachements and all the from/to headers.

Happy coding!