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方法的第二参数,通过调用setHtmlTextToMimePartsetPlainTextToMimePart来实现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正文的三种方式(一)【附带源码】相关推荐

  1. 【021】基于springboot的党务管理系统(含管理员、用户党支部三种身份(附源码数据库)

    文章目录 一.运行结果截图 二.源码获取方式: 三.保姆级操作教程: 一.运行结果截图 (详细操作过程见文末,保姆级) 技术栈:springboot.mysql.vue.mybatis.layui 我 ...

  2. Java的三种代理模式完整源码分析

    Java的三种代理模式&完整源码分析 Java的三种代理模式&完整源码分析 参考资料: 博客园-Java的三种代理模式 简书-JDK动态代理-超详细源码分析 [博客园-WeakCach ...

  3. java解析遍历List集合(其实现子类)的三种方式

    java解析遍历List集合(其实现子类)的三种方式 1 使用迭代器对象 1.1 底层 1.1.1 List接口继承了Collection接口 1.1.2 而Collection接口又继承了Itera ...

  4. java获取小程序中用户的unionId的三种方式

    前提条件: 想要获取unionId,必须几个小程序或者公众号在同一个主体之下,要不然没有unionId,只会生成用户的openid,可登陆下面这个微信官方平台查看 https://open.weixi ...

  5. java时间戳是什么类型_java 获取时间戳的三种方式

    java 获取时间戳的三种方式 CreationTime--2018年7月13日16点29分 Author:Marydon 1.实现方式 方式一:推荐使用 System.currentTimeMill ...

  6. java类初始数组_java中数组初始化的三种方式是什么

    java中数组初始化的三种方式是:1.静态初始化,如[int a[] = {2, 0, 1, 9, 2020}]:2.动态初始化,如[int[] c = new int[4]]:3.默认初始化,如[i ...

  7. java 实现邮件带附件发送

    邮件发送测试案例 1. 这里以网易邮箱做案例:注册网易邮箱并开通smtp服务 开启smtp服务并保存授权码(很重要) 2. 在 maven 项目的 pom.xml中引入依赖 <!-- 邮件发送依 ...

  8. MQ发送普通消息(三种方式)

    MQ 发送普通消息有三种实现方式:可靠同步发送.可靠异步发送.单向(Oneway)发送.本文介绍了每种实现的原理.使用场景以及三种实现的异同,同时提供了代码示例以供参考. 可靠同步发送 原理:同步发送 ...

  9. java 如何初始化数组_java中初始化数组的三种方式分别是什么

    三种初始化方式: 1.静态初始化:创建+赋值 2.动态初始化:先创建再赋值 3.默认初始化:创建之后若不赋值则会被赋对应数据类型的默认值 (视频教程推荐:java视频) 我们来看一下具体代码:publ ...

最新文章

  1. Java中的某些接口为什么没有任何方法?
  2. docker 部署_Kooteam搭建之Docker部署
  3. BZOJ2490 Zombie’s Treasure Chest
  4. pytorch 加载模型_福利,PyTorch中文版官方教程来啦(附下载)
  5. Oracle视图添加约束,Oracle创建视图的语法
  6. 2020年上半年家电市场报告
  7. 其实没有啥好说的公司组织去清远漂流
  8. python functools.reduce_Python之functools.reduce使用
  9. Java类加载器 以及类加载器的委托模型
  10. Major GC 是清理老年代。 Full GC 是清理整个堆空间—包括年轻代和老年代。
  11. 中国首个芯片大学最快于本月底在南京挂牌;​华为方舟编译器正式支持 C 语言;Ora2Pg v21.0 发布|极客头条
  12. db2审计功能db2audit导致的数据库宕机问题处理
  13. python求解矩阵搜索问题,矩阵中每一行和第一列都是递增的 给定一个元素查找矩阵中是否存在该元素
  14. xml mysql 树形数据删除_使用递归删除树形结构的所有子节点(java和mysql实现)
  15. TIA博途_如何更新程序中的指令版本和CPU固件版本?
  16. Nginx+php+mysql超时问题总结
  17. 最实用的上网网址一览表
  18. 村长选举c语言程序,大村长-第一章 选举-爱阅小说网
  19. 悉尼大学理学院计算机科学,悉尼大学理学院本科申请
  20. ActiveMQ 安装及使用过程

热门文章

  1. C#多线程加载控件界面卡死的解决
  2. [python][GUI]pyside6
  3. F0011: error while parsing the configuration: File contains no section headers....
  4. RMAN简明教程之六——RMAN的管理
  5. plugin(插件)
  6. 腾讯开源柠檬 Lemon
  7. 导师建议(20210714)
  8. 视频驱动程序概念整理
  9. matlab非线性相位fir,数字信号处理实验(MATLAB版)实验23线性相位FIR数字滤波器.ppt...
  10. Flask_Tool上传下载压缩文件