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:
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:
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():
For example, the implementation InputStreamResource always return true from the method isOpen() that makes impossible to use this implementation as an attachment:
The working example is:
2. Attachment is a DataSource interface
This example does not contain pitfalls and pretty clear:
It would be helpful to have a look at the spring reference chapter.
It is an easy task could be implemented like this:
public void send(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:
public class MimeMessageHelper {
...
public void addAttachment(String attachmentFilename, InputStreamSource inputStreamSource) {
...
}
public void addAttachment(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()) {
throw new 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:
public class InputStreamResource extends AbstractResource {
//...
@Override
public boolean isOpen() {
return true;
}
//...
}
The working example is:
public void send() {
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);
}
}
private void sendMimeMessageWithAttachments(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:
public void send() {
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);
}
}
private void sendMimeMessageWithAttachments(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.