文章目录
实际开发时需要实现邮件发送,本文章实现如何从零实现邮件发送。也就是 Spring Boot 项目中如何实现邮箱发送。
Java发送邮箱的方式
1、前提:需要获取发件人邮箱的授权码,也就是打开POP3/IMAP/SMTP
服务设置,拿到授权码。
2、获取到邮件服务器的 smtp 地址:
服务商 | smtp服务地址 | smtp服务端口 | pop3服务地址 | pop3服务端口 |
---|---|---|---|---|
新浪: sina.com | smtp.sina.com.cn | 25 | pop3.sina.com.cn | 110 |
搜狐:sohu.com | smtp.sohu.com | 25 | pop3.sohu.com | 110 |
163:163.com | smtp.163.com | 25 | smtp.163.com | 110 |
QQ:qq.com | smtp.qq.com | 25 或 465 或 587 | smtp.qq.com | 110 |
foxmail:foxmail.com | smtp.foxmail.com | 25 | pop3.foxmail.com | 110 |
QQ企业邮箱:exmail.qq.com | smtp.exmail.qq.com | 995 | pop3.exmail.qq.com | 587/465 |
1. 基于 Javax.mail 实现
先引入依赖:
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.7</version>
</dependency>
大致的流程:
1、创建配置项变量 Properties 对象,用于声明 smtp 相关配置;
2、创建一个Session,重写一个Authenticator,用于声明发件人邮箱地址和授权码;
3、利用 session 创建一个 MimeMessage 对象,再利用 MimeMessage 创建一个 MimeMessageHelper 对象,该对象用于设置收件人、发件人、抄送、秘密抄送、主题、内容、附件、发送时间等属性;
4、利用 Transport.send 方法发送邮件。
代码示例:
@Slf4j
public class EmailJavax {
// 也可以从配置文件中取值
// smtp服务地址
private static final String senderSmtpHost = "smtp.qq.com";
// 邮箱端口号
private static final String senderSmtpPort = "465";
// 发信人邮箱
private static final String senderEmail = "[email protected]";
// 发信人邮箱授权码
private static final String senderPassword = "xxx";
/**
* 邮件发送
*
* @param subject 邮件主题
* @param content 邮件内容
* @param contentIsHtml 内容是否为html格式
* @param fromMailPersonalName 发件人昵称
* @param toMail 收件人邮箱
* @param ccMail 抄送人邮箱
* @param bccMail 秘密抄送人邮箱
* @param fileNames 文件名(本地路径)
*/
public static void sendEmail(String subject, String content, boolean contentIsHtml, String fromMailPersonalName, String toMail, String ccMail, String bccMail, List<String> fileNames) throws GeneralSecurityException, UnsupportedEncodingException, MessagingException {
// 1.创建配置项变量,用于声明 smtp 相关配置
Properties properties = System.getProperties();
// smtp服务地址
properties.put("mail.smtp.host", senderSmtpHost);
// smtp服务端口
properties.put("mail.smtp.port", senderSmtpPort);
// 开启验证
properties.put("mail.smtp.auth", "true");
// 开启TLS加密
properties.put("mail.smtp.starttls.enable", "true");
// 是否启用socketFactory,默认为true
properties.put("mail.smtp.socketFactory.fallback", "true");
MailSSLSocketFactory sf = new MailSSLSocketFactory();
sf.setTrustAllHosts(true);
properties.put("mail.smtp.ssl.enable", "true");
properties.put("mail.smtp.ssl.socketFactory", sf);
// 2.重写Authenticator,用于声明发件人邮箱地址和授权码
// 建立会话,将邮箱授权码给jvm
Session session = Session.getDefaultInstance(properties, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(senderEmail, senderPassword);
}
});
// 设置为true可以在控制台打印发送过程,生产环境关闭
session.setDebug(true);
// 3.创建MimeMessage对象
// 创建邮件对象
MimeMessage message = new MimeMessage(session);
// 创建MimeMessageHelper对象,通过MimeMessageHelper设置正文和附件,否则会导致两者显示不全
MimeMessageHelper helper = new MimeMessageHelper(message, true, "utf-8");
//设置发件人
helper.setFrom(new InternetAddress(senderEmail, fromMailPersonalName));
// 设置收件人,to为收件人,cc为抄送,bcc为密送
if (StringUtils.isEmpty(toMail)) {
log.error("邮件收件人为空");
return;
}
helper.setTo(InternetAddress.parse(toMail, false));
if (!StringUtils.isEmpty(ccMail)) {
helper.setCc(InternetAddress.parse(ccMail, false));
}
if (!StringUtils.isEmpty(bccMail)) {
helper.setBcc(InternetAddress.parse(bccMail, false));
}
// 设置邮件主题
helper.setSubject(subject);
//设置邮件正文内容
helper.setText(content, contentIsHtml);
//设置发送的日期
helper.setSentDate(new Date());
// 设置附件(注意这里的fileName必须是服务器本地文件名,不能是远程文件链接)
if (!CollectionUtils.isEmpty(fileNames)) {
for (String fileName : fileNames) {
FileDataSource fileDataSource = new FileDataSource(fileName);
helper.addAttachment(fileDataSource.getName(), fileDataSource);
}
}
// 4.调用Transport的send方法去发送邮件
Transport.send(message);
}
}
// 测试:
public class Test(){
public static void main(String[] args) throws MessagingException, GeneralSecurityException, UnsupportedEncodingException {
// excel表格的存放位置:
String fileName = "/xx/xx/xx/供应商接口参数.xlsx";
String html = "<h1>统计数据如下所示:</h1>" +
"<table border=\"1\">\n" +
" <tr>\n" +
" <th>月度销售额</th>\n" +
" <th>年度销售额</th>\n" +
" </tr>\n" +
" <tr>\n" +
" <td>10000</td>\n" +
" <td>2000000</td>\n" +
" </tr>\n" +
"</table>";
// 调方法:
EmailJavax.sendEmail("统计数据", html, true, "发送人名字", "收件人邮箱", null, null, Collections.singletonList(fileName));
}
}
关于附件上传的方法
附件上传有多种方式,除了上面用到的 FileDataSource
形式添加附件外,还有 文件、输入流的方式添加:
addAttachment(String attachmentFilename, DataSource dataSource)
addAttachment(String attachmentFilename, File file)
addAttachment(String attachmentFilename, InputStreamSource inputStreamSource)
addAttachment(String attachmentFilename, InputStreamSource inputStreamSource, String contentType)
2. 基于 org.apache.commons.mail 实现
commons
包中提供了 Email
抽象类,该类下实现了
HtmlEmail(用于HTML正文,附件邮件发送)
ImageHtmlEmail(用于HTML图片正文,附件邮件发送)
MultiPartEmail(用于附件邮件发送)
SimpleEmail(用于简单邮件发送)
其继承关系如图所示:
1、引入依赖:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-email</artifactId>
<version>1.5</version>
</dependency>
2、实现:
@Slf4j
public class EmailCommons {
// 也可以从配置文件中取值
// smtp服务地址
private static final String senderSmtpHost = "smtp.qq.com";
// 邮箱端口号
private static final String senderSmtpPort = "465";
// 发信人邮箱
private static final String senderEmail = "[email protected]";
// 发信人邮箱授权码
private static final String senderPassword = "xxx";
/**
* 邮件发送
*
* @param subject 邮件主题
* @param content 邮件内容
* @param contentIsHtml 内容是否为html格式
* @param fromMailPersonalName 发件人昵称
* @param toMail 收件人邮箱
* @param ccMail 抄送人邮箱
* @param bccMail 秘密抄送人邮箱
* @param fileList 附件
*/
public static void sendEmail(String subject, String content, boolean contentIsHtml, String fromMailPersonalName, String toMail, String ccMail, String bccMail, File[] fileList) throws GeneralSecurityException, UnsupportedEncodingException, MessagingException {
// 1.创建HtmlEmail对象
HtmlEmail email = new HtmlEmail();
// smtp服务地址
email.setHostName(senderSmtpHost);
// smtp服务端口
email.setSmtpPort("mail.smtp.port", senderSmtpPort);
email.setCharset("utf-8");
// 邮件验证
email.setAuthentication(senderEmail,senderPassword);
//设置发件人
email.setFrom(senderEmail, fromMailPersonalName);
// 设置收件人,to为收件人,cc为抄送,bcc为密送
if (StringUtils.isEmpty(toMail)) {
log.error("邮件收件人为空");
return;
}
email.addTo(toMail);
if (!StringUtils.isEmpty(ccMail)) {
email.addCc(ccMail);
}
if (!StringUtils.isEmpty(bccMail)) {
email.addBcc(bccMail);
}
// 设置邮件主题
email.setSubject(subject);
//设置邮件正文内容
if(contentIsHtml){
email.setHtmlMsg(content);
}else{
email.setMsg(content);
}
// 设置附件
if(!ObjectUtils.isEmpty(fileList)){
for (File file : fileList) {
EmailAttachment emailAttachment = new EmailAttachment();
emailAttachment.setName(MimeUtility.encodeText(file.getName()));
emailAttachment.setPath(file.getPath());
email.attach(emailAttachment);
}
}
// 4.调用send方法去发送邮件
email.send();
}
}
3、测试:
public class Test(){
public static void main(String[] args) throws MessagingException, GeneralSecurityException, UnsupportedEncodingException {
// excel表格的存放位置:
String fileName = "/xx/xx/xx/供应商接口参数.xlsx";
File file = new File(fileName);
String html = "<h1>统计数据如下所示:</h1>" +
"<table border=\"1\">\n" +
" <tr>\n" +
" <th>月度销售额</th>\n" +
" <th>年度销售额</th>\n" +
" </tr>\n" +
" <tr>\n" +
" <td>10000</td>\n" +
" <td>2000000</td>\n" +
" </tr>\n" +
"</table>";
EmailCommons.sendEmail("统计数据", html, true, "发送人名字", "收件人邮箱", null, null,new File[]{file} );
}
}
常见报错
1、535 Login Fail. Please enter your authorization code to login
原因:邮箱验证设置的账号密码错误
解决:注意参数值正确性:email.setAuthentication(发件人邮箱地址,邮箱授权码);
2、MessagingException: Got bad greeting from SMTP host: smtp.qq.com, port: 465, response: [EOF]
解决:commons.mail 发送邮件时,QQ 邮箱使用默认端口 25 即可
3. 基于 spring-boot-starter-mail 实现(推荐)
1、引入依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
2、使用配置文件:
spring:
# 配置发送邮件的配置信息
mail:
# 配置smtp服务主机地址
host: smtp.qq.com
# 发送者邮箱
username: [email protected]
# 配置密码,注意不是真正的密码,而是申请到的授权码
password: jlpXXXXXdecj
# 端口号:465或587
port: 465
# 默认的邮件编码为UTF-8
default-encoding: UTF-8
# 其他参数
properties:
mail:
# 配置SSL 加密工厂
smtp:
ssl:
# 本地测试,先放开ssl
enable: true
required: true
# 开启debug模式,这样邮件发送过程的日志会在控制台打印出来,方便排查错误
debug: true
3、实现:
/**
* 发送邮件类
*/
public class SendEmailUtil {
// 注入系统相关类
@Autowired
private JavaMailSender javaMailSender;
@Autowired
private MailProperties mailProperties;
// 发送者邮箱
// @Value("${spring.mail.username}")
// private String sendMailer;
/**
* 邮件发送1
*
* @param subject 邮件主题
* @param content 邮件内容
* @param contentIsHtml 内容是否为html格式
* @param fromMailPersonalName 发件人昵称
* @param toMail 收件人邮箱
* @param ccMail 抄送人邮箱
* @param bccMail 秘密抄送人邮箱
* @param fileNames 文件名(本地文件名)
*/
public static void sendEmail(String subject, String content, boolean contentIsHtml, String fromMailPersonalName,
String toMail, String ccMail, String bccMail, List<String> fileNames) throws MessagingException, UnsupportedEncodingException {
// true 代表支持复杂的类型
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
/* 邮件发信人:两种写法:
1. 定义成员变量获取application.yml的username属性
@Value("${spring.mail.username}")
private String sendMailer;
helper.setFrom(sendMailer,发件人名称)
2. 注入系统类的对象,然后调方法获取,获取的值也是application.yml文件中的值
@Autowired
private MailProperties mailProperties;
helper.setFrom(mailProperties.getUsername(),发件人名称);
*/
helper.setFrom(mailProperties.getUsername(), fromMailPersonalName);
// 邮件收信人 1或多个
helper.setTo(toMail);
if (!ObjectUtils.isEmpty(ccMail)) {
// 邮件抄送人
helper.setCc(ccMail);
}
if (!ObjectUtils.isEmpty(bccMail)) {
// 邮件私密抄送人
helper.setBcc(bccMail);
}
// 邮件主题
helper.setSubject(subject);
// 邮件内容 contentIsHtml值为 true 代表支持html
helper.setText(content, contentIsHtml);
// 设置附件(注意这里的fileName必须是服务器本地文件名,不能是远程文件链接)
if (!CollectionUtils.isEmpty(fileNames)) {
for (String fileName : fileNames) {
// 添加邮件附件
FileDataSource fileDataSource = new FileDataSource(fileName);
helper.addAttachment(fileDataSource.getName(), fileDataSource);
}
}
// 发送邮件
javaMailSender.send(mimeMessage);
}
/**
* 邮件发送2 -- 方法优化 -- 文件对象
*
* @param subject 邮件主题
* @param content 邮件内容
* @param contentIsHtml 内容是否为html格式
* @param fromMailPersonalName 发件人昵称
* @param toMail 收件人邮箱
* @param ccMail 抄送人邮箱
* @param bccMail 秘密抄送人邮箱
* @param files 文件对象
*/
public static void sendEmail(String subject, String content, boolean contentIsHtml, String fromMailPersonalName,
String toMail, String ccMail, String bccMail, File[] files) throws MessagingException, UnsupportedEncodingException {
MimeMessage message = javaMailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setFrom(mailProperties.getUsername(), fromMailPersonalName);
helper.setTo(toMail);
if (!ObjectUtils.isEmpty(ccMail)) {
helper.setCc(ccMail);
}
if (!ObjectUtils.isEmpty(bccMail)) {
helper.setBcc(bccMail);
}
helper.setSubject(subject);
helper.setText(content, contentIsHtml);
// 设置附件,不能是远程文件
if (!ObjectUtils.isEmpty(files)) {
for (File file : files) {
helper.addAttachment(file.getName(), file);
}
}
javaMailSender.send(message);
}
/**
* 邮件发送3 -- 方法优化 -- 使用流
*
* @param subject 邮件主题
* @param content 邮件内容
* @param contentIsHtml 内容是否为html格式
* @param fromMailPersonalName 发件人昵称
* @param toMail 收件人邮箱
* @param ccMail 抄送人邮箱
* @param bccMail 秘密抄送人邮箱
* @param fileName 文件名称
* @param fileInput 文件流
*/
public static void sendEmail(String subject, String content, boolean contentIsHtml, String fromMailPersonalName,
String toMail, String ccMail, String bccMail, String fileName, InputStreamSource fileInput) throws MessagingException, UnsupportedEncodingException {
MimeMessage message = javaMailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setFrom(mailProperties.getUsername(), fromMailPersonalName);
helper.setTo(toMail);
if (!ObjectUtils.isEmpty(ccMail)) {
helper.setCc(ccMail);
}
if (!ObjectUtils.isEmpty(bccMail)) {
helper.setBcc(bccMail);
}
helper.setSubject(subject);
helper.setText(content, contentIsHtml);
// 设置附件,不能是远程文件
if (fileInput != null) {
helper.addAttachment(fileName, fileInput);
}
javaMailSender.send(message);
}
}
关于邮件发送的方法参数: 上面几个方法,最后接收附件的参数都不一样,说明可以灵活变化
sendEmail(xxx, List<String> fileNames)
:可以接收多个附件,其中传的时候,就是附件的绝对路径sendEmail(xxx, File[] files)
:可以接收多个附件,传的时候,就是附件的文件对象sendEmail(xxx, InputStreamSource fileInput)
:接收一个附件,传的时候,就是附件的流
5、测试:
/**
* excel表格生成工具
*/
public class ExcelUtil {
/**
* 生成excel文件
*
* @param fileName excel文件路径
* @param dataList 数据列表
* @param clazz 导出对象类
* @param <T>
* @return
*/
public static <T> File generateExcel(String fileName, List<T> dataList, Class<T> clazz) {
// 生成文件
File file = new File(fileName);
// 单sheet写入
EasyExcel.write(file, clazz).sheet("XXX").doWrite(dataList);
return file;
}
/**
* 生成excel文件 -- 方法优化 -- 用流
*
* @param dataList 数据列表
* @param clazz 导出对象类
* @param <T>
* @return
*/
public static <T> ByteArrayOutputStream generateExcel(List<T> dataList, Class<T> clazz) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
// 单excel写入
EasyExcel.write(out, clazz).sheet("XXX").doWrite(dataList);
return out;
}
}
public class Test(){
public static void main(String[] args) throws MessagingException, GeneralSecurityException, UnsupportedEncodingException {
String content = "客户统计数据如附件所示";
// 测试邮件发送1
// excel表格的存放位置:
String fileName = "/xx/xx/xx/供应商接口参数.xlsx";
String html = "<h1>统计数据如下所示:</h1>" +
"<table border=\"1\">\n" +
" <tr>\n" +
" <th>月度销售额</th>\n" +
" <th>年度销售额</th>\n" +
" </tr>\n" +
" <tr>\n" +
" <td>10000</td>\n" +
" <td>2000000</td>\n" +
" </tr>\n" +
"</table>";
SendEmailUtil.sendEmail("统计数据", html, true, "发送人名字", "收件人邮箱", null, null, Arrays.asList(fileName));
// 测试邮件发送2
File excel = ExcelUtil.generateExcel("文件名", 表格映射的实体类对象, 表格映射的实体类.class);
SendEmailUtil.sendEmail("统计数据", content, false, "发送人名字", "收件人邮箱", null, null, new File[]{excel});
// 测试邮件发送3
ByteArrayOutputStream bos = ExcelUtil.generateExcel(userInfos, UserInfo.class);
SendEmailUtil.sendEmail("统计数据", content, false, "发送人名字", "收件人邮箱", null, null, fileName, new ByteArrayResource(bos.toByteArray()));
}
}
注意: 实现 excel 生成,然后发送邮箱 的代码,可以查看这篇文章:生成 excel 并发送邮箱
至此!文章的内容结束!!记得关注收藏,有更多精彩内容!!!