最近App加了一个发邮件的功能,就用spring的javaMail写了下。
整个开发过程没啥难的,需求就是打包发送一些附件,再来点模板,没想到最后栽在了编码问题上,忘了那本书说过了。
软件开发,编码问题将伴随你的一生
附上一些配置
- spring-content.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="${mail.host}"/>
<property name="port" value="${mail.port}"/>
<property name="username" value="${mail.username}"/>
<property name="password" value="${mail.password}"/>
</bean>
<bean id="freeMarker" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<!-- 指定模板文件目录 -->
<property name="templateLoaderPath" value="classpath:" />
<!-- 设置FreeMarker环境属性 -->
<property name="freemarkerSettings">
<props>
<!--刷新模板的周期,单位为秒 -->
<prop key="template_update_delay">1800</prop>
<!--模板的编码格式 -->
<prop key="default_encoding">UTF-8</prop>
<!--本地化设置-->
<prop key="locale">zh_CN</prop>
</props>
</property>
</bean>
|
- 邮件配置
1
2
3
4
5
6
|
mail.host=smtp.163.com
mail.port=465
mail.username=xxxxxx@163.com
mail.password=xxxxxx
#mail.zip.path=/usr/local/zip/
mail.zip.path=E://invoice/
|
- 代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
@Service
public class MailService {
private static final Logger logger = LoggerFactory.getLogger(MailRestController.class);
@Autowired
private JavaMailSenderImpl mailSender;
@Autowired
private FreeMarkerConfigurer freeMarker;
@Value("${mail.username}")
private String from;
@Value("${upload.path}")
private String invoicePath;
@Value("${mail.zip.path}")
private String zipPath;
/**
* 发送带有附件的email
*/
public RestResult sendEmailWithAttachment(MailParameter mailParameter) {
Properties javaMailProperties = new Properties();
javaMailProperties.put("mail.smtp.auth", true);
javaMailProperties.put("mail.smtp.ssl.enable", "true");
javaMailProperties.put("mail.smtp.timeout", 5000);
javaMailProperties.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
mailSender.setJavaMailProperties(javaMailProperties);
//设置默认编码 防止内容乱码
mailSender.setDefaultEncoding("UTF-8");
try {
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true,"UTF-8");
helper.setFrom(new InternetAddress(from,"Telami"));
helper.setTo(mailParameter.getMail());
//这里就是为了防止主题乱码的,网上大多教程也是这样做的
helper.setSubject(MimeUtility.encodeText( "您有一封邮件","UTF-8","B"));
helper.setText(getMailText(), true);
//插入图片
ClassPathResource image = new ClassPathResource("content.png");
helper.addInline("content", image);
//拼接图片路径
List<String> wholeInvoicePaths = mailParameter.getInvoiceAddresses()
.stream()
.map(address -> invoicePath + address)
.collect(Collectors.toList());
String fileName = zipInvoices(wholeInvoicePaths);
FileSystemResource zip = new FileSystemResource(zipPath + fileName);
helper.addAttachment("一个压缩包.zip", zip);
mailSender.send(message);
} catch (SMTPSendFailedException e) {
logger.error("send email fail {}",e);
return RestResult.build(RestExceptionEnum.SERVER_ERROR);
} catch (IOException e) {
logger.error("send email fail {}",e);
return RestResult.build(RestExceptionEnum.SERVER_ERROR);
} catch (MessagingException e) {
logger.error("send email fail {}",e);
return RestResult.build(RestExceptionEnum.SERVER_ERROR);
}
logger.info("邮件发送完毕");
return RestResult.ok();
}
/**
* 通过模板构造邮件内容,参数content将替换模板文件中的${content}标签。
*/
private String getMailText() {
String htmlText = null;
try {
// 通过指定模板名获取FreeMarker模板实例
Template template = freeMarker.getConfiguration().getTemplate("invoice.html");
// FreeMarker通过Map传递动态数据
Map<String, String> map = new HashMap<String, String>();
map.put("code", "爱生活,爱telami");
htmlText = FreeMarkerTemplateUtils.processTemplateIntoString(template, map);
} catch (IOException e) {
e.printStackTrace();
} catch (TemplateException e) {
e.printStackTrace();
}
return htmlText;
}
/**
* 打包
*
* @param invoicePaths
*/
public String zipInvoices(List<String> invoicePaths) throws IOException {
File f = new File(zipPath);
if (!f.exists()){
f.mkdirs();
}
String zipFileName = IdGen.uuid() + ".zip";
ZipOutputStream zouts = new ZipOutputStream(new FileOutputStream(zipPath + zipFileName));
byte[] buf = new byte[4096];
int readByte;
for (int i = 0; i < invoicePaths.size(); i++) {
File file = new File(invoicePaths.get(i));
FileInputStream fin = new FileInputStream(file);
zouts.putNextEntry(new ZipEntry(file.getName()));
while ((readByte = fin.read(buf)) != -1) {
zouts.write(buf, 0, readByte);
}
zouts.closeEntry();
fin.close();
}
zouts.close();
return zipFileName;
}
```
----------
整个过程就是找到指定路径下的多个文件,打包,作为附件发送到用户邮箱。
模板用的freemarker,传了点参数。模板就不放出来了,写的比较简陋。
- 防止内容乱码比较简单
```java
//设置默认编码 防止内容乱码
mailSender.setDefaultEncoding("UTF-8");
|
1
2
|
//这里就是为了防止主题乱码的,网上大多教程也是这样做的,“B”就是使用base64编码
helper.setSubject(MimeUtility.encodeText( "您有一封邮件","UTF-8","B"));
|
到此为止其实都没啥问题,按部就班的写就行了。但是!!!!!!!!!
我一开始是把主题这个字段,配置在了properties文件里面了,注入到了service中,没想到就是这个原因,导致我用尽了网上了方法都不好使。。。
ps:在本地测试无论你的主题是注入进来的,还是写死的都没问题,但是部署在阿里云上就会出现问题,原因就是properties文件编码导致的,这个文件应该设置成UTF-8编码。
哦对了,阿里云屏蔽了25端口,防止垃圾邮件的横行,所以我们只能用465加密端口来发送邮件。