Using Spring Mail with Velocity

Mail is a common feature in many applications and even with the support provided by Spring, you may find yourself creating the same code in every application just to build the correct structure for a message. You will also find that using a wholly programmatic approach to message construction places too much of the message content inside your application, making it difficult to modify this content. We have found that a flexible solution to this problem is to create a reusable implementation of the MimeMessagePreparator interface that creates a message in a common structure and obtains message content from Velocity templates.

Velocity is a templating engine that allows you to create any kind of textual output by merging text-based templates with Java Objects. Velocity is most widely used as a replacement or complement to JSP in the Web Tier, as discussed in http://jakarta.apache.org/velocity, or you can read Pro Jakarta Velocity: From Professional to Expert by Rob Harrop (Apress, 2004).

We have found that a message structure that works well in most mail clients is simply to provide both plain text and HTML content in a single multipart. We have found that it is better to avoid embedded images and host them on a web server instead. You can link to them in the standard way from within the HTML content.

For the solution shown in this section, we created a class, VelocityMimeMessagePreparator, that is designed to be configured using DI. This means you can define an instance of VelocityMimeMessagePreparator in your Spring configuration, setting important properties such as the sender and recipients addresses as well the Velocity templates to use for the plain text and HTML message parts. At runtime, you simply obtain the VelocityMimeMessagePreparator bean from Spring and pass it a Map containing the data you wish to merge with the templates. Spring also provides excellent support for Velocity, meaning that you can configure the VelocityEngine instance used by the VelocityMimeMessagePreparator in your configuration file. Listing 15-17 shows the code for the VelocityMimeMessagePreparator class.

Listing 15-17: The VelocityMimeMessagePreparator Class

image from book
package com.apress.prospring.ch15.velocity;      import java.util.Map;      import javax.mail.BodyPart; import javax.mail.Message; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeBodyPart; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMultipart;      import org.apache.velocity.app.VelocityEngine; import org.springframework.beans.factory.InitializingBean; import org.springframework.mail.javamail.MimeMessagePreparator; import org.springframework.ui.velocity.VelocityEngineUtils;      public class VelocityMimeMessagePreparator implements MimeMessagePreparator,         InitializingBean {          private VelocityEngine velocityEngine;          private String plainTextTemplate = "plainText.vm";          private String htmlTemplate = "html.vm";          private String from;          private String to;          private String subject;          private Map data;          public void prepare(MimeMessage msg) throws Exception {         // set header details         msg.addFrom(InternetAddress.parse(from));         msg.addRecipients(Message.RecipientType.TO, InternetAddress.parse(to));         msg.setSubject(subject);              // create wrapper multipart/alternative part         MimeMultipart ma = new MimeMultipart("alternative");         msg.setContent(ma);              // create the plain text         BodyPart plainText = new MimeBodyPart();         plainText.setText(VelocityEngineUtils.mergeTemplateIntoString(                 velocityEngine, plainTextTemplate, data));         ma.addBodyPart(plainText);              //  create the html part         BodyPart html = new MimeBodyPart();         html.setContent(VelocityEngineUtils.mergeTemplateIntoString(                 velocityEngine, htmlTemplate, data), "text/html");         ma.addBodyPart(html);     }          public void afterPropertiesSet() throws Exception {         if (velocityEngine == null) {             throw new IllegalArgumentException(                     "Must set the velocityEngine property of "                             + getClass().getName());         }     }          public void setPlainTextTemplatePath(String plainTextTemplate) {         this.plainTextTemplate = plainTextTemplate;     }          public void setHtmlTemplatePath(String htmlTemplate) {         this.htmlTemplate = htmlTemplate;     }          public void setVelocityEngine(VelocityEngine velocityEngine) {         this.velocityEngine = velocityEngine;     }          public void setTo(String to) {         this.to = to;     }          public void setFrom(String from) {         this.from = from;     }          public void setSubject(String subject) {         this.subject = subject;     }          public void setData(Map data) {         this.data = data;     }      }
image from book

As you can see, there is nothing particularly clever about this code. We create a MimeMessage using the structure shown earlier in the section entitled "Sending an HTML Mail Message with Plain Text Alternative." Notice, however, that we do not directly create an instance of VelocityEngine—this is provided using DI, because we use the VelocityEngineUtils class provided by Spring to interact with Velocity. A more complex implementation of this class would provide support for adding CC and BCC recipients, but note that this implementation does support multiple TO recipients, because the call to InternetAddress.parse() returns InternetAddress[] and successfully parses comma-separated lists of addresses.

Listing 15-18 shows a simple plain text template you can use with this class.

Listing 15-18: A Simple Plain Text Template

image from book
This is the plain text mail.      The message of the day is: $msg.
image from book

Here you can see we have a Velocity template that contains a single variable field, $msg. At runtime, we can specify a value for that field. Listing 15-19 shows the corresponding HTML template, which also contains a $msg variable.

Listing 15-19: The HTML Message Template

image from book
<html>     <head></head>     <body>     <h1>This is the HTML mail</h1>     <h2>Today's message is: <em>$msg</em></h2>     <img src="/books/1/144/1/html/2/http://www.apress.com/img/v2/hdr_logo.gif">     </body> </html>
image from book

Notice that instead of using a Content-ID for the image source, we used a standard URL pointing to an image stored on the Apress web server.

In Listing 15-20, you can see a sample configuration file that configures a VelocityMimeMessagePreparator bean.

Listing 15-20: Configuring the VelocityMimeMessagePreparator

image from book
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"  "http://www.springframework.org/dtd/spring-beans.dtd"> <beans>     <bean             >         <property name="to">             <value>robh@cakesolutions.net</value>         </property>         <property name="from">             <value>mail@apress.com</value>         </property>         <property name="subject">             <value>Mail Using Velocity</value>         </property>         <property name="plainTextTemplatePath">             <value>./ch15/src/vm/plainText.vm</value>         </property>         <property name="htmlTemplatePath">             <value>./ch15/src/vm/html.vm</value>         </property>         <property name="velocityEngine">           <bean />         </property>     </bean>     </beans>
image from book

This configuration is fairly basic but you can see that it allows for easy modification not only of basic message parameters, such as the sender address, but also of the templates that make up the plain text and HTML parts of the message. To supply the VelocityMimeMessagePreparator class with an instance of VelocityEngine, we use the VelocityEngineFactoryBean supplied by Spring. We use the default VelocityEngine configuration, but had we wanted to, we could have modified this configuration using the VelocityEngineFactoryBean.

To use this class in an application, all you need to do is obtain the bean from Spring along with an instance of JavaMailSender, configure the VelocityMimeMessagePreparator with some data to merge into the template, and then invoke the JavaMailSender.send() method, as shown in Listing 15-21.

Listing 15-21: Using the VelocityMimeMessagePreparator Class

image from book
package com.apress.prospring.ch15.velocity;      import java.util.HashMap; import java.util.Map;      import org.springframework.context.ApplicationContext; import org.springframework.context.support.FileSystemXmlApplicationContext; import org.springframework.mail.javamail.JavaMailSender;      public class VelocityRunner {          public static void main(String[] args) {         ApplicationContext ctx = new FileSystemXmlApplicationContext(                 new String[] { "./ch15/src/conf/velocity.xml",                         "./ch15/src/conf/javaMailSender.xml" });              JavaMailSender sender = (JavaMailSender) ctx.getBean("sender");         VelocityMimeMessagePreparator preparator =                        (VelocityMimeMessagePreparator) ctx.getBean("preparator");              Map data = new HashMap();         data.put("msg", "Hello World!");              preparator.setData(data);              sender.send(preparator);     } }
image from book

Figure 15-13 shows the resulting plain text message and Figure 15-14 shows the resulting HTML message.

image from book
Figure 15-13: Plain text message generated by Velocity

image from book
Figure 15-14: HTML message generated by Velocity



Pro Spring
Pro Spring
ISBN: 1590594614
EAN: 2147483647
Year: 2006
Pages: 189

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net