Suggestions for Java email templating?

Perhaps Apache Velocity could work for you?


StringTemplate is also a very nice template engine.


I ran into a similar problem about a year ago. In our case, our front end developers were all familiar with JSP, and I really did not want to throw another templating engine into the mix. I wanted something that relied on the servlet container's JSP processor to generate e-mail content for me.

It's fairly straightforward:

  1. I had to have a JSP page in my application (you can put it in /WEB-INF if you don't want it externally accessible).
  2. I wrote a custom HttpServletResponse and ServletOutputStream that captures content written by the servlet container and turns it into a String, and relied on RequestDispatcher.include(...) to make a "request" to the template JSP (I also wrote a custom HttpServletRequest to isolate the original request from mutation).
  3. Because this is a bit of a hack, and not the way the servlet API was intended to be used, I encapsulated all this in a utility class, so that all the client code has to do is pass in the path to the JSP template, and get back the processed content.

Jack Leow said he wrote a custom HttpServletResponse so that he could re-use JSPs for generating email templates, I just did the same and would like to share my code sample / prototype for those not sure where to begin:

Usually when serving a JSP page, you'd do something like this:

res.setContentType("text/html");
RequestDispatcher jsp = req.getRequestDispatcher("/WEB-INF/templates/" + template);
res.setStatus(200);
jsp.forward(req, res);

Now instead of doing that jsp.forward to an HttpServletResponse, do a jsp.forward to your custom Servlet Response:

EmailServletResponse res2 = new EmailServletResponse();
jsp.forward(req, res2);
System.out.println(res2.toString()); <<-- email gets printed here

Your EmailServlet response will simply be a class that implements HttpServletResponse, fill in the blanks and use an underlying StringWriter to accomplish the toString conversion:

public class EmailServletResponse implements HttpServletResponse {

private int status;
private StringWriter sw = new StringWriter();

@Override
public void flushBuffer() throws IOException {
    sw.flush();
}

@Override
public int getBufferSize() {
    return 1024;
}

@Override
public String getCharacterEncoding() {
    return "UTF-8";
}

@Override
public String getContentType() {
    return "text/html";
}

@Override
public Locale getLocale() {
    return Locale.getDefault();
}

@Override
public ServletOutputStream getOutputStream() throws IOException {
    return new ServletOutputStream() {
        @Override
        public void write(int b) throws IOException {
            sw.write(b);
        }
    };
}

@Override
public PrintWriter getWriter() throws IOException {
    PrintWriter pw = new PrintWriter(sw);
    return pw;
}

@Override
public boolean isCommitted() {
    return false;
}

@Override
public void reset() {       
}

@Override
public void resetBuffer() {
}

@Override
public void setBufferSize(int arg0) {
}

@Override
public void setCharacterEncoding(String arg0) {
}

@Override
public void setContentLength(int arg0) {
}

@Override
public void setContentType(String arg0) {
}

@Override
public void setLocale(Locale arg0) {
}

@Override
public void addCookie(Cookie arg0) {
}

@Override
public void addDateHeader(String arg0, long arg1) {
}

@Override
public void addHeader(String arg0, String arg1) {
}

@Override
public void addIntHeader(String arg0, int arg1) {
}

@Override
public boolean containsHeader(String arg0) {
    return false;
}

@Override
public String encodeRedirectURL(String arg0) {
    return "";
}

@Override
public String encodeRedirectUrl(String arg0) {
    return "";
}

@Override
public String encodeURL(String arg0) {
    return "";
}

@Override
public String encodeUrl(String arg0) {
    return "";
}

@Override
public void sendError(int arg0) throws IOException {

}

@Override
public void sendError(int arg0, String arg1) throws IOException {

}

@Override
public void sendRedirect(String arg0) throws IOException {

}

@Override
public void setDateHeader(String arg0, long arg1) {

}

@Override
public void setHeader(String arg0, String arg1) {


}

@Override
public void setIntHeader(String arg0, int arg1) {

}

@Override
public void setStatus(int status) {
    this.status = status;
}

@Override
public void setStatus(int status, String message) {
    setStatus(status);
}

public String toString(){
    return sw.getBuffer().toString();
}
}

Feel free to improve on the code where needed, this was a quick prototyping session :)