Spring integration with Quartz for sending bulk e-mails

Quartz is a full-featured, open source job scheduling service that can be integrated with or used along side virtually any Java EE or Java SE application but sometimes configuring quartz scheduler to send bulk e-mails to different users with different messages in your project becomes tedious. This can be extremely easy if you are using Spring Framework.
This blog gives an insight on how can we integrate quartz scheduler with spring framework to schedule a job which will send e-mails to different users based on velocity template. The Velocity Template Language is basically meant to provide the easiest, simplest, and cleanest way to incorporate dynamic content in a web page.
Steps to integrate Spring, Quartz and Velocity Template to write a scheduler are given below.
Step-1:
Write and configure JobDetailBean : Quartz basically uses Triggers, Jobs and JobDetail for scheduling all kind of jobs. JobDetail object contains all required information to run a job. In the below example, SendingMailsJob is a job detail bean.

Below is the source code of SendingMailsJob class:

/**
 * Job implementation that sends mail notifications to all users.
 *
 */
public class SendingMailsJob extends QuartzJobBean {
  private MailServiceImpl mailService;
  @Override
  protected void executeInternal(JobExecutionContext context)
   throws JobExecutionException {
   mailService.sendMail(getUserListInformation());
  }
 /**
  * returns a list of users.
  * @return userList
  */
  private List<User> getUserListInformation() {
    List<User> userList = new ArrayList<User>();
    User user = new User();
    user.setUserName("ABC");
    user.setEmailAddress("ABC@abc.com");
    userList.add(user);
    return userList;
  }

 /* Setter Methods */
  public void setMailService(MailServiceImpl mailService) {
    this.mailService = mailService;
  }
}

Configuration of SendingMailsJob as a bean in email-configuration.xml

<bean name="sendMailJob">
  <property name="jobClass" value="com.xebia.jobscheduler.SendingMailsJob" />
  <property name="jobDataAsMap">
  <map>
    <entry key="mailService" value-ref="mailService" />
  </map>
  </property>
</bean>

In the above configuration ‘jobDataAsMap’ property of JobDetailBean is used to set the values of the SendingMailsJob bean’s properties.
Step-2:
Write and configure service class MailServiceImpl as bean :
MailServiceImpl class is a service class, having  sendMail(List<User> userList) method which creates an empty List of MimeMessagePreparator and iterates on userList. On each iteration of user, an anonymous inner class has been created which implements MimeMessagePreparator interface and implement it’s prepare(MimeMessage mimeMessage) method.
Inside prepare(MimeMessage mimeMessage) method, an object of  MimeMessageHelper is created and sets the email related information(e.g. To email address, From email address, subject of email and body text of mail).
For setting body text of email, VelocityEngineUtils.mergeTemplateIntoString(velocityEngine, “reminderMail-format.vm”, model) method has been used. Here “reminderMail-format.vm” is the velocity template and model is nothing but a HashMap, which contains user related information like name of the user, which will be used in velocity template while creating email message.
At the end of this method an array of MimeMessagePreparator has been created and passed to JavaMailSender’s send(MimeMessagePreparator[] arg) method which is used to send mails to all the email address.
Below is the source code of MailServiceImpl class:

/**
 * This class is used to send e-mails based on the velocity template.
 *
 */
 public class MailServiceImpl {
   private JavaMailSender mailSender;
   private VelocityEngine velocityEngine;
   private String defaultFrom;
   private static final String[] MONTHS = { "January", "February", "March",
                 "April", "May", "June", "July", "August", "September", "October",
                 "November", "December" };

  /**
   * Iterates over userList and sends e-mail message to each user based on
   * Velocity templates.
   *
   * @param userList
   */
   public void sendMail(List<User> userList) {
     final Calendar calendar = Calendar.getInstance();
     calendar.setTime(new Date());
     List<MimeMessagePreparator> preparatorList = new
                                 ArrayList<MimeMessagePreparator>();
     for (final User user : userList) {
       MimeMessagePreparator preparator = new MimeMessagePreparator() {
       public void prepare(MimeMessage mimeMessage) throws Exception {
         MimeMessageHelper message = new MimeMessageHelper(mimeMessage);
         message.setTo(user.getEmailAddress());
         message.setFrom(defaultFrom);
         Map model = new HashMap();
         model.put("user", user);
         model.put("month", getMonth(calendar.get(Calendar.MONTH)));
         String text = VelocityEngineUtils.mergeTemplateIntoString(
                velocityEngine, "reminderMail-format.vm", model);
         message.setSubject("Reminder for timesheet approval");
         message.setText(text, true);
       }};
       preparatorList.add(preparator);
     }
     MimeMessagePreparator[] preparatorArray = new
                              MimeMessagePreparator[userList.size()];
     preparatorList.toArray(preparatorArray);
     mailSender.send(preparatorArray);
   }

  /**
   * Gets the month as a String representation.
   *
   * @param month The month
   * @return monthAsString The month in a String representation.
   */
   private String getMonth(int month) {
     return MONTHS[month];
   }

   /* Setter Methods */
   public void setVelocityEngine(VelocityEngine velocityEngine) {
     this.velocityEngine = velocityEngine;
   }

   public void setMailSender(JavaMailSender mailSender) {
     this.mailSender = mailSender;
   }

   public void setDefaultFrom(String defaultFrom) {
     this.defaultFrom = defaultFrom;
   }
}

Configuration of MailServiceImpl as a bean in email-configuration.xml

<bean id="mailService">
  <property name="mailSender" ref="mailSender" />
  <property name="velocityEngine" ref="velocityEngine" />
  <property name="defaultFrom" value="${mail.default.from}" />
</bean>

Step-3:
Define velocity template for email format:
Now we need to define our velocity template and keep it in our classpath.
Example of reminderMail-format.vm

<html>
  <body>
    <h5>
      Dear ${user.userName},
    <div>
       We kindly request you to enter your time sheet for the month of ${month}.<br>
       This is a gentle reminder to all. Please ignore this mail if you have<br>
       already fill your time sheet.
    </div>
    <br>
    Thank you for your cooperation.<br>
    Kind regards, <br>
    XYZ
   </h5>
  </body>
</html>

Step-4
Configure mailSender, velocityEngine, cronTrigger and SchedulerFactoryBean :
Now it’s time to configure other required beans in our spring configuration file (email-configuration.xml used in this example)

<bean id="mailSender">
  <property name="host" value="${mail.host}" />
  <property name="port" value="${mail.port}" />
  <property name="username" value="${mail.username}" />
  <property name="password" value="${mail.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="velocityEngine">
  <property name="velocityProperties">
    <value>
      resource.loader=class
      class.resource.loader.class=org.apache.velocity.runtime.
                             resource.loader.ClasspathResourceLoader
    </value>
  </property>
</bean>
<bean id="cronTrigger">
  <property name="jobDetail" ref="sendMailJob" />
  <!-- run on every last working day of month at 10:00 am -->
  <property name="cronExpression" value="0 0 10 LW * ?"/>
</bean>
<bean>
  <property name="triggers">
  <list>
    <ref bean="cronTrigger" />
  </list>
  </property>
</bean>

Now the above code configuration can be used by any web client or stand alone java client to schedule our email functionality. Once the beans will be loaded in the spring container, quartz scheduler will be activated and send mail on every last working day of the month at 10:00 am(as per cron expression described above).
Complete source code can be downloaded from here. In this example I have used simple web client based on SpringMVC framework.

Advertisements

About shahmukesh

I am a senior consultant and currently working with Xebia.
This entry was posted in Quartz, Spring, Velocity and tagged , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s