需求:批量发邮件给用户,邮件是html的,有个按钮点了可以下载附件或html之类的
想法:java基本的发邮件的工具是JavaMail,而我用的是alpha的comnoms-email。然后呢,html的内容也不少,不可能用StringBuilder去拼一个字符串吧,所以我就使用freemarker模板,去生成html。后面又说邮件要分状态,某个状态下是下载附件,这个是已经上传到阿里oss上了,直接打开那个oss地址就行;但某个状态是要本地生成一个html,然后上传到oss上,然后拿回调的oss地址去下载。很6的是这个本地生成的html其实是已经有了的,但是它是在前端Vue项目里的,所以说可以复用。但是呢,我还真没试过在freemaker里去搞vue,有这功夫谁会在模板引擎里用,直接前后台分离啊歪。好吧,需求如此,开干。
首先是,集成下所需的jar包:
org.apache.commons
commons-email
1.4
org.freemarker
freemarker
2.3.30
然后,实现发邮件的功能,同时生成html邮件。使用Juint运行commons-email官方示例。
@Test
public void test() throws EmailException {
HtmlEmail email = new HtmlEmail();
// hostName为你发送邮件的账号的smtp服务器,一般每种邮箱都有特定的smtp服务器
// 比如:smtp.163.com是163邮箱的,端口25,身份认证是:账号和登录密码
// smtp.qq.com是qq邮箱的,端口465,身份认证是:账号和QQ邮箱授权码
email.setHostName("smtp.163.com");
email.setSmtpPort(25);
// 账号和密码
email.setAuthentication("***@163.com", "***");
// 将要发送邮件的接受人和称呼
email.addTo("**@qq.com", "weic");
// 发送人和称呼
email.setFrom("*@163.com", "Me");
// 邮件主题
email.setSubject("Test email with inline image");
// 字符编码
email.setCharset("UTF-8");
// embed the image and get the content id
URL url = new URL("http://www.apache.org/images/asf_logo_wide.gif");
String cid = email.embed(url, "Apache logo");
// set the html message
email.setHtmlMsg("The apache logo - ");
// set the alternative message
email.setTextMsg("你的email不支持html格式");
// send the email
email.send();
}
运行下,可以看看你是否接收到邮件
现在思考下一个需求点,邮件不再是一个简单的html页面,可能需要一些花里胡哨的操作。那可以使用freemarker模板引擎生成对应的html,总好过自己去搞html字符串。
首先,在resources文件下新建一个email/template文件,然后将我们用到的ftl模板放入。需要注意的是如果我们是在test下跑的junit,需要在test中java的同级目录新建一个resources文件,然后通过Mark将其标记为资源文件,之后重复resources的流程。
index.ftl
Hello World!
用于测试的Html邮件
${name}的名片
${name}
<#--${sex}
-->
<#--${age}岁
-->
电话:
10086
邮箱:
****@**.com
juint test方法
HtmlEmail email = new HtmlEmail();
// hostName为你发送邮件的账号的smtp服务器,一般每种邮箱都有特定的smtp服务器
// 比如:smtp.163.com是163邮箱的,端口25,身份认证是:账号和登录密码
// smtp.qq.com是qq邮箱的,端口465,身份认证是:账号和QQ邮箱授权码
email.setHostName("smtp.163.com");
email.setSmtpPort(25);
// 账号和密码
email.setAuthentication("***@163.com", "***");
// 将要发送邮件的接受人和称呼
email.addTo("**@qq.com", "weic");
// 发送人和称呼
email.setFrom("*@163.com", "Me");
// 邮件主题
email.setSubject("Test email with inline image");
// 字符编码
email.setCharset("UTF-8");
// 开启ssl
email.setSSLCheckServerIdentity(true)
// 读取SendEmail的根目录,这里就是target的目录
String baseURL = Objects.requireNonNull(SendEmail.class.getClassLoader().getResource("")).getPath();
StringWriter html = new StringWriter();
try {
// freemarker指定版本
Configuration cfg = new Configuration(Configuration.VERSION_2_3_30);
//指定对象模板存放的位置
cfg.setDirectoryForTemplateLoading(new File(baseURL+"/email/template"));
//设置字符集
cfg.setDefaultEncoding("utf-8");
// 通过map设置参数
Map rootMap = new HashMap<>(20);
rootMap.put("logo", "http://www.apache.org/images/asf_logo_wide.gif");
rootMap.put("name", "Hello World!");
rootMap.put("btnText", "点击一下");
rootMap.put("downloadUrl", "");
// 读取模板
Template template = cfg.getTemplate("index.ftl");
// 写入参数
template.process(rootMap, html);
} catch (IOException e) {
e.printStackTrace();
} catch (TemplateException e) {
e.printStackTrace();
}
// set the html message
email.setHtmlMsg(html.toString());
// set the alternative message
email.setTextMsg("你的email不支持html格式");
// send the email
email.send();
看下效果:
在代码中我们有一个downloadUrl参数,他的作用是点击下载一个html,但是呢,这个html需要本地去生成,然后上传到oss上。也就是说我们需要oss回调的地址,作为download的地址。
...
String baseURL = Objects.requireNonNull(SendEmail.class.getClassLoader().getResource("")).getPath();
// 在本地生成一个html
File afile = new File(baseURL + "test.html");
try {
Configuration cfg = new Configuration(Configuration.VERSION_2_3_30);
//指定对象模板存放的位置
cfg.setDirectoryForTemplateLoading(new File(baseURL+"/email/template"));
//设置字符集
cfg.setDefaultEncoding("utf-8");
Template template = cfg.getTemplate("resume.ftl");
// 为resume.ftl模板写入数据
Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(afile), "UTF-8"));
template.process(result, out);
out.flush();
out.close();
// 通过oss上传html
OSS ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
// 通过雪花算法生成唯一文件名
String fileName = Snowflake.generateId() + ".html";
PutObjectRequest putObjectRequest = new PutObjectRequest(bucket, fileName , afile);
ossClient.putObject(putObjectRequest);
ossClient.shutdown();
// 获取地址,注:oss的相关配置应提前准备好,webHost地址为oss地址前缀
onlinePath = webHost + fileName;
// 如果文件存在删除
if (afile.exists()) {
afile.delete();
}
} catch (Exception e) {
e.printStackTrace();
// 如果文件存在删除
if (afile.exists()) {
afile.delete();
}
}
...
resume.ftl
!DOCTYPE html>