Mailing with Spring Mail

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.

  1. 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;
    }
    }
  2. 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.

  1. Create a new Maven web project with the name Spring4MongoDB_MailChapter3.
  2. 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.
  3. Use the same dependencies as used previously.
  4. 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>
  5. Compile the Maven project. Create a separate folder called com.packt.mailService for the mail service.
  6. 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 */ }   }
  7. 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); }
  8. 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
         ("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"; }

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("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---"); }   }

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 xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
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());    } } }

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>
  1. Create a new Maven web project with the name Spring4MongoDB_Mail_VelocityChapter3.
  2. Create a package and name it com.packt.velocity.templates.
  3. 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>
  4. Use all the dependencies that we have added in the previous sections.
  5. To the existing Maven project, add this dependency:
    <dependency>
    <groupId>org.apache.velocity</groupId>
    <artifactId>velocity</artifactId>
    <version>1.7</version>
    </dependency>
  6. 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(); } }
  7. 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("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); }
  8. 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.

  1. Create a class called MailSenderAsyncService that implements the MailSender interface.
  2. Import the org.springframework.core.task.TaskExecutor package.
  3. 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);    } } }
  4. 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"/>
  5. 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:

  1. Create a package called com.packt.aop.
  2. 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.

  3. Update the dispatcher-servlet.xml file with aop configurations. Update the xlmns namespace using the following code:
    xmlns:aop=http://www.springframework.org/schema/aop
  4. Also update the xsi:schemalocation, as shown in the following code:
    xsi:schemaLocation="http://www.springframework.org/
    schema/aop http://www.springframework.org/
    schema/aop/spring-aop-2.5.xsd
  5. Update the bean configuration in the .xml file:
    <aop:config>
    <aop:aspect ref="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:


You've been reading an excerpt of:

Mastering Spring Application Development

Explore Title
comments powered by Disqus