目录
场景与方案分析
最近博主做了一个项目,有一个业务场景是这样的:
后台管理员发布活动的时候可以上传与此活动相关的几个文件,用户报名某活动之后,将这些文件以附件的方式发送到其邮箱。
综上需求,我先介绍一下我们系统的情况:
1、文件可能上传多个,所以邮件的发送涉及到多附件上传;
2、我们的系统是前后端分离的,文件模块采用的是分布式的MinIO服务器,都是外网服务器上的线上文件,不是落在Java项目所运行的服务器磁盘上;
3、为了用户体验,邮件中的每个附件名称都要是用户上传时的原文件名称。
以上三点我们依次考虑,
第一点无所谓,我们只需要一个for循环即可;
第二点,因为我们的文件存储在专门的文件服务器上,所以我们需要读取文件的IO流,而不是指定本地磁盘上的文件路径;
第三点,我们在上传文件的时候记录了文件的原名称,在发送邮件时要用一个实体类声明文件的外网路径(用于获取IO流)以及文件的原名称。
开启QQ邮箱的SMTP服务
要发送邮件,就涉及到邮件发送方,在项目中一般是公司的企业账号,但是测试、学习用我们自己的QQ邮箱也是可以的,步骤很简单,在你的QQ邮箱里进行如下操作:
然后点击“账户”,往下滑:
点击“开启”,腾讯就会对你的身份进行验证,验证通过之后会给你一个授权码,将这个授权码保存好,作为你发送邮件的凭证。
实体类准备
我们将文件在外网的路径和原名称,用一个实体类来表示,在发送邮件时将该实体类的集合作为实参,达到多附件的效果。
package com.dosion.model.activity.entity.activity;
import lombok.Data;
/**
* <p>
* 活动课件
* </p>
*
* @author 秋枫艳梦
* @date 2019-12-03
* */
@Data
public class ActivityCourse {
//原文件名
private String fileName;
//文件的外网路径
private String filePath;
public ActivityCourse () {}
public ActivityCourse (String fileName , String filePath) {
this.fileName = fileName;
this.filePath = filePath;
}
}
工具类准备
package com.dosion.utils;
import com.alibaba.druid.util.StringUtils;
import com.dosion.model.activity.entity.activity.ActivityCourse;
import com.sun.mail.util.MailSSLSocketFactory;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.activation.URLDataSource;
import javax.mail.*;
import javax.mail.internet.*;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
public class EmailUtils {
// 发件人电子邮箱
private static String from = "你的QQ@qq.com";
// 发件人电子邮箱授权码
private static String pass = "你的授权码";
//设置QQ邮箱服务器
private static String host = "smtp.qq.com";
/**
* 发送带附件的邮件
*
* @param receive 收件人
* @param subject 邮件主题
* @param msg 邮件内容
* @param courseList 课件附件的地址集合
* @return
* @throws GeneralSecurityException
*/
public static void sendMail(String receive, String subject, String msg, List<ActivityCourse> courseList)
throws GeneralSecurityException, MalformedURLException {
// 获取系统属性
Properties properties = System.getProperties();
// 设置邮件服务器
properties.setProperty("mail.smtp.host", host);
properties.put("mail.smtp.auth", "true");
MailSSLSocketFactory sf = new MailSSLSocketFactory();
sf.setTrustAllHosts(true);
properties.put("mail.smtp.ssl.enable", "true");
properties.put("mail.smtp.ssl.socketFactory", sf);
// 获取默认session对象
Session session = Session.getDefaultInstance(properties, new Authenticator() {
public PasswordAuthentication getPasswordAuthentication() { // qq邮箱服务器账户、第三方登录授权码
return new PasswordAuthentication(from, pass); // 发件人邮件用户名、密码
}
});
try {
//创建MimeMessage 对象
MimeMessage message = new MimeMessage(session);
//设置发送人
message.setFrom(new InternetAddress(from));
//设置接收人
message.addRecipient(Message.RecipientType.TO, new InternetAddress(receive));
//设置邮件主题
message.setSubject(subject);
// 创建普通消息部分
BodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setText(msg);
// 创建多重消息
Multipart multipart = new MimeMultipart();
// 设置多重消息的文本消息部分
multipart.addBodyPart(messageBodyPart);
//设置多重消息的附件部分
int size = courseList.size();
URL url;
for (int i = 0; i < size; i++) {
// 发送多个附件部分
messageBodyPart = new MimeBodyPart();
String path = courseList.get(i).getFilePath();
String fileName = courseList.get(i).getFileName();
// 设置要发送附件的文件IO流
url = new URL(path);
DataSource source = new URLDataSource(url);
messageBodyPart.setDataHandler(new DataHandler(source));
//设置附件名称
messageBodyPart.setFileName(MimeUtility.encodeText(fileName));
multipart.addBodyPart(messageBodyPart);
}
//设置最终的邮件
message.setContent(multipart);
//发送
Transport.send(message);
} catch (MessagingException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
测试
我们从京东上随便找一张图片:
再从我们的项目上拉一个xls文件:
duxiaohui.dosion.cc/activity/system/file/activity-ee5452ddeeb649dd8cc5ac63ef6c443d.xls
public static void main(String[] args) throws GeneralSecurityException, MalformedURLException {
List<ActivityCourse> courseList = new ArrayList<>();
courseList.add(new ActivityCourse("京东商品图片.png","https://img10.360buyimg.com/mobilecms/s500x500_jfs/t1/86469/24/3091/112229/5ddcc257E7f8899db/d51bbc277e44ed94.jpg"));
courseList.add(new ActivityCourse("每日一答__模板.xls","http://duxiaohui.dosion.cc/activity/system/file/activity-ee5452ddeeb649dd8cc5ac63ef6c443d.xls"));
sendMail("xxx@qq.com","多附件测试-博客","多附件正文,消息",courseList);
}
执行这个main方法,可以看到已经收到邮件了: