In this article, by Anjana Mankale, author of the book Mastering Spring Application Development we shall see how we can use the Spring mail template to e-mail recipients. We shall also demonstrate using Spring mailing template configurations using different scenarios.
(For more resources related to this topic, see here.)
Spring mail message handling process
The following diagram depicts the flow of a Spring mail message process. With this, we can clearly understand the process of sending mail using a Spring mailing template.
A message is created and sent to the transport protocol, which interacts with internet protocols. Then, the message is received by the recipients.
The Spring mail framework requires a mail configuration, or SMTP configuration, as the input and message that needs to be sent. The mail API interacts with internet protocols to send messages. In the next section, we shall look at the classes and interfaces in the Spring mail framework.
Interfaces and classes used for sending mails with Spring
The package org.springframework.mail is used for mail configuration in the spring application.
The following are the three main interfaces that are used for sending mail:
- MailSender: This interface is used to send simple mail messages.
- JavaMailSender: This interface is a subinterface of the MailSender interface and supports sending mail messages.
- MimeMessagePreparator: This interface is a callback interface that supports the JavaMailSender interface in the preparation of mail messages.
The following classes are used for sending mails using Spring:
- SimpleMailMessage: This is a class which has properties such as to, from, cc, bcc, sentDate, and many others. The SimpleMailMessage interface sends mail with MailSenderImp classes.
- JavaMailSenderImpl: This class is an implementation class of the JavaMailSender interface.
- MimeMessageHelper: This class helps with preparing MIME messages.
Sending mail using the @Configuration annotation
We shall demonstrate here how we can send mail using the Spring mail API.
- First, we provide all the SMTP details in the .properties file and read it to the class file with the @Configuration annotation. The name of the class is MailConfiguration.
mail.properties file contents are shown below: mail.protocol=smtp mail.host=localhost mail.port=25 mail.smtp.auth=false mail.smtp.starttls.enable=false mail.from=me@localhost mail.username= mail.password= @Configuration @PropertySource("classpath:mail.properties") public class MailConfiguration { @Value("${mail.protocol}") private String protocol; @Value("${mail.host}") private String host; @Value("${mail.port}") private int port; @Value("${mail.smtp.auth}") private boolean auth; @Value("${mail.smtp.starttls.enable}") private boolean starttls; @Value("${mail.from}") private String from; @Value("${mail.username}") private String username; @Value("${mail.password}") private String password; @Bean public JavaMailSender javaMailSender() { JavaMailSenderImpl mailSender = new JavaMailSenderImpl(); Properties mailProperties = new Properties(); mailProperties.put("mail.smtp.auth", auth); mailProperties.put("mail.smtp.starttls.enable", starttls); mailSender.setJavaMailProperties(mailProperties); mailSender.setHost(host); mailSender.setPort(port); mailSender.setProtocol(protocol); mailSender.setUsername(username); mailSender.setPassword(password); return mailSender; } }
- The next step is to create a rest controller to send mail; to do so, click on Submit. We shall use the SimpleMailMessage interface since we don’t have any attachment.
@RestController class MailSendingController { private final JavaMailSender javaMailSender; @Autowired MailSubmissionController(JavaMailSender javaMailSender) { this.javaMailSender = javaMailSender; } @RequestMapping("/mail") @ResponseStatus(HttpStatus.CREATED) SimpleMailMessage send() { SimpleMailMessage mailMessage = new SimpleMailMessage(); mailMessage.setTo("packt@localhost"); mailMessage.setReplyTo("anjana@localhost"); mailMessage.setFrom("Sonali@localhost"); mailMessage.setSubject("Vani veena Pani"); mailMessage.setText("MuthuLakshmi how are you?Call
Me Please [...]"); javaMailSender.send(mailMessage); return mailMessage; } }
Sending mail using MailSender and Simple Mail Message with XML configuration
“Simple mail message” means the e-mail sent will only be text-based with no HTML formatting, no images, and no attachments. In this section, consider a scenario where we are sending a welcome mail to the user as soon as the user gets their order placed in the application. In this scenario, the mail will be sent after the database insertion operation is successful.
Create a separate folder, called com.packt.mailService, for the mail service. The following are the steps for sending mail using the MailSender interface and SimpleMailMessage class.
- Create a new Maven web project with the name Spring4MongoDB_MailChapter3.
- We have also used the same Eshop db database with MongoDB for CRUD operations on Customer, Order, and Product. We have also used the same mvc configurations and source files.
- Use the same dependencies as used previously.
- We need to add dependencies to the pom.xml file:
<dependency> <groupId>org.springframework.integration</groupId> <artifactId>spring-integration-mail</artifactId> <version>3.0.2.RELEASE</version> <scope>runtime</scope> </dependency> <dependency> <groupId>javax.activation</groupId> <artifactId>activation</artifactId> <version>1.1-rev-1</version> <scope>runtime</scope> </dependency> <dependency> <groupId>javax.mail</groupId> <artifactId>mail</artifactId> <version>1.4.3</version> </dependency>
- Compile the Maven project. Create a separate folder called com.packt.mailService for the mail service.
- Create a simple class named MailSenderService and autowire the MailSender and SimpleMailMessage classes. The basic skeleton is shown here:
public class MailSenderService { @Autowired private MailSender mailSender; @AutoWired private SimpleMailMessage simplemailmessage; public void sendmail(String from, String to, String
subject, String body){ /*Code */ } } - Next, create an object of SimpleMailMessage and set mail properties, such as from, to, and subject to it.
public void sendmail(String from, String to, String
subject, String body){ SimpleMailMessage message=new SimpleMailMessage(); message.setFrom(from); message.setSubject(subject); message.setText(body); mailSender.send(message); } - We need to configure the SMTP details. Spring Mail Support provides this flexibility of configuring SMTP details in the XML file.
<bean id="mailSender"
class="org.springframework.mail.javamail.
JavaMailSenderImpl"> <property name="host" value="smtp.gmail.com" /> <property name="port" value="587" /> <property name="username" value="username" /> <property name="password" value="password" /> <property name="javaMailProperties"> <props> <prop key="mail.smtp.auth">true</prop> <prop key="mail.smtp.starttls.enable">true</prop> </props> </property> </bean> <bean id="mailSenderService" class="
com.packt.mailserviceMailSenderService "> <property name="mailSender" ref="mailSender" /> </bean> </beans>We need to send mail to the customer after the order has been placed successfully in the MongoDB database. Update the addorder() method
as follows:@RequestMapping(value = "/order/save", method =
RequestMethod.POST) // request insert order recordh public String addorder(@ModelAttribute("Order")
Order order,Map<String, Object> model) { Customer cust=new Customer(); cust=customer_respository.getObject
(order.getCustomer().getCust_id()); order.setCustomer(cust); order.setProduct(product_respository.getObject
(order.getProduct().getProdid())); respository.saveObject(order); mailSenderService.sendmail
("[email protected]",cust.getEmail(), "Dear"+cust.getName()+"Your order
details",order.getProduct().getName()+"-price-"+order
.getProduct().getPrice()); model.put("customerList", customerList); model.put("productList", productList); return "order"; }
Sending mail to multiple recipients
If you want to intimate the user regarding the latest products or promotions in the application, you can create a mail sending group and send mail to multiple recipients using Spring mail sending support.
We have created an overloaded method in the same class, MailSenderService, which will accept string arrays. The code snippet in the class will look like this:
public class MailSenderService { @Autowired private MailSender mailSender; @AutoWired private SimpleMailMessage simplemailmessage; public void sendmail(String from, String to, String subject,
String body){ /*Code */ } public void sendmail(String from, String []to, String subject,
String body){ /*Code */ } }
The following is the code snippet for listing the set of users from MongoDB who have subscribed to promotional e-mails:
public List<Customer> getAllObjectsby_emailsubscription(String
status) { return mongoTemplate.find(query(
where("email_subscribe").is("yes")), Customer.class); }
Sending MIME messages
Multipurpose Internet Mail Extension (MIME) allows attachments to be sent over the Internet. This class just demonstrates how we can send mail with MIME messages. Using a MIME message sender type class is not advisible if you are not sending any attachments with the mail message. In the next section, we will look at the details of how we can send mail with attachments.
Update the MailSenderService class with another method. We have used the MIME message preparator and have overridden the prepare method() to set properties for the mail.
public class MailSenderService { @Autowired private MailSender mailSender; @AutoWired private SimpleMailMessage simplemailmessage; public void sendmail(String from, String to, String subject,
String body){ /*Code */ } public void sendmail(String from, String []to, String subject,
String body){ /*Code */ } public void sendmime_mail(final String from, final String to,
final String subject, final String body) throws MailException{ MimeMessagePreparator message = new MimeMessagePreparator() { public void prepare(MimeMessage mimeMessage)
throws Exception { mimeMessage.setRecipient(Message.RecipientType.TO,new
InternetAddress(to)); mimeMessage.setFrom(new InternetAddress(from)); mimeMessage.setSubject(subject); mimeMessage.setText(msg); } }; mailSender.send(message); }
Sending attachments with mail
We can also attach various kinds of files to the mail. This functionality is supported by the MimeMessageHelper class. If you just want to send a MIME message without an attachment, you can opt for MimeMesagePreparator. If the requirement is to have an attachment to be sent with the mail, we can go for the MimeMessageHelper class with file APIs.
Spring provides a file class named org.springframework.core.io.FileSystemResource, which has a parameterized constructor that accepts file objects.
public class SendMailwithAttachment { public static void main(String[] args)
throws MessagingException { AnnotationConfigApplicationContext ctx =
new AnnotationConfigApplicationContext(); ctx.register(AppConfig.class); ctx.refresh(); JavaMailSenderImpl mailSender =
ctx.getBean(JavaMailSenderImpl.class); MimeMessage mimeMessage = mailSender.createMimeMessage(); //Pass true flag for multipart message MimeMessageHelper mailMsg = new MimeMessageHelper(mimeMessage,
true); mailMsg.setFrom("[email protected]"); mailMsg.setTo("[email protected]"); mailMsg.setSubject("Test mail with Attachment"); mailMsg.setText("Please find Attachment."); //FileSystemResource object for Attachment FileSystemResource file = new FileSystemResource(new
File("D:/cp/ GODGOD. jpg")); mailMsg.addAttachment("GODGOD.jpg", file); mailSender.send(mimeMessage); System.out.println("---Done---"); } }
Sending preconfigured mail
In this example, we shall provide a message that is to be sent in the mail, and we will configure it in an XML file. Sometimes when it comes to web applications, you may have to send messages on maintenance. Think of a scenario where the content of the mail changes, but the sender and receiver are preconfigured. In such a case, you can add another overloaded method to the MailSender class.
We have fixed the subject of the mail, and the content can be sent by the user. Think of it as “an application which sends mails to users whenever the build fails”.
<?xml version="1.0" encoding="UTF-8"?> <beans
xsi_schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/
context/spring-context-3.0.xsd"> <context:component-scan base-package="com.packt" /> <!-- SET default mail properties --> <bean id="mailSender" class=
"org.springframework.mail.javamail.JavaMailSenderImpl"> <property name="host" value="smtp.gmail.com"/> <property name="port" value="25"/> <property name="username" value="[email protected]"/> <property name="password" value="password"/> <property name="javaMailProperties"> <props> <prop key="mail.transport.protocol">smtp</prop> <prop key="mail.smtp.auth">true</prop> <prop key="mail.smtp.starttls.enable">true</prop> <prop key="mail.debug">true</prop> </props> </property> </bean> <!-- You can have some pre-configured messagess also which are
ready to send --> <bean id="preConfiguredMessage" class=
"org.springframework.mail.SimpleMailMessage"> <property name="to" value="[email protected]"></property> <property name="from" value="[email protected]"></property> <property name="subject" value="FATAL ERROR- APPLICATION AUTO
MAINTENANCE STARTED-BUILD FAILED!!"/> </bean> </beans>
Now we shall sent two different bodies for the subjects.
public class MyMailer { public static void main(String[] args){ try{ //Create the application context ApplicationContext context = new
FileSystemXmlApplicationContext(
"application-context.xml"); //Get the mailer instance ApplicationMailer mailer = (ApplicationMailer)
context.getBean("mailService"); //Send a composed mail mailer.sendMail("[email protected]", "Test Subject",
"Testing body"); }catch(Exception e){ //Send a pre-configured mail mailer.sendPreConfiguredMail("build failed exception occured
check console or logs"+e.getMessage()); } } }
Using Spring templates with Velocity to send HTML mails
Velocity is the templating language provided by Apache. It can be integrated into the Spring view layer easily. The latest Velocity version used during this book is 1.7. In the previous section, we demonstrated using Velocity to send e-mails using the @Bean and @Configuration annotations. In this section, we shall see how we can configure Velocity to send mails using XML configuration.
All that needs to be done is to add the following bean definition to the .xml file. In the case of mvc, you can add it to the dispatcher-servlet.xml file.
<bean id="velocityEngine" class=
"org.springframework.ui.velocity.VelocityEngineFactoryBean"> <property name="velocityProperties"> <value> resource.loader=class class.resource.loader.class=org.apache.velocity
.runtime.resource.loader.ClasspathResourceLoader </value> </property> </bean>
- Create a new Maven web project with the name Spring4MongoDB_Mail_VelocityChapter3.
- Create a package and name it com.packt.velocity.templates.
- Create a file with the name orderconfirmation.vm.
<html> <body> <h3> Dear Customer,<h3> <p>${customer.firstName} ${customer.lastName}</p> <p>We have dispatched your order at address.</p> ${Customer.address} </body> </html>
- Use all the dependencies that we have added in the previous sections.
- To the existing Maven project, add this dependency:
<dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity</artifactId> <version>1.7</version> </dependency>
- To ensure that Velocity gets loaded on application startup, we shall create a class. Let’s name the class VelocityConfiguration.java. We have used the annotations @Configuration and @Bean with the class.
import java.io.IOException; import java.util.Properties; import org.apache.velocity.app.VelocityEngine; import org.apache.velocity.exception.VelocityException; import org.springframework.context.annotation.Bean; import
org.springframework.context.annotation.Configuration; import
org.springframework.ui.velocity.VelocityEngineFactory; @Configuration public class VelocityConfiguration { @Bean public VelocityEngine getVelocityEngine() throws VelocityException, IOException{ VelocityEngineFactory velocityEngineFactory = new
VelocityEngineFactory(); Properties props = new Properties(); props.put("resource.loader", "class"); props.put("class.resource.loader.class",
"org.apache.velocity.runtime.resource.loader." +
"ClasspathResourceLoader"); velocityEngineFactory.setVelocityProperties(props); return factory.createVelocityEngine(); } } - Use the same MailSenderService class and add another overloaded sendMail() method in the class.
public void sendmail(final Customer customer){ MimeMessagePreparator preparator = new
MimeMessagePreparator() { public void prepare(MimeMessage mimeMessage) throws Exception { MimeMessageHelper message =
new MimeMessageHelper(mimeMessage); message.setTo(user.getEmailAddress()); message.setFrom("[email protected]"); // could be
parameterized Map model = new HashMap(); model.put("customer", customer); String text =
VelocityEngineUtils.mergeTemplateIntoString(
velocityEngine, "com/packt/velocity/templates/
orderconfirmation.vm", model); message.setText(text, true); } }; this.mailSender.send(preparator); } - Update the controller class to send mail using the Velocity template.
@RequestMapping(value = "/order/save", method =
RequestMethod.POST) // request insert order recordh public String addorder(@ModelAttribute("Order") Order
order,Map<String, Object> model) { Customer cust=new Customer(); cust=customer_respository.getObject(order.getCustomer()
.getCust_id()); order.setCustomer(cust); order.setProduct(product_respository.getObject
(order.getProduct().getProdid())); respository.saveObject(order); // to send mail using velocity template. mailSenderService.sendmail(cust); return "order"; }
Sending Spring mail over a different thread
There are other options for sending Spring mail asynchronously. One way is to have a separate thread to the mail sending job. Spring comes with the taskExecutor package, which offers us a thread pooling functionality.
- Create a class called MailSenderAsyncService that implements the MailSender interface.
- Import the org.springframework.core.task.TaskExecutor package.
- Create a private class called MailRunnable. Here is the complete code for MailSenderAsyncService:
public class MailSenderAsyncService implements MailSender{ @Resource(name = "mailSender") private MailSender mailSender; private TaskExecutor taskExecutor; @Autowired public MailSenderAsyncService(TaskExecutor taskExecutor){ this.taskExecutor = taskExecutor; } public void send(SimpleMailMessage simpleMessage) throws
MailException { taskExecutor.execute(new MailRunnable(simpleMessage)); } public void send(SimpleMailMessage[] simpleMessages)
throws MailException { for (SimpleMailMessage message : simpleMessages) { send(message); } } private class SimpleMailMessageRunnable implements
Runnable { private SimpleMailMessage simpleMailMessage; private SimpleMailMessageRunnable(SimpleMailMessage
simpleMailMessage) { this.simpleMailMessage = simpleMailMessage; } public void run() { mailSender.send(simpleMailMessage); } } private class SimpleMailMessagesRunnable implements
Runnable { private SimpleMailMessage[] simpleMessages; private SimpleMailMessagesRunnable(SimpleMailMessage[]
simpleMessages) { this.simpleMessages = simpleMessages; } public void run() { mailSender.send(simpleMessages); } } } - Configure the ThreadPool executor in the .xml file.
<bean id="taskExecutor" class="org.springframework.
scheduling.concurrent.ThreadPoolTaskExecutor"
p_corePoolSize="5" p_maxPoolSize="10" p_queueCapacity="100"
p_waitForTasksToCompleteOnShutdown="true"/> - Test the source code.
import javax.annotation.Resource; import org.springframework.mail.MailSender; import org.springframework.mail.SimpleMailMessage; import org.springframework.test.context.ContextConfiguration; @ContextConfiguration public class MailSenderAsyncService { @Resource(name = " mailSender ") private MailSender mailSender; public void testSendMails() throws Exception { SimpleMailMessage[] mailMessages = new
SimpleMailMessage[5]; for (int i = 0; i < mailMessages.length; i++) { SimpleMailMessage message = new SimpleMailMessage(); message.setSubject(String.valueOf(i)); mailMessages[i] = message; } mailSender.send(mailMessages); } public static void main (String args[]){ MailSenderAsyncService asyncservice=new
MailSenderAsyncService(); Asyncservice. testSendMails(); } }
Sending Spring mail with AOP
We can also send mails by integrating the mailing functionality with Aspect Oriented Programming (AOP). This can be used to send mails after the user registers with an application. Think of a scenario where the user receives an activation mail after registration. This can also be used to send information about an order placed on
an application. Use the following steps to create a MailAdvice class using AOP:
- Create a package called com.packt.aop.
- Create a class called MailAdvice.
public class MailAdvice { public void advice (final ProceedingJoinPoint
proceedingJoinPoint) { new Thread(new Runnable() { public void run() { System.out.println("proceedingJoinPoint:"+
proceedingJoinPoint); try { proceedingJoinPoint.proceed(); } catch (Throwable t) { // All we can do is log the error. System.out.println(t); } } }).start(); } }This class creates a new thread and starts it. In the run method, the proceedingJoinPoint.proceed() method is called. ProceddingJoinPoint is a class available in AspectJ.jar.
- Update the dispatcher-servlet.xml file with aop configurations. Update the xlmns namespace using the following code:
advice"> <aop:around method="fork"
pointcut="execution(* org.springframework.mail
.javamail.JavaMailSenderImpl.send(..))"/> </aop:aspect> </aop:config>
Summary
In this article, we demonstrated how to create a mailing service and configure it using Spring API. We also demonstrated how to send mails with attachments using MIME messages. We also demonstrated how to create a dedicated thread for sending mails using ExecutorService. We saw an example in which mail can be sent to multiple recipients, and saw an implementation of using the Velocity engine to create templates and send mails to recipients. In the last section, we demonstrated how the Spring framework supported mails can be sent using Spring AOP and threads.
Resources for Article:
Further resources on this subject:
- Time Travelling with Spring [article]
- Welcome to the Spring Framework [article]
- Creating a Spring Application [article]