Wednesday, March 31, 2010

Velocity templates for Email

When sending customized emails a developer faces how to make template available to those in charge of configuring how the content will look like.

Apache Velocity is a perfect template Engine that allows the developer to send emails keeping separation of concerns.

I am showing here three pieces of code. The first shows a typical velocity template, the second how to merge some context variables into the template and the third just a wrapper over the Java Mail API. It should be straightforward to put them all together.

A Velocity Template

<h1>Welcome to $welcomeTo</h1>
    <div id="countdown">
      #set($list = ["4", "3", "2", "1", "Blast Off!"])

      #foreach($item in $list)
        $item
      #end

    </div>
    <h2>Products</h2>
    <p>Buying $productList.size() products!</p>
    #set( $count = 1 )

    <TABLE>
        #foreach( $prod in $productList )

          <TR>
            <TD>$count</TD>
            <TD>$prod.product</TD>
            <TD>$prod.price</TD>
          </TR>
          #set( $count = $count + 1 )
        #end

    </TABLE>
    <h2>Billing address</h2>
    <div id="billing-address">
        Name: $userMap.name<br/>
        Country: $userMap.country<br/>
        City: $userMap.city<br/>
    </div>

Java merging some cotext into template

import java.io.StringWriter;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.VelocityContext;
import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;

public class VelocityExample
{
public static void main( String args[] ) throws Exception
{
//Init the runtime engine.

Velocity.init();

//Make a Context

VelocityContext context = new VelocityContext();

//Put simple data in it
context.put("welcomeTo", "New York");
context.put("technology", "Velocity");

//More complex data
List list = new ArrayList();
Map map = new HashMap();

map.put("product", "umbrella");
map.put("price", "$9.99");
list.add( map );

map = new HashMap();
map.put("product", "shoes");
map.put("price", "$39.99");
list.add( map );

map = new HashMap();
map.put("product", "pants");
map.put("price", "$19.99");
list.add( map );

Map userMap = new HashMap();
userMap.put("name", "Mr Bean");
userMap.put("country", "UK");
userMap.put("city","London");



context.put("productList", list);
context.put("userMap", userMap);


//render a template

StringWriter w = new StringWriter();

Velocity.mergeTemplate("testtemplate.vm", context, w );
System.out.println(" template : " + w );

//Render a String

String s = "We are using $technology to render this string";
w = new StringWriter();
Velocity.evaluate( context, w, "mystring", s );
System.out.println(" string : " + w );
}
}

A Java Mail API wrapper

import java.util.Properties;

import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.Multipart;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;


public class EmailService {

public void sendEmail(String emailServer, String mailFrom, String rcptTo, String subject, String textMessage, String htmlMessage) throws Exception{
sendEmail(emailServer, mailFrom, rcptTo, subject, textMessage, htmlMessage, null, null);
}

public void sendEmail(String emailServer, String mailFrom, String rcptTo, String subject, String textMessage, String htmlMessage, String rcptCc, String rcptBcc) throws Exception{
boolean sendText = !Utils.isEmpty(textMessage);
boolean sendHTML = !Utils.isEmpty(htmlMessage);
if(!sendText){
throw new Exception("I need a message at least in plain text. I also handle HTML. Please supply the message to proceed.");
}
if(!sendText && !sendHTML){
throw new Exception("I need a message in plain text, HTML or both to proceed.");
}
// Create the message to send
Properties props = new Properties();
props.put("mail.smtp.host", emailServer);
Session session = Session.getInstance(props,null);
MimeMessage message = new MimeMessage(session);

// Create the email addresses involved
InternetAddress from = new InternetAddress(mailFrom);
//InternetAddress to = new InternetAddress(rcptTo);

// Fill in header
message.setSubject(subject);
message.setFrom(from);
if (!Utils.isEmpty(rcptTo)) {
message.addRecipients(Message.RecipientType.TO, InternetAddress.parse(rcptTo.replaceAll(";", ",")));
}
if(!Utils.isEmpty(rcptCc)){
message.addRecipients(Message.RecipientType.CC, InternetAddress.parse(rcptCc.replaceAll(";", ",")));
}
if(!Utils.isEmpty(rcptBcc)){
message.addRecipients(Message.RecipientType.BCC, InternetAddress.parse(rcptBcc.replaceAll(";", ",")));
}

// Create a multi-part to combine the parts
Multipart multipart = new MimeMultipart("alternative");

// Create your text message part
BodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setText(textMessage);

// Add the text part to the multipart
multipart.addBodyPart(messageBodyPart);

if(sendHTML){
// Create the html part
messageBodyPart = new MimeBodyPart();
messageBodyPart.setContent(htmlMessage, "text/html");
}


// Add html part to multi part
multipart.addBodyPart(messageBodyPart);

// Associate multi-part with message
message.setContent(multipart);

// Send message
Transport.send(message);
}
}

1 comment:

Ekta said...

Can I get the complete code?

Followers