I’ve been using the App Engine Mail API for a while now to send emails in plain text format, but recently decided to beef it up to allow HTML formatting. In addition, I wanted a template-based approach so I could more easily modify the email contents. To achieve both purposes, I chose Apache Velocity, an easy-to-use, general purpose framework that lets you easily create anything textual from a template (text, email, XML, even Java code once on a previous project).
The main subtlety to observe when using Velocity with App Engine is that by default, Velocity uses the filesystem resource loader to load templates. This works fine in the App Engine development server and should also work in production as long as you put your templates in the WAR. Since my project is using Maven, however, the standard way to do this is to put templates in src/main/resources and let Maven automatically copy them to WEB-INF/classes during the build. In order for Velocity to see them on the classpath, you need Velocity’s ClasspathResourceLoader, so I created a helper class that lazily initializes the Velocity engine with the required resource loader:
/**
* Singleton that initializes Velocity engine instance with the classpath resource loader
*
* @author David Chandler
*/
public class VelocityHelper {
private static VelocityEngine velocityEngine;
static VelocityEngine getVelocityEngine() {
if (velocityEngine == null)
init();
return velocityEngine;
}
private static void init() {
velocityEngine = new VelocityEngine();
Properties velocityProperties = new Properties();
velocityProperties.put("resource.loader", "class");
velocityProperties.put("class.resource.loader.description", "Velocity Classpath Resource Loader");
velocityProperties.put("class.resource.loader.class",
"org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
velocityEngine.init(velocityProperties);
}
}
To use the template, first populate the VelocityContext with variables to be replaced, then merge the template:
VelocityContext context = new VelocityContext();
context.put("date", today);
context.put("username", "johndoe");
VelocityEngine ve = VelocityHelper.getVelocityEngine();
// Finds template in WEB-INF/classes
template = ve.getTemplate("emailTemplate.vm");
StringWriter writer = new StringWriter();
template.merge(context, writer);
Since we’re sending an HTML email, the template is just an HTML file named emailTemplate.vm (by convention–.vm stands for Velocity macro). The template merge substitutes variables like ${date} with their values from the VelocityContext populated above. You can also loop over Collections with #foreach ($item in $list) … #end.
Now let’s send the email. There are a couple things to observe here.
First, webmail readers like Gmail write the HEAD and BODY tags to the page, so the browser will likely ignore these tags in your HTML template. This means you can’t link a stylesheet in the HEAD section of your HTML and expect it to work across email clients. The most compatible approach is to use inline styles, that is, the style=”” attribute on various HTML tags right in your template.
Second, in order to send HTML email, you must set the MIME type correctly. Here is the code that takes the template output, sets the MIME type, and sends the email:
import java.util.Properties;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.servlet.ServletException;
...
Properties props = new Properties();
Session session = Session.getDefaultInstance(props, null);
try
{
Message msg = new MimeMessage(session);
msg.setFrom(from);
msg.addRecipient(Message.RecipientType.TO, to);
msg.setSubject(msgSubject);
if (msgBody.startsWith("<!DOCTYPE html"))
msg.setContent(msgBody, "text/html");
else
msg.setText(msgBody);
Transport.send(msg);
}
catch (AddressException e)
{
throw new ServletException(e);
}
catch (MessagingException e)
{
throw new ServletException(e);
}
That’s it in a nutshell. Spam away…
/dmc
Like this:
Like Loading...