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.)
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.
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:
The following classes are used for sending mails using Spring:
We shall demonstrate here how we can send mail using the Spring mail API.
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; } }
@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; } }
"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.
<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>
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){ SimpleMailMessage message=new SimpleMailMessage(); message.setFrom(from); message.setSubject(subject); message.setText(body); mailSender.send(message); }
<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
("anjana.mprasad@gmail.com",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"; }
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); }
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); }
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("ANJUANJU02@gmail.com"); mailMsg.setTo("RAGHY03@gmail.com"); 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---"); } }
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="anju@gmail.com"/> <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="packt@gmail.com"></property> <property name="from" value="anju@gmail.com"></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("nikhil@gmail.com", "Test Subject",
"Testing body"); }catch(Exception e){ //Send a pre-configured mail mailer.sendPreConfiguredMail("build failed exception occured
check console or logs"+e.getMessage()); } } }
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>
<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>
<dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity</artifactId> <version>1.7</version> </dependency>
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(); } }
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("webmaster@packt.com"); // 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); }
@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"; }
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.
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); } } }
<bean id="taskExecutor" class="org.springframework.
scheduling.concurrent.ThreadPoolTaskExecutor"
p_corePoolSize="5" p_maxPoolSize="10" p_queueCapacity="100"
p_waitForTasksToCompleteOnShutdown="true"/>
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(); } }
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:
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.
advice"> <aop:around method="fork"
pointcut="execution(* org.springframework.mail
.javamail.JavaMailSenderImpl.send(..))"/> </aop:aspect> </aop:config>
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.
Further resources on this subject: