Sending e-mails using JavaMail API

Spring framework provides classes such as JavaMailSenderImpl , SimpleMailMessage , and so on, which simplify sending e-mails via JavaMail API. In this recipe, we'll look at Roo commands that help with the configuration of these classes. To verify that the emailing feature in our application is working correctly, we'll send an e-mail via Gmail.

Getting ready

Create a new directory C: oo-cookbookch06-email in your system. Copy the ch06_web_app.roo script to the ch06-email directory. If you are using a different database than MySQL or your connection settings are different than what is specified in the script, then modify the script accordingly.

Start the Roo shell from the ch06-email directory and execute the ch06_web_app.roo script using the script command. Executing the Roo script will create a flightapp-web eclipse project that represents a Spring Web MVC application consisting of Flight and FlightDescription JPA entities.

How to do it...

To simplify e-mail sending, follow the steps given here:

  1. Execute the email sender setup command, by providing username and password argument values for the Gmail account through which you want to send e-mails. In the following command, replace the <username> and <password> argument values with the values that reflect your Gmail account username and password, respectively. It is important to note that you don't need to specify @gmail.com as the value of username, as it is derived from the hostServer argument. If you are using a different mail server for sending e-mails, then modify the argument values accordingly.
    ... roo> email sender setup --hostServer smtp.gmail.com --port 587 --protocol SMTP --username  <username> --password  <password>
    
    Updated SRC_MAIN_RESOURCESMETA-INFspringapplicationContext.xml
    Updated ROOTpom.xml [Added dependencies ..., javax.mail:mail:1.4.1, javax.activation:activation:1.1.1]
    Created SRC_MAIN_RESOURCESMETA-INFspringemail.properties
    
  2. Execute the email template setup command to specify the sender of the e-mail message and the subject of the e-mail (replace <username> with your Gmail account username), as shown here:
    ... roo> email template setup --from  <username> @gmail.com --subject "A new Flight instance has been created"
    
    Updated SRC_MAIN_RESOURCESMETA-INFspringapplicationContext.xml
    Updated SRC_MAIN_RESOURCESMETA-INFspringemail.properties
    
  3. Add Spring's MailSender and SimpleMailMessage fields, along with a sendMessage method, to FlightController.java using the field email template command, as shown here:
    ... roo> field email template --class ~.web.FlightController
    
    Updated ...flightappwebFlightController.java
    
  4. Execute the perform eclipse command to update the project's classpath settings:
    .. roo> perform eclipse
    
  5. Import the flightapp-web Eclipse project into Eclipse IDE.
  6. Open FlightController_Roo_Controller.aj file, copy the declaration that introduces create(...) method in FlightController.java and paste it in the FlightController.java file.

    Note

    If you are using Spring Roo 1.1.3, then remove the create method declaration from FlightController_Roo_Controller.aj file. This is required because the create declaration from FlightController_Roo_Controller.aj file is not automatically removed in Spring Roo 1.1.3.

    The create method of the FlightController class is invoked when the user enters flight information and submits the request to create a new Flight instance. After adding the create(...) method, your FlightController.java should look as follows:

    @RooWebScaffold(...)
    @RequestMapping("/flights")
    @Controller
    public class FlightController {
    
     @Autowired
     private transient MailSender mailTemplate;
    
     @Autowired
     private transient SimpleMailMessage simpleMailMessage;
    
     @RequestMapping(method = RequestMethod.POST)
     public String create(@Valid Flight flight, 
       BindingResult bindingResult, Model uiModel, 
       HttpServletRequest httpServletRequest) {
       ...
       flight.persist();
       return "redirect:/flights/" + 
         encodeUrlPathSegment(flight.getFlightId().toString(),  
         httpServletRequest);
     }
        
     public void sendMessage(java.lang.String mailTo, 
        java.lang.String message) {
       ...
     }
    }

    In the given code, the create method has been directly added to the FlightController.java by copying it from the FlightController_Roo_Controller.aj AspectJ ITD file. In the ITD, the create method is declared as shown here:

    public String FlightController.create(...)

    Make sure that you remove the FlightController from the name of the method when you copy it to the FlightController.java file. So, this method in FlightController.java becomes:

    public String create(...)

    When you add the create(...) method in FlightController.java with the same signature as in FlightController_Roo_Controller.aj, then Roo removes the create(...) method from FlightController_Roo_Controller.aj. Refresh the flightapp-web project in Eclipse IDE so that modifications made by Roo are visible.

  7. Now, modify the create(...) method in FlightController.java by adding the following piece of code just after the call to flight.persist() method:
    sendMessage("<username>@gmail.com", "A new instance of Flight entity with id " + flight.getFlightId() + " has been created.");

    In this code, replace <username> with your Gmail account username.

  8. Exit the Roo shell and execute the tomcat:run goal of the Tomcat maven plugin from the ch06-email directory to deploy the flightapp-web project in an embedded Tomcat container, as shown here:
    C:
    oo-cookbookch06-email> mvn tomcat:run
    

    Access the flightapp-web application from the web browser using the following URL: http://localhost:8080/flightapp-web. You should now see the following home page of the flightapp-web application:

    How to do it...

    Select the Create new Flight Description option from the menu, which shows the form for creating a new FlightDescription entity instance. Once you have created the FlightDescription instance, select the Create new Flight menu option to create a Flight instance. The following screenshot shows the form for creating a Flight instance:

    How to do it...

    Enter Departure Date, Arrival Date, and Flight Description information and click the Save button. Saving the Flight instance will result in sending an e-mail to your Gmail account, with the subject as A new Flight instance has been created and the message A new instance of Flight entity with ID 1 has been created. As you create more Flight instances, an e-mail is sent to your Gmail account for each Flight instance created.

How it works...

JavaMail API provides classes such as Session , Transport , Authenticator , and so on, that are used for composing, sending, and reading e-mails. If you want to directly use the JavaMail API to send an e-mail message, then you'll need to know how to use different JavaMail API classes and interfaces. Spring framework abstracts the inner workings of JavaMail API by providing a set of classes and interfaces, which simplifies writing programs that require the functionality of sending e-mails. Also, Spring provides an exception hierarchy, which abstracts exceptions thrown during composing, parsing, and sending e-mails or while authenticating with the mail server.

The following figure shows the important classes and interfaces of Spring that provide e-mail sending functionality. You can find these classes and interfaces in the org.springframework.mail and org.springframework.mail.javamail packages of the Spring framework.

How it works...

MailSender interface is a generic interface that defines e-mail sending functionality. As shown in the given figure, it defines two send methods that accept Spring's SimpleMailMessage and SimpleMailMessage[] objects as arguments.

The JavaMailSender interface extends the MailSender interface and defines methods specific to sending e-mails using JavaMail API. JavaMailSender defines methods such as createMimeMessage—for creating a MimeMessage instance (which is part of JavaMail API), send—for sending a MimeMessage, and so on. For the complete list of methods defined by Spring, refer to the Spring API documentation for the JavaMailSender interface. Spring provides a concrete implementation of the JavaMailSender interface through the JavaMailSenderImpl class, which you can use in your application to send e-mails.

It is important to note that the MailSender interface defines send methods that accept SimpleMailMessage or SimpleMailMessage[] objects as arguments, and the JavaMailSender interface defines send methods that accept MimeMessage or MimeMessage[] objects as arguments. SimpleMailMessage is part of Spring framework and is useful for creating simple mail messages consisting of from, to, e-mail body, and so on. If you want to send more refined messages consisting of attachments, inline images, and so on, then you should use MimeMessage to create your mail message.

Now that we have a basic understanding of different classes and interfaces that come into the picture when it comes to sending e-mails, let's look at various Spring Roo commands that we used in the flightapp-web application for setting up e-mail support and sending e-mails.

Setting up e-mail sending support

The email sender setup Roo command sets up e-mail sending support in a Roo project by configuring JavaMailSenderImpl in Spring's application context. When the email sender setup command is executed, the following actions are performed by Roo:

  • The SRC_MAIN_RESOURCESMETA-INFspringapplicationContext.xml file is updated to configure JavaMailSenderImpl as a Spring bean
  • The SRC_MAIN_RESOURCESMETA-INFspringemail.properties file is created, which contains properties for setting up the JavaMailSenderImpl instance. The properties defined in the email.properties file come from the arguments specified for the email sender setup command.
  • The pom.xml file is updated to reflect dependency on JavaMail and Java Activation Framework(JAF) JAR files.

The following listing shows the JavaMailSenderImpl configuration in the applicationContext.xml file:

<bean class="org.springframework.mail.javamail.
  JavaMailSenderImpl" id="mailSender">
  <property name="host" value="${email.host}"/>
  <property name="protocol" value="${email.protocol}"/>
  <property name="port" value="${email.port}"/>
  <property name="username" value="${email.username}"/>
  <property name="password" value="${email.password}"/>
  <property name="javaMailProperties">
    <props>
      <prop key="mail.smtp.auth">true</prop>
      <prop key="mail.smtp.starttls.enable">true</prop>
    </props>
  </property>
</bean>

In the given XML, JavaMailSenderImpl is configured with properties such as host, protocol, port, and so on. The values of these properties come from the email.properties file.

The following listing shows the email.properties file:

email.host=smtp.gmail.com
email.password=<password>
email.port=587
email.protocol=smtp
email.username=<username>

Instead of <username> and <password>, you'll see username and password values specified for the email sender setup command. The email.properties file is read by Spring's PropertyPlaceholderConfigurer to fill the placeholders defined in the configuration of JavaMailSender. The applicationContext.xml file uses the <property-placeholder> element of Spring's context to configure a PropertyPlaceholderConfigurer, as shown here:

<context:property-placeholder location="classpath*:META-INF/spring/*.properties"/>

The location attribute specifies that the PropertyPlaceholderConfigurer will look for properties files in the META-INF/spring directory of the project.

Note

In this recipe, we used the email sender setup command to set up JavaMailSenderImpl for the flightapp-web project that represents a Spring Web MVC application. You can use the email sender setup command with any Roo project that requires an e-mail sending feature.

Let's now look at how to set up a SimpleMailMessage instance:

Setting up a mail message

The email template setup command configures SimpleMailMessage as a bean in the applicationContext.xml file. The email template setup command accepts two arguments: from and subject, identifying the sender and subject of the email, respectively. When the email sender setup command is executed, the following actions are performed by Roo:

  • Configures SimpleMailMessage as a Spring-managed bean in applicationContext.xml, as shown here:
    <bean class="org.springframework.mail.SimpleMailMessage" 
        id="templateMessage">
        <property name="from" value="${email.from}"/>
            <property name="subject" value="${email.subject}"/>
        </bean>
    </beans>

    The values of ${email.from} and ${email.subject} placeholders come from the email.properties file.

  • Updates the email.properties file to include email.from and email.subject properties, the values of which come from the value of the from and subject arguments passed to the email template setup command:
    email.from=<username>@gmail.com
    email.subject=A new Flight instance has been created

Now that JavaMailSenderImpl and SimpleMailMessage instances are configured in the application context XML file, we'll look at how to send e-mails.

Sending mails

To send an e-mail from your enterprise application you'll require access to both the JavaMailSenderImpl and SimpleMailMessage instances registered with the Spring's application context. Attributes referring to these instances are automatically added to a class by the field email template Roo command. The following code listing shows the FlightController.java class after the field email template command was executed against it:

import org.springframework.mail.MailSender;
....
public class FlightController {

  @Autowired
  private transient MailSender mailTemplate;

  @Autowired
  private transient SimpleMailMessage simpleMailMessage;

  public void sendMessage(java.lang.String mailTo,
   java.lang.String message) {
     simpleMailMessage.setTo(mailTo);
     simpleMailMessage.setText(message);
     mailTemplate.send(simpleMailMessage);
  }
}

In the given code, the mailTemplate attribute refers to the JavaMailSenderImpl instance and the simpleMailMessage attribute refers to the SimpleMailMessage instance registered with the Spring's application context. It is important to note that the type of the mailTemplate attribute is MailSender and not JavaMailSender. Also, a sendMessage method is added to the FlightController.java for sending e-mails. The sendMessage method accepts arguments that identify the e-mail recipient's address and the text content or body of the e-mail. The sendMessage method makes use of the send(SimpleMailMessage) method of MailSender to send e-mails.

You can now call the send method from within the FlightController.java class methods to send e-mails. In our example scenario, we called send method from the create method after a Flight instance was persisted, as shown here:

@RequestMapping(method = RequestMethod.POST)
 public String create(@Valid Flight flight, 
   BindingResult bindingResult, Model uiModel, 
   HttpServletRequest httpServletRequest) {
   ...
   flight.persist();
   sendMessage("<username>@gmail.com", 
   "A new instance of Flight entity with id " 
    + flight.getFlightId() 
    + "has been created.");
   
   return "redirect:/flights/" + 
     encodeUrlPathSegment(flight.getFlightId().toString(),  
     httpServletRequest);
 }

There's more...

Let's now look at how to send e-mails asynchronously, how to send more refined e-mails consisting of attachments, inline images, and so on, and finally how to send e-mails when the JavaMail Session is configured in JNDI.

Sending e-mails asynchronously

E-mail sending that we have discussed so far in this recipe, is synchronous in nature. Typically, e-mails are sent asynchronously by applications—something which can be achieved in Spring via the @Async annotation. The field email template command supports an async argument, that instructs Roo to do the following:

  • Create the sendMessage method, which is annotated with the @Async Spring annotation
  • Enable detection of the @Async annotated methods using the <annotation-driven> element of Spring's task namespace, as shown here:
    <task:annotation-driven executor="asyncExecutor"
          mode="aspectj" />

    The executor attribute refers to an implementation of the java.util.concurrent.Executor interface, responsible for executing the @Async annotated method.

  • Configure Spring's ThreadPoolTaskExecutor in application context XML using the <executor> element of Spring's task namespace, as shown here:
    <task:executor id="asyncExecutor" 
        pool-size="${executor.poolSize}" />
  • Spring's ThreadPoolTaskExecutor configures a java.util.concurrent.ThreadPoolExecutor instance (an implementation of java.util.concurrent.Executor) with the thread pool size specified by the pool-size attribute value. The ${executor.poolSize} placeholder's value comes from the email.properties file.
  • Add the executor.poolSize property to the email.properties file, as shown here:
    executor.poolSize=10

To send mails asynchronously when a FlightDescription instance is created, execute the following field email template command against the FlightDescriptionController class, as shown here:

.. roo> field email template --class ~.web.FlightDescriptionController --async

Now, copy the create(...) method from FlightDescriptionController_Roo_Controller.aj to FlightDescriptionController.java and add a call to the sendMessage(...) method, as shown here:

@RequestMapping(method = RequestMethod.POST)
public String create(@Valid FlightDescription...) {
  ...
  flightDescription.persist();
  sendMessage("<username>@gmail.com", 
    "FlightDescription instance created");
  return "redirect:/flightdescriptions/" + ..
}

Sending e-mails with attachments

As mentioned earlier, if you want to send mails with attachments, inline images, and so on, then you need to use MimeMessage instead of SimpleMailMessage. The field email template command adds SimpleMailMessage and MailSender type attributes to the Java class, as shown here:

  @Autowired
  private transient MailSender mailTemplate;

  @Autowired
  private transient SimpleMailMessage simpleMailMessage;

Now, MailSender defines methods which accept a SimpleMailMessage or SimpleMailMessage[] object as the argument. JavaMailSender, on the other hand, defines methods which accept a MimeMessage or MimeMessage[] object as the argument. So, we need to change the type of mailTemplate attribute from MailSender to JavaMailSender (a sub-interface of MailSender) to send messages of type MimeMessage. Also, we need to remove the simpleMailMessage attribute from the class because we need mail message of type MimeMessage and not SimpleMailMessage when sending mail messages with attachments or inline images.

So, how do we go about creating a MimeMessage? Spring provides the following utility classes that simplify creating a MimeMessage:

  • MimeMessagePreparator: A callback interface for preparing a MimeMessage
  • MimeMessageHelper: A helper class that provides methods for creating and populating a MimeMessage

The following code shows modified FlightDescriptionController.java that makes use of MimeMessageHelper to send a mail message with an attachment when a new FlightDescription instance is created:

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.scheduling.annotation.Async;
...
public class FlightDescriptionController {

  @Autowired
  private transient JavaMailSender mailTemplate;

  @RequestMapping(method = RequestMethod.POST)
  public String create(@Valid FlightDescription 
    flightDescription...) {
    ...
    flightDescription.persist();
    sendMessage(..);
    return "redirect:/flightDescriptions/" + ...);
  }
    
  @Async
  public void sendMessage(java.lang.String mailTo, 
    java.lang.String message) throws MessagingException {
    MimeMessage mimeMessage = 
      mailTemplate.createMimeMessage();

    MimeMessageHelper helper = 
      new MimeMessageHelper(mimeMessage, true);
    helper.setTo(mailTo);
    helper.setText(message);
    helper.addAttachment("logo.gif", 
      new File("C:/logo.gif"));
    mailTemplate.send(mimeMessage);
  }
}

In the FlightDescriptionController.java we made the following changes:

  • Changed return type of the mailMessage attribute from MailSender to JavaMailSender
  • Removed the simpleMailMessage attribute of type SimpleMailMessage as we need a MimeMessage instance to send mails with attachments
  • Modified the sendMessage method to make use of the MimeMessageHelper class to create a MimeMessage instance and add attachments to it.

Sending e-mails with JavaMail Session configured in JNDI

If JavaMail Session is configured in JNDI of your application server, then you'll need to modify the applicationContext.xml file of your Roo project to create the JavaMailSenderImpl instance using JavaMail Session configured in JNDI, as shown here:

<beans ... xmlns:jee="http://www.springframework.org/schema/jee" ... xsi:schemaLocation="http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd">
.....
<jee:jndi-lookup id="mailSession" jndi-name="mail/session" />

<bean class="org.springframework.mail.javamail.JavaMailSenderImpl"   
  id="mailSender">
  <property name="session" value="mailSession"/>
</bean>
.....

The jndi-lookup element of Spring's jee namespace, shown in the given code, is responsible for accessing the JavaMail Session configured in JNDI with name "mail/session" (referred to by the jndi-name attribute) and making it available in a Spring application context with bean id as "mailSession".

See also

  • Refer to the next recipe, Sending and receiving messages with JMS, to see how you can send and receive messages using JMS
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.135.216.75