springboot:java实现邮件及附件发送、HTML正文的三种方式(一)【附带源码】
0. 引言
邮件发送是我们日常开发中比较常见的功能,常用于预警信息提醒、统计数据定期发送等需求。一般该方法会由前人封装好,实际开发时只需要调用即可,但具体怎么实现的,如何从零实现邮件发送,这是我们要掌握的。
所以今天我们就整理一下java实现邮件发送的三种方式,供大家参考。
- 基于javax.mail实现
- 基于org.apache.commons.mail实现
- 基于spring-boot-starter-mail实现
1. 环境准备
1.1 开发环境
以下演示均基于各组件当前最新的稳定版本实现,jdk基于1.8版本
commons-email 1.5
javax.mail 1.4.7
spring-boot-starter-mail 跟随springboot版本,文中演示的是2.3.7.RELEASE
1.2 开启邮箱协议与授权
其次我们需要了解的是,程序要发送邮件,是需要一个邮箱账号的, 并且其账号需要开启SMTP邮件协议以及邮件授权码,并不是密码。
以下我们以QQ邮箱为例,示范其开启过程,其他邮箱大同小异。
1、登陆邮箱,点击设置
,进入账户
,下拉页面
2、找到POP3/IMAP/SMTP
服务设置。这里我们可以开启POP3/SMTP
或者IMAP/SMTP
服务,两者的区别
3、点击开启
后,会要求你发送短信验证
4、发送后,点击我已发送
,然后会给你一个授权码,将该码保存下来,这就是我们需要的授权码。
5、其次我们需要获取到邮件服务器的smtp地址,比如我们这里用的是qq邮箱,其地址就是smtp.qq.com
。对应类型邮箱的smtp地址直接百度即可。
1.3 常见的邮箱服务及端口
服务商 | 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 | pop3.163.com | 110 |
QQ qq.com | smtp.qq.com | 25 | pop3.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 |
2. 实现
2.1 javax.mail实现
2.1.1 思路
利用javax.mail实现邮件发送功能主要分成一下几步:
1、创建配置项变量Properties
对象,用于声明smtp相关配置
2、重写一个Authenticator
,用于声明发件人邮箱地址和授权码
3、基于上述两步创建的对象,创建一个Session
4、利用session创建一个MimeMessage
对象,再利用MimeMessage创建一个MimeMessageHelper
对象,该对象用于设置收件人、发件人、抄送、秘密抄送、主题、内容、附件、发送时间等属性
5、利用Transport.send
方法发送邮件
在清楚了实现流程后,我们直接上代码演示
2.1.2 实操
1、引入依赖
<dependency><groupId>javax.mail</groupId><artifactId>mail</artifactId><version>1.4.7</version>
</dependency>
2、创建工具类,实现发送功能
/*** @author benjamin_5* @Description* @date 2022/10/3*/
public class EmailJavaxUtil {private static final Logger logger = LoggerFactory.getLogger(EmailJavaxUtil.class);// 发件人smtp邮箱服务地址private static final String senderSmtpHost = "smtp.qq.com";// 发件人邮箱地址private static final String senderEmail = "xxx@qq.com";// smtp邮箱授权码private static final String senderPassword = "xxx";// 端口private static final String senderSmtpPort = "465";private static void sendEmail(String subject, String content,boolean contentIsHtml, String fromMailPersonalName,String toMail, String ccMail, String bccMail, List<String> fileNames)throws GeneralSecurityException, UnsupportedEncodingException, MessagingException {// 设置参数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,默认为trueproperties.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);// 建立会话,利用内部类将邮箱授权给jvmSession session = Session.getDefaultInstance(properties, new Authenticator() {@Overrideprotected PasswordAuthentication getPasswordAuthentication() {return new PasswordAuthentication(senderEmail, senderPassword);}});// 设置为true可以在控制台打印发送过程,生产环境关闭session.setDebug(true);// 创建邮件对象MimeMessage message = new MimeMessage(session);// 通过MimeMessageHelper设置正文和附件,否则会导致两者显示不全MimeMessageHelper helper = new MimeMessageHelper(message,true,"utf-8");//设置收件人,to为收件人,cc为抄送,bcc为密送if (StringUtils.isEmpty(toMail)) {logger.error("邮件收件人为空");return;}//设置发件人helper.setFrom(new InternetAddress(senderEmail, fromMailPersonalName));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);}}//调用Transport的send方法去发送邮件Transport.send(message);}}
3、调用测试
public static void main(String[] args) throws MessagingException, GeneralSecurityException, UnsupportedEncodingException {String fileName = "/Library/project/study/java/mail_send_demo/src/main/resources/供应商接口参数.xlsx";sendEmail("测试邮件1","这是一封测试邮件",false,"55555","wuhanxue5@sina.com",null,null, Collections.singletonList(fileName));}
4、可以看到邮件正常接收到了
2.1.3 补充内容
1、需要注意的是如果采用如下的方式设置附件和正文的话,会导致两者有一个不显示。如下,附件设置在后就会覆盖设置的正文内容,正文内容在后就会覆盖附件内容。
//设置邮件正文内容
message.setText(content);
if(!CollectionUtils.isEmpty(fileNames)){// 附件上传组件Multipart multipart =new MimeMultipart("mixed");for (String fileName : fileNames) {MimeBodyPart bodyPart = new MimeBodyPart();FileDataSource fileDataSource = new FileDataSource(fileName);bodyPart.setDataHandler(new DataHandler(fileDataSource));// 解决附件中文名乱码bodyPart.setFileName(MimeUtility.encodeText(fileDataSource.getName(), "utf-8", null));// 添加附件multipart.addBodyPart(bodyPart);}// 附件的设置语句必须放在设置正文内容之后,否则会导致附件设置为空message.setContent(multipart);
}
解决的办法就是使用MimeMessageHelper
类来实现,如上述演示所示。
2、附件上传有多种方式,除了上述演示的使用FileDataSource
形式添加附件外,还有文件、输入流的方式来添加,可以结合需求多样开发。
addAttachment(String attachmentFilename, DataSource dataSource)
addAttachment(String attachmentFilename, File file)
addAttachment(String attachmentFilename, InputStreamSource inputStreamSource)
addAttachment(String attachmentFilename, InputStreamSource inputStreamSource, String contentType)
同时看源码会发现,除了addAttachment
方法外,addInline
方法也能添加附件。生产开发复制粘贴上述的工具类完全足够,但是要想进一步理解,深入掌握组件,更需要大家去阅读源码,了解api方法的多样性。
2.1.3 邮件正文为html格式
有时我们需要自定义我们邮件正文的样式,也就需要发送html格式的邮件正文。那么这又怎么实现呢?
其实眼尖的同学会发现,我上述提供的工具类中已经提供了一个contentIsHtml
参数,用来标识内容是否为html
其实现利用了MimeMessageHelper
提供的setText方法的第二参数,通过调用setHtmlTextToMimePart
或setPlainTextToMimePart
来实现html正文的解析
话不多说,我们来测试一下
public static void main(String[] args) throws MessagingException, GeneralSecurityException, UnsupportedEncodingException {String fileName = "/Library/project/study/java/mail_send_demo/src/main/resources/供应商接口参数.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>";sendEmail("统计数据",html,true,"55555","wuhanxue5@sina.com",null,null, Collections.singletonList(fileName));}
邮件正常接收并且html样式显示正常
源码地址
以上演示的源码可以在如下地址中下载
git源码地址
关注专栏,了解后续内容
基于org.apache.commons.mail实现邮件发送
基于spring-boot-starter-mail实现邮件发送
springboot:java实现邮件及附件发送、HTML正文的三种方式(一)【附带源码】相关推荐
- 【021】基于springboot的党务管理系统(含管理员、用户党支部三种身份(附源码数据库)
文章目录 一.运行结果截图 二.源码获取方式: 三.保姆级操作教程: 一.运行结果截图 (详细操作过程见文末,保姆级) 技术栈:springboot.mysql.vue.mybatis.layui 我 ...
- Java的三种代理模式完整源码分析
Java的三种代理模式&完整源码分析 Java的三种代理模式&完整源码分析 参考资料: 博客园-Java的三种代理模式 简书-JDK动态代理-超详细源码分析 [博客园-WeakCach ...
- java解析遍历List集合(其实现子类)的三种方式
java解析遍历List集合(其实现子类)的三种方式 1 使用迭代器对象 1.1 底层 1.1.1 List接口继承了Collection接口 1.1.2 而Collection接口又继承了Itera ...
- java获取小程序中用户的unionId的三种方式
前提条件: 想要获取unionId,必须几个小程序或者公众号在同一个主体之下,要不然没有unionId,只会生成用户的openid,可登陆下面这个微信官方平台查看 https://open.weixi ...
- java时间戳是什么类型_java 获取时间戳的三种方式
java 获取时间戳的三种方式 CreationTime--2018年7月13日16点29分 Author:Marydon 1.实现方式 方式一:推荐使用 System.currentTimeMill ...
- java类初始数组_java中数组初始化的三种方式是什么
java中数组初始化的三种方式是:1.静态初始化,如[int a[] = {2, 0, 1, 9, 2020}]:2.动态初始化,如[int[] c = new int[4]]:3.默认初始化,如[i ...
- java 实现邮件带附件发送
邮件发送测试案例 1. 这里以网易邮箱做案例:注册网易邮箱并开通smtp服务 开启smtp服务并保存授权码(很重要) 2. 在 maven 项目的 pom.xml中引入依赖 <!-- 邮件发送依 ...
- MQ发送普通消息(三种方式)
MQ 发送普通消息有三种实现方式:可靠同步发送.可靠异步发送.单向(Oneway)发送.本文介绍了每种实现的原理.使用场景以及三种实现的异同,同时提供了代码示例以供参考. 可靠同步发送 原理:同步发送 ...
- java 如何初始化数组_java中初始化数组的三种方式分别是什么
三种初始化方式: 1.静态初始化:创建+赋值 2.动态初始化:先创建再赋值 3.默认初始化:创建之后若不赋值则会被赋对应数据类型的默认值 (视频教程推荐:java视频) 我们来看一下具体代码:publ ...
最新文章
- Java中的某些接口为什么没有任何方法?
- docker 部署_Kooteam搭建之Docker部署
- BZOJ2490 Zombie’s Treasure Chest
- pytorch 加载模型_福利,PyTorch中文版官方教程来啦(附下载)
- Oracle视图添加约束,Oracle创建视图的语法
- 2020年上半年家电市场报告
- 其实没有啥好说的公司组织去清远漂流
- python functools.reduce_Python之functools.reduce使用
- Java类加载器 以及类加载器的委托模型
- Major GC 是清理老年代。 Full GC 是清理整个堆空间—包括年轻代和老年代。
- 中国首个芯片大学最快于本月底在南京挂牌;​华为方舟编译器正式支持 C 语言;Ora2Pg v21.0 发布|极客头条
- db2审计功能db2audit导致的数据库宕机问题处理
- python求解矩阵搜索问题,矩阵中每一行和第一列都是递增的 给定一个元素查找矩阵中是否存在该元素
- xml mysql 树形数据删除_使用递归删除树形结构的所有子节点(java和mysql实现)
- TIA博途_如何更新程序中的指令版本和CPU固件版本?
- Nginx+php+mysql超时问题总结
- 最实用的上网网址一览表
- 村长选举c语言程序,大村长-第一章 选举-爱阅小说网
- 悉尼大学理学院计算机科学,悉尼大学理学院本科申请
- ActiveMQ 安装及使用过程
热门文章
- C#多线程加载控件界面卡死的解决
- [python][GUI]pyside6
- F0011: error while parsing the configuration: File contains no section headers....
- RMAN简明教程之六——RMAN的管理
- plugin(插件)
- 腾讯开源柠檬 Lemon
- 导师建议(20210714)
- 视频驱动程序概念整理
- matlab非线性相位fir,数字信号处理实验(MATLAB版)实验23线性相位FIR数字滤波器.ppt...
- Flask_Tool上传下载压缩文件