当前位置:首页 > 开发 > 开源软件 > 正文

Javax mail实现模板邮件发送

发表于: 2013-09-27   作者:arthur8   来源:转载   浏览次数:
摘要:        最近,在开发工作中有这么的需求,使用模板技术加javax mail发送模板邮件,经历的一系列的蛋疼时刻终于搞定,在这里做下总结,以备以后在遇到类似问题,方便查找。      使用VelocityEngine + Spring完成模板解析,VelocityTemplateMailProcessor.java: &

       最近,在开发工作中有这么的需求,使用模板技术加javax mail发送模板邮件,经历的一系列的蛋疼时刻终于搞定,在这里做下总结,以备以后在遇到类似问题,方便查找。

     使用VelocityEngine + Spring完成模板解析,VelocityTemplateMailProcessor.java:

    

   
/**
 * 处理velocity邮件模板,将template中参数替换为真实值
 * 
 * @author Arthur
 * 
 */
public class VelocityTemplateMailProcessor implements TemplateMailProcessor {

	private final static Logger LOGGER = Logger
			.getLogger(VelocityTemplateMailProcessor.class);

	/**
	 * 使用velocity模板引擎处理邮件模板,支持在velocity等模板文件中对时间和数字进行格式化支持
	 * 
	 * @param templateLocation
	 *            邮件模板路径:例如在src/main/resoures下有一个example.tpl文件,
	 *            则起对应的tamplateLocation为example.tpl
	 * @param charsetEncoding
	 *            读取邮件模板使用的charset
	 * @param attributeMap
	 *            模板中对应占位符的值map
	 * @return
	 */
	public String process(String templateLocation, String charsetEncoding,
			Map<String, Object> attributeMap) {
		// First, volidate attributeMap, make sure "dateTool" & "numberTool" not
		// used by application
		this.validate(attributeMap);

		try {
			Properties prop = new Properties();
			prop.put("file.resource.loader.class",
					"org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
			// 增加date和number格式化支持
			try {
				VelocityTemplateMailProcessor.class.getClassLoader().loadClass(
						"org.apache.velocity.tools.generic.DateTool");
				LOGGER.info("DateTool 'org.apache.velocity.tools.generic.DateTool' found in classpath and support date format");
				DateTool dateTool = new DateTool();
				attributeMap.put("dateTool", dateTool);
			} catch (ClassNotFoundException e) {
				// not exist, just skip
			}

			try {
				VelocityTemplateMailProcessor.class.getClassLoader().loadClass(
						"org.apache.velocity.tools.generic.NumberTool");
				LOGGER.info("NumberTool 'org.apache.velocity.tools.generic.NumberTool' found in classpath and support numberic format");
				NumberTool numberTool = new NumberTool();
				attributeMap.put("numberTool", numberTool);
			} catch (ClassNotFoundException e) {
				// not exist, just skip
			}

			VelocityEngineFactoryBean factoryBean = new VelocityEngineFactoryBean();
			factoryBean.setVelocityProperties(prop);
			VelocityEngine velocityEngine = factoryBean.createVelocityEngine();
			LOGGER.debug("VelocityEngine initialization is ok");

			return VelocityEngineUtils.mergeTemplateIntoString(velocityEngine,
					templateLocation, charsetEncoding, attributeMap);
		} catch (Exception e) {
			LOGGER.error("use VelocityEngine to process mail template["
					+ "templateLocation" + "] error", e);
			throw new ParseTemplateException(e);
		}
	}

	private void validate(Map<String, Object> attributeMap) {
		if (attributeMap.get("dateTool") != null) {
			throw new IllegalArgumentException(
					"dateTool is reserved field not for application, Please make sure it's not used");
		}

		if (attributeMap.get("numberTool") != null) {
			throw new IllegalArgumentException(
					"numberTool is reserved field not for application, Please make sure it's not used");
		}
	}
}

      ok,使用该类完成邮件模板的解析工作,接着发送邮件,邮件发送类这里就不贴出来了;

      使用javax mail发送邮件时最容易遇到的问题就是邮件内容和标题的乱码,对于内容乱码,相信很多人都遇到过,也都知道怎么解决。

       至于标题乱码有点棘手,需要对邮件title进行Base64编码,防止邮件标题中文乱码,但是这里就需要对使用哪个Base64实现类进行选择,

       不幸的是开始楼主选择了Sun的sun.misc.BASE64Encoder进行encode,结果发现有的邮件乱码,有的邮件正常;好蛋疼!!

       经过楼主的排查,翻阅javax mail源码(MimeMessage、MimeUtility.java、PropUtil.java)发现在MimeMessage.java中:

public void setSubject(String subject, String charset)
			throws MessagingException {
	if (subject == null) {
	    removeHeader("Subject");
	} else {
	    try {
		setHeader("Subject", MimeUtility.fold(9,
		    MimeUtility.encodeText(subject, charset, null)));
	    } catch (UnsupportedEncodingException uex) {
		throw new MessagingException("Encoding error", uex);
	    }
	}
    }

    该方法调用到了MimeUtility.fold()方法

 public static String fold(int used, String s) {
	if (!foldText)
	    return s;

	int end;
	char c;
	// 请注意这里
	// Strip trailing spaces and newlines
	for (end = s.length() - 1; end >= 0; end--) {
	    c = s.charAt(end);
	    if (c != ' ' && c != '\t' && c != '\r' && c != '\n')
		break;
	}
	if (end != s.length() - 1)
	    s = s.substring(0, end + 1);

	// 一下省略啦
	......
    }

       该方法遇到""、\t、\r、\n就会将邮件标题截取,剩余部分默认将其作为邮件内容;

       回过头来,再看下sun.misc.BASE64Encoder.encode(),sun的base64实现完全遵循了Base64(RFC2045~RFC2049)规范,将加密后的字符串每76个字符后插入回车换行符,这就导致了邮件标题base64之后不完整,而且邮件内容多了一部分,导致邮件无法被解析展示。

       最后楼主经过测试使用了apache的Base64实现org.apache.commons.codec.binary.Base64,该实现对加密后的Base64字符串不进行任何回车换行的操作。

       OK,这里把解决邮件标题乱码的部分代码贴出来:

String subject = new String(Base64.encodeBase64("subject".getBytes("UTF-8")));
mailMessage.setSubject("=?UTF-8?B?" + subject + "?=");

 

 

   第一次写博客,写的不好还请轻拍:)

Javax mail实现模板邮件发送

  • 0

    开心

    开心

  • 0

    板砖

    板砖

  • 0

    感动

    感动

  • 0

    有用

    有用

  • 0

    疑问

    疑问

  • 0

    难过

    难过

  • 0

    无聊

    无聊

  • 0

    震惊

    震惊

编辑推荐
本文是《轻量级 Java Web 框架架构设计》的系列博文。 在 Java 应用系统中为了实现邮件发送与收取功
这个问题困扰了我很久,获取到gmail繁体内容了,并且还试过 String ones = (String) part.getConten
1.freeMarker封装后的工具类 2.发送邮件的模板(mailWFTFile.ftl) 親愛的客戶您好:<br> &nbs
前言:OA自动发送邮件的程序不好使,SQL Server 存储过程邮件发送程序好使,但是不利于标准化和维护
Java Mail是利用已存在的邮箱账号,不必登录如网易邮箱,qq邮箱等官方邮箱网站而使用程序发送邮件。
想为游戏服务器添加一个自动报警功能,所以需要发送邮件,直接下载了Javamail,里面的例子可以直接
通过java的网络编程特性,完成邮件发送的功能,效果图如下: 第一步,新建java项目,MailTest 第二
通过java的网络编程特性,完成邮件发送的功能,效果图如下: 首先新建一个maiTest的java项目, 然后
通过java的网络编程特性,完成邮件发送的功能,效果图如下: 第一步,新建java项目,MailTest 第二
想为游戏服务器添加一个自动报警功能,所以需要发送邮件,直接下载了Javamail,里面的例子可以直接
版权所有 IT知识库 CopyRight © 2009-2015 IT知识库 IT610.com , All Rights Reserved. 京ICP备09083238号