阿里云部署项目,使用465端口,JavaMail发送邮件,乱码问题解决

最近App加了一个发邮件的功能,就用spring的javaMail写了下。

整个开发过程没啥难的,需求就是打包发送一些附件,再来点模板,没想到最后栽在了编码问题上,忘了那本书说过了。

软件开发,编码问题将伴随你的一生

附上一些配置

  1. 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. 邮件配置
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. 代码
  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加密端口来发送邮件。