Java电子邮件模板的建议?

44
我们有一个应用程序需要发送各种不同类型的模板电子邮件。当前的代码非常繁琐,也不太灵活。有没有人知道可以帮助处理这种工作的库?我们正在寻找一种适用于电子邮件模板的模板库。
9个回答

25

1
好的建议。另外,您需要在将主题/正文内容传递到像JavaMail这样的API之前进行替换。否则,由于编码或换行问题,您可能会生成无效的EML文件。 - Chase Seibert
我们最终使用了StringTemplate。非常简单,但对我们的情况非常灵活。 - J. Scarbrough
1
但是,哦!它有一个多么可怕的网站。反馈表单已经损坏了。它也不在Maven中。关于Java文化,它为什么认为把东西拼凑在一起,让它们看起来很糟糕,并期望人们“使用”它们是可以接受的呢?将Django(基于Python的项目)文档与任何Java产品的文档进行比较。我非常失望。我将使用Velocity - 即使它具有副作用,臃肿且可能更糟。 - Andriy Drozdyuk
2
如果您需要通过maven导入它,可以在这里找到它:http://mvnrepository.com/artifact/org.antlr/ST4 - Erlend Halvorsen
2
如果您喜欢StringTemplate,那么您可能会更喜欢Google Soy Templates:https://developers.google.com/closure/templates/ 此外,也要听听drozzy说的话。 - Rich Apodaca
StringTemplate 相对于 Velocity/Freemarker 学习曲线有点陡峭。此外,我知道 StringTemplate 的开发者有一个 NetBeans 插件,提供语法高亮功能,但我很难让它轻松工作;而我使用的是 Eclipse。理论上,StringTemplate 更优秀;但需要付出一定的初始成本。 - Jake Toronto

23

2
+1 我以前就用过 Velocity + Spring 来完成这个任务。 - cletus
我也是。(Velocity,不是Spring) - Evan

23

Jack Leow说他编写了一个自定义的HttpServletResponse,以便可以重用JSP来生成电子邮件模板,我也做了同样的事情,并且想分享我的代码示例/原型给那些不确定如何开始的人:

通常在提供JSP页面时,您会执行类似以下操作:

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

现在,不要将 jsp.forward 转发给 HttpServletResponse,而是将其转发到您的自定义 Servlet Response:

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

您的EmailServlet响应只需实现HttpServletResponse接口,并填写空白部分,使用底层的StringWriter来完成toString转换:

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();
}
}

如有需要,请随意改进代码。这只是一个快速的原型设计会话 :)


PS,最好使用HttpServletResponseWrapper。 - Jan Vladimir Mostert

18

大约一年前,我遇到了类似的问题。在我们的情况下,我们的前端开发人员都熟悉JSP,我真的不想让另一个模板引擎加入到混合中。我想要一些依赖于Servlet容器的JSP处理器来为我生成电子邮件内容的东西。

步骤相对简单:

  1. 我必须在我的应用程序中有一个JSP页面(如果您不希望它被外部访问,可以将其放在/WEB-INF中)。
  2. 我编写了一个自定义的HttpServletResponseServletOutputStream,捕获Servlet容器写入的内容并将其转换成字符串,并依靠RequestDispatcher.include(...)向模板JSP发送“请求”(我还编写了一个自定义的HttpServletRequest以隔离原始请求免受变异的影响)。
  3. 因为这有点像黑客行为,而不是Servlet API预期的使用方式,所以我将所有这些封装在一个实用类中,这样所有客户端代码只需传递JSP模板的路径,就可以获得已处理的内容。

1
你是从示例中工作的吗?我非常喜欢使用JSP模板的想法。 - Jan Vladimir Mostert
不,这是我在以前的工作中想出来的东西。不幸的是,我现在无法访问代码了。 - Jack Leow
4
看一下我的代码示例,它其实非常简单:https://dev59.com/l3RB5IYBdhLWcg3w9Lzn#20847683 - Jan Vladimir Mostert
如果您不想将JAR文件添加到项目中,这将非常有用:这也是我的情况,因为我在GAE上,并且每个添加的JAR文件都会增加实例启动时的负担。所以感谢您的提示,我自己没有想到这一点 :) - Zied Hamdi

17

我更喜欢Freemarker,而不是Velocity;在我看来,这种情况下Freemarker要简单得多。

如果你正在使用Spring,那么你可能对Spring MVC中的Freemarker感兴趣。


Freemarker比Velocity在允许的内容方面要严格一些,这点值得肯定。 - Jake Toronto

8

3

如果你喜欢StringTemplate,那么你可能会更喜欢Google Soy。个人认为,它的可用性更好、组织更为合理、文档更加完整、支持更加强大。


2
也可以创建一个类似于“邮件内容JSP”的页面来实现此功能。
mails/orderConfirmed.jsp
mails/sendingYourOrderNotification.jsp

然后只需对"/mails/*.jsp"进行http客户端请求,以获取您想要的邮件内容。
我认为这是jsp的公平使用,因为您无论如何都想生成HTML,并且请求自己的服务器不会消耗带宽。
好处是您可以进行jsp包含,甚至使用更高级的库,例如tiles、jsf、struts、wicket。您不需要学习新的工具,可以使用您已经知道的东西。Jsp是一种相当高效的模板引擎,它们存在于2000年以来。
坏处是您不能使用键入的变量来组合jsp,您仅限于将字符串作为请求参数(或一个好的大json :-))
这也是隔离代码甚至在需要性能优化时拆分服务器的良好方法。

1
如果您在JSP之前使用控制器或servlet,则可以使用请求参数来加载完整对象以供在JSP中使用。 - Jake Toronto
1
是的,但如果您计划稍后将邮件服务器与应用程序的其余部分分离(特别是现在我们总是有个性化的邮件),我建议避免这样做:因为您必须插入带有客户ID的取消订阅链接,称呼收件人姓名等,所以可能会有与邮件活动一样多的JSP处理(至少数千个)。在同一“主”服务器上完成此任务可以降低前端性能。 - Zied Hamdi

0

有一个示例可以使用 Snippetory 来发送电子邮件。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接