This section describes how to send email with the Spring Framework.
The Spring Framework provides a helpful utility library for sending email that shields you from the specifics of the underlying mailing system and is responsible for low-level resource handling on behalf of the client.
The org.springframework.mail
package is the root level package for the Spring
Framework’s email support. The central interface for sending emails is the MailSender
interface. A simple value object that encapsulates the properties of a simple mail such
as from
and to
(plus many others) is the SimpleMailMessage
class. This package
also contains a hierarchy of checked exceptions that provide a higher level of
abstraction over the lower level mail system exceptions, with the root exception being
MailException
. See the javadoc
for more information on the rich mail exception hierarchy.
The org.springframework.mail.javamail.JavaMailSender
interface adds specialized
JavaMail features, such as MIME message support to the MailSender
interface
(from which it inherits). JavaMailSender
also provides a callback interface called
org.springframework.mail.javamail.MimeMessagePreparator
for preparing a MimeMessage
.
Usage
Assume that we have a business interface called OrderManager
, as the following example shows:
-
Java
-
Kotlin
public interface OrderManager {
void placeOrder(Order order);
}
interface OrderManager {
fun placeOrder(order: Order)
}
Further assume that we have a requirement stating that an email message with an order number needs to be generated and sent to a customer who placed the relevant order.
Basic MailSender
and SimpleMailMessage
Usage
The following example shows how to use MailSender
and SimpleMailMessage
to send an
email when someone places an order:
-
Java
-
Kotlin
public class SimpleOrderManager implements OrderManager {
private MailSender mailSender;
private SimpleMailMessage templateMessage;
public void setMailSender(MailSender mailSender) {
this.mailSender = mailSender;
}
public void setTemplateMessage(SimpleMailMessage templateMessage) {
this.templateMessage = templateMessage;
}
@Override
public void placeOrder(Order order) {
// Do the business calculations...
// Call the collaborators to persist the order...
// Create a thread-safe "copy" of the template message and customize it
SimpleMailMessage msg = new SimpleMailMessage(this.templateMessage);
msg.setTo(order.getCustomer().getEmailAddress());
msg.setText(
"Dear " + order.getCustomer().getFirstName()
+ order.getCustomer().getLastName()
+ ", thank you for placing order. Your order number is "
+ order.getOrderNumber());
try {
this.mailSender.send(msg);
}
catch (MailException ex) {
// simply log it and go on...
System.err.println(ex.getMessage());
}
}
}
class SimpleOrderManager : OrderManager {
lateinit var mailSender: MailSender
lateinit var templateMessage: SimpleMailMessage
override fun placeOrder(order: Order) {
// Do the business calculations...
// Call the collaborators to persist the order...
// Create a thread-safe "copy" of the template message and customize it
val msg = SimpleMailMessage(this.templateMessage)
msg.setTo(order.customer.emailAddress)
msg.text = ("Dear " + order.customer.firstName
+ order.customer.lastName
+ ", thank you for placing order. Your order number is "
+ order.orderNumber)
try {
mailSender.send(msg)
} catch (ex: MailException) {
// simply log it and go on...
System.err.println(ex.message)
}
}
}
The following example shows the bean definitions for the preceding code:
-
Java
-
Kotlin
-
Xml
@Bean
JavaMailSender mailSender() {
JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
mailSender.setHost("mail.mycompany.example");
return mailSender;
}
@Bean // this is a template message that we can pre-load with default state
SimpleMailMessage templateMessage() {
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom("[email protected]");
message.setSubject("Your order");
return message;
}
@Bean
SimpleOrderManager orderManager(JavaMailSender mailSender, SimpleMailMessage templateMessage) {
SimpleOrderManager orderManager = new SimpleOrderManager();
orderManager.setMailSender(mailSender);
orderManager.setTemplateMessage(templateMessage);
return orderManager;
}
@Bean
fun mailSender(): JavaMailSender {
return JavaMailSenderImpl().apply {
host = "mail.mycompany.example"
}
}
@Bean // this is a template message that we can pre-load with default state
fun templateMessage() = SimpleMailMessage().apply {
from = "[email protected]"
subject = "Your order"
}
@Bean
fun orderManager(javaMailSender: JavaMailSender, simpleTemplateMessage: SimpleMailMessage) = SimpleOrderManager().apply {
mailSender = javaMailSender
templateMessage = simpleTemplateMessage
}
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="mail.mycompany.example"/>
</bean>
<!-- this is a template message that we can pre-load with default state -->
<bean id="templateMessage" class="org.springframework.mail.SimpleMailMessage">
<property name="from" value="[email protected]"/>
<property name="subject" value="Your order"/>
</bean>
<bean id="orderManager" class="com.mycompany.businessapp.support.SimpleOrderManager">
<property name="mailSender" ref="mailSender"/>
<property name="templateMessage" ref="templateMessage"/>
</bean>
Using JavaMailSender
and MimeMessagePreparator
This section describes another implementation of OrderManager
that uses the MimeMessagePreparator
callback interface. In the following example, the mailSender
property is of type
JavaMailSender
so that we are able to use the JavaMail MimeMessage
class:
import jakarta.mail.Message;
import jakarta.mail.MessagingException;
import jakarta.mail.internet.InternetAddress;
import jakarta.mail.internet.MimeMessage;
import jakarta.mail.internet.MimeMessage;
import org.springframework.mail.MailException;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessagePreparator;
public class SimpleOrderManager implements OrderManager {
private JavaMailSender mailSender;
public void setMailSender(JavaMailSender mailSender) {
this.mailSender = mailSender;
}
public void placeOrder(final Order order) {
// Do the business calculations...
// Call the collaborators to persist the order...
MimeMessagePreparator preparator = new MimeMessagePreparator() {
public void prepare(MimeMessage mimeMessage) throws Exception {
mimeMessage.setRecipient(Message.RecipientType.TO,
new InternetAddress(order.getCustomer().getEmailAddress()));
mimeMessage.setFrom(new InternetAddress("[email protected]"));
mimeMessage.setText("Dear " + order.getCustomer().getFirstName() + " " +
order.getCustomer().getLastName() + ", thanks for your order. " +
"Your order number is " + order.getOrderNumber() + ".");
}
};
try {
this.mailSender.send(preparator);
}
catch (MailException ex) {
// simply log it and go on...
System.err.println(ex.getMessage());
}
}
}
The mail code is a crosscutting concern and could well be a candidate for
refactoring into a custom Spring AOP aspect, which could then
be run at appropriate joinpoints on the OrderManager target.
|
The Spring Framework’s mail support ships with the standard JavaMail implementation. See the relevant javadoc for more information.
Using the JavaMail MimeMessageHelper
A class that comes in pretty handy when dealing with JavaMail messages is
org.springframework.mail.javamail.MimeMessageHelper
, which shields you from
having to use the verbose JavaMail API. Using the MimeMessageHelper
, it is
pretty easy to create a MimeMessage
, as the following example shows:
// of course you would use DI in any real-world cases
JavaMailSenderImpl sender = new JavaMailSenderImpl();
sender.setHost("mail.host.com");
MimeMessage message = sender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message);
helper.setTo("[email protected]");
helper.setText("Thank you for ordering!");
sender.send(message);
Sending Attachments and Inline Resources
Multipart email messages allow for both attachments and inline resources. Examples of inline resources include an image or a stylesheet that you want to use in your message but that you do not want displayed as an attachment.
Attachments
The following example shows you how to use the MimeMessageHelper
to send an email
with a single JPEG image attachment:
JavaMailSenderImpl sender = new JavaMailSenderImpl();
sender.setHost("mail.host.com");
MimeMessage message = sender.createMimeMessage();
// use the true flag to indicate you need a multipart message
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setTo("[email protected]");
helper.setText("Check out this image!");
// let's attach the infamous windows Sample file (this time copied to c:/)
FileSystemResource file = new FileSystemResource(new File("c:/Sample.jpg"));
helper.addAttachment("CoolImage.jpg", file);
sender.send(message);
Inline Resources
The following example shows you how to use the MimeMessageHelper
to send an email
with an inline image:
JavaMailSenderImpl sender = new JavaMailSenderImpl();
sender.setHost("mail.host.com");
MimeMessage message = sender.createMimeMessage();
// use the true flag to indicate you need a multipart message
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setTo("[email protected]");
// use the true flag to indicate the text included is HTML
helper.setText("<html><body><img src='cid:identifier1234'></body></html>", true);
// let's include the infamous windows Sample file (this time copied to c:/)
FileSystemResource res = new FileSystemResource(new File("c:/Sample.jpg"));
helper.addInline("identifier1234", res);
sender.send(message);
Inline resources are added to the MimeMessage by using the specified Content-ID
(identifier1234 in the above example). The order in which you add the text
and the resource are very important. Be sure to first add the text and then
the resources. If you are doing it the other way around, it does not work.
|
Creating Email Content by Using a Templating Library
The code in the examples shown in the previous sections explicitly created the content of the email message,
by using methods calls such as message.setText(..)
. This is fine for simple cases, and it
is okay in the context of the aforementioned examples, where the intent was to show you
the very basics of the API.
In your typical enterprise application, though, developers often do not create the content of email messages by using the previously shown approach for a number of reasons:
-
Creating HTML-based email content in Java code is tedious and error prone.
-
There is no clear separation between display logic and business logic.
-
Changing the display structure of the email content requires writing Java code, recompiling, redeploying, and so on.
Typically, the approach taken to address these issues is to use a template library (such as FreeMarker) to define the display structure of email content. This leaves your code tasked only with creating the data that is to be rendered in the email template and sending the email. It is definitely a best practice when the content of your email messages becomes even moderately complex, and, with the Spring Framework’s support classes for FreeMarker, it becomes quite easy to do.