Suggestions for Java email templating?

69,376

Solution 1

StringTemplate is also a very nice template engine.

Solution 2

Perhaps Apache Velocity could work for you?

Solution 3

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 :)

Solution 4

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.

Solution 5

I prefer Freemarker, here over Velocity; imo, Freemarker much simpler in this case.

If you are using Spring, then you may be interested in, Freemarker in Spring MVC.

Share:
69,376

Related videos on Youtube

J. Scarbrough
Author by

J. Scarbrough

Technology Professional

Updated on February 14, 2020

Comments

  • J. Scarbrough
    J. Scarbrough about 4 years

    we have an application that needs to send out various different types of template email. The current code is very cumbersome and not very flexible. Does any one konw of a library to help with this type of work... We are looking for some kind of templating library for email.

  • Lordn__n
    Lordn__n over 15 years
    +1 I've used Velocity + Spring for exactly this before.
  • Evan
    Evan over 15 years
    Me too. (Velocity, not Spring)
  • Chase Seibert
    Chase Seibert over 15 years
    Good call. As a side-note, you would want to do the replacements BEFORE passing the subject/body content into an API like JavaMail. Otherwise, you may end-up producing an invalid EML file due to encoding or line wrap issues.
  • J. Scarbrough
    J. Scarbrough about 15 years
    We ended up using StringTemplate. Very simple yet flexible for our situation.
  • Andriy Drozdyuk
    Andriy Drozdyuk about 13 years
    But, oh! what a horrible website it has. The feedback form is broken. It is also not in Maven. What is it about Java culture that says it's ok to throw-things-together and make em look crappy and expect people to "use" them? Compare Django (python-based project) documentation to the one of ANY java product. I am very disappointed. I am going to use Velocity - even though it has side-effects, is bloated and probably worse.
  • GabiMe
    GabiMe over 12 years
    If you need to import it through maven you can find it here: mvnrepository.com/artifact/org.antlr/ST4
  • Rich Apodaca
    Rich Apodaca about 12 years
    If you like StringTemplate, you may like Google Soy Templates even better: developers.google.com/closure/templates Also, what drozzy said.
  • Jan Vladimir Mostert
    Jan Vladimir Mostert over 10 years
    Did you work from an example? I quite like the idea of using JSP templates.
  • Jack Leow
    Jack Leow over 10 years
    No, it's something I came up with at a previous job. Unfortunately I don't have access to the code anymore.
  • Jan Vladimir Mostert
    Jan Vladimir Mostert over 10 years
    See my code sample here, it's actually fairly simple: stackoverflow.com/a/20847683/527533
  • Zied Hamdi
    Zied Hamdi about 10 years
    This can be very useful if you don't want to add jars to your project : it's my case since I'm on GAE and every added jar adds its weight on instance startups. So thanks for the tip, I didn't come to it by my self :)
  • Jan Vladimir Mostert
    Jan Vladimir Mostert about 10 years
    PS, rather use HttpServletResponseWrapper
  • Jake Toronto
    Jake Toronto about 10 years
    StringTemplate has a bit of a learning curve compared to Velocity/Freemarker. Also, I know the developer of StringTemplate has a NetBeans plugin that provides syntax highlighting, but I couldn't get it to work very easily; and I use Eclipse, any way. StringTemplate is theoretically superior; but it comes with an initial cost.
  • Jake Toronto
    Jake Toronto about 10 years
    if you front the jsps with a controller or servlet, then you can use the request parameters to load full objects for use in the JSPs
  • Jake Toronto
    Jake Toronto about 10 years
    +1 for Freemarker being a little more strict than Velocity in what it allows.
  • Zied Hamdi
    Zied Hamdi about 10 years
    Yes but I would recommend to avoid that if you plan to separate the mail server from the rest of the application later (especially that nowadays we always have personalized mails : because you have to insert the unsubscribe link with the client id, you call the person by her name, etc.. so there might be as many jsp processing as the mail campaign (thousands at least). Having that task done on the same "main" server could reduce the front end performance