文章目录

  • 1. 前言
    • 1.1 说明
    • 1.2 建议
    • 1.3 源码
  • 2. 发件人邮箱开通smtp 服务
    • 2.1 为什么开通smtp 服务
    • 2.2 开启服务的步骤
    • 2.3 普通邮箱开启服务图文
  • 3. 工具类封装
    • 3.1 邮件依赖管理
    • 3.2 日志依赖管理
    • 3.3 邮件工具类封装
  • 4. 工具类测试及效果演示
  • 5. 邮件发送API 测试及效果演示

内个, 祝各位七夕快乐 ^ _ ^

1. 前言

1.1 说明

此处为Java 版,封装了邮件发送工具,支持smtp 服务的邮箱,对发件人邮箱要求开通smtp 服务,否则不会发送邮件。
    发件邮箱发件过多时,可能会被收件邮箱作为恶意发件人,之后再接收该发件人的邮件会作为垃圾邮件。

1.2 建议

生产环境配置多发件人使用轮询机制发送。
    收件人标记发件人不是垃圾邮件。

1.3 源码

https://github.com/niaonao/email

2. 发件人邮箱开通smtp 服务

2.1 为什么开通smtp 服务

点击链接可以看下原理
    简单的说,邮件可以通过smtp 协议在各个邮件服务器之间传输。

2.2 开启服务的步骤

  • 开启smtp服务;
  • 获取授权码/密码;

此授权码用于第三方邮件客户端登录时作为账号密码验证账号登录。
    授权码可以重置。

    /*** 邮件发送者账户* 邮件发送协议 smtp 账号密码/账号授权码*/private static final String emailSenderAccount = "2171128382@qq.com";private static final String emailSenderAuthCode = "ojaerigbrwgmdjed";

2.3 普通邮箱开启服务图文

(1)腾讯邮箱

图2-1.腾讯邮箱开启SMTP 服务图

图2-2.请求获取授权码图

图2-3.获取授权码图

(2)网易邮箱

图2-4.网易邮箱开启SMTP 服务图

图2-5.网易邮箱设置授权码图

3. 工具类封装

3.1 邮件依赖管理

<!-- 邮件: https://mvnrepository.com/artifact/com.sun.mail/javax.mail -->
<dependency><groupId>com.sun.mail</groupId><artifactId>javax.mail</artifactId><version>1.6.2</version>
</dependency>

3.2 日志依赖管理

<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional>
</dependency>

3.3 邮件工具类封装

package pers.niaonao.email.util;import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import pers.niaonao.email.constant.SystemConstant;import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.List;
import java.util.Properties;/*** @className: SMTPEmailUtil* @description: 邮件工具类**      推荐文章更好理解smtp原理: <<手工体验smtp和pop3协议>> https://www.cnblogs.com/ysocean/p/7653252.html**      SMTP 协议发送邮件*      (1) 获取会话 Session, 配置环境信息及用户授权验证*      (2) 创建邮件 Message, 完善邮件对象消息`主题`附件`日期`发送者接收者抄送者密送者等信息*      (3) 发送邮件 Transport, 提供网络传输对象发送邮件**      邮件交互会话 javax.mail.Session: Session 对象保存了邮件系统的配置信息及提供用户验证*      密码验证类 Authenticator, 是抽象类, 可以新建实现类去覆盖原方法, 也可以像下面静态代码块直接使用.*      编写邮件需要 MimeMessage 对象, 该对象是抽象类的 javax.mail.Message 的一个实现类;** @author: niaonao* @date: 2019/7/24**/
@Slf4j
public class SMTPEmailUtil {/*** 邮件发送者账户* 邮件发送协议 smtp 账号密码/账号授权码* 发件人* (邮件发送者从业务上看应支持系统配置, 此处就直接写好了数据; 你可以维护在配置文件,系统参数或数据库)*/private static final String emailSenderAccount = "2171128382@qq.com";private static final String emailSenderAuthCode = "ojaerigbrwgmdjed";private static final String emailSenderName = "哪都通物流有限公司";/*** 环境信息*/private static Properties props = new Properties();static {// 设置用户的认证方式, 邮箱账户, 授权码props.put(SystemConstant.MAIL_SMTP_HOST, getHost(emailSenderAccount));props.setProperty(SystemConstant.MAIL_SMTP_AUTH, String.valueOf(Boolean.TRUE));props.put(SystemConstant.MAIL_SMTP_USER, emailSenderAccount);props.put(SystemConstant.MAIL_SMTP_PASSWORD, emailSenderAuthCode);}/*** @description: 邮箱服务器域名通用转换, 格式支持多数邮件服务器, 部分不支持* @param email* @return: java.lang.String* @author: niaonao* @date: 2019/7/25*/private static String getHost(String email) {return new StringBuffer(SystemConstant.SMTP).append(SystemConstant.SYMBOL_POINT).append(email.split(SystemConstant.SYMBOL_AT)[1]).toString();}/*** @description: 获取共享的 Session* @return: javax.mail.Session* @author: niaonao* @date: 2019/7/25*/private static Session getSession() {return Session.getInstance(props, new Authenticator() {@Overrideprotected PasswordAuthentication getPasswordAuthentication() {return new PasswordAuthentication(emailSenderAccount, emailSenderAuthCode);}});}/*** @description: 获取非共享的Session, 方法内部使用了 synchronized 关键字* lambda的使用条件是‘a functional interface has exactly one abstract method’* abstract class 使用lambda 的话要改造满足该条件* @return: javax.mail.Session* @author: niaonao* @date: 2019/7/25*/private static Session getDefaultInstance() {return Session.getDefaultInstance(props, new Authenticator() {@Overrideprotected PasswordAuthentication getPasswordAuthentication() {return new PasswordAuthentication(emailSenderAccount, emailSenderAuthCode);}});}/*** @description: 默认邮件发送者*      即配置邮箱和密码\授权码的账户* @param* @return: javax.mail.internet.InternetAddress* @author: niaonao* @date: 2019/7/25*/private static InternetAddress getDefaultSender() {try {return new InternetAddress(emailSenderAccount, emailSenderName, SystemConstant.CHARSET_UTF_8);} catch (UnsupportedEncodingException e) {log.error("[邮件工具]: 初始化异常{}", e.getMessage());throw new RuntimeException("获取默认邮件发送人错误!");}}/*** @description: 传输工具* @return: javax.mail.Transport* @author: niaonao* @date: 2019/7/25*/private static Transport getTransport() throws MessagingException {// 设置邮件协议 smtpTransport transport = getSession().getTransport(SystemConstant.SMTP);// 此处 QQ 邮箱, 通过账号和授权码链接transport.connect(getHost(emailSenderAccount), emailSenderAccount, emailSenderAuthCode);return transport;}/*** @description: 收件人转换 Address 对象* @param receiverEmailList* @return: javax.mail.internet.InternetAddress[]* @author: niaonao* @date: 2019/7/25*/private static InternetAddress[] tranAddressByList(List<String> receiverEmailList) {/*List<InternetAddress> internetAddressList = new ArrayList<>();receiverEmailList.forEach(item -> {InternetAddress internetAddress = new InternetAddress();internetAddress.setAddress(item);internetAddressList.add(internetAddress);});InternetAddress[] addresses = internetAddressList.stream().toArray(InternetAddress[]::new);*/if (CollectionUtils.isEmpty(receiverEmailList)) {return null;}InternetAddress[] address = new InternetAddress[receiverEmailList.size()];for (int index = 0; index < receiverEmailList.size(); index++) {InternetAddress internetAddress = new InternetAddress();internetAddress.setAddress(receiverEmailList.get(index));address[index] = internetAddress;}return address;}/*** @description: 发送普通文本* @param subject 邮件主题* @param text  邮件普通文本内容* @param emailReceiverAccount  接收者* @param sendDate  邮件发送时间* @return: void* @author: niaonao* @date: 2019/7/24*/public static void sendEmailByText(String subject, String text, String emailReceiverAccount, Date sendDate) {try {// 邮件对象MimeMessage msg = new MimeMessage(getSession());// 发送人msg.setFrom(getDefaultSender());// 发送方式,接收人msg.setRecipients(Message.RecipientType.TO, emailReceiverAccount);// 消息msg.setSubject(subject);msg.setText(text);if (null != sendDate) {msg.setSentDate(sendDate.before(new Date()) ? new Date() : sendDate);} else {// 邮件默认立即发送msg.setSentDate(new Date());}//发送邮件Transport.send(msg);log.info("[邮件发送]: 邮件已发送!");} catch (MessagingException e) {log.error("[邮件发送]: 普通文本邮件发送异常, {}", e.getMessage());}}/*** @description: 发送普通消息邮件(多收件人)* @param subject   邮件标题* @param text      邮件内容* @param receiverEmailList 接收人* @param sendDate  邮件发送时间* @return: void* @author: niaonao* @date: 2019/7/25*/public static void sendEmailByText(String subject, String text, List<String> receiverEmailList, Date sendDate) {InternetAddress[] addresses = tranAddressByList(receiverEmailList);try {// 邮件对象MimeMessage msg = new MimeMessage(getSession());msg.setFrom(getDefaultSender());msg.setRecipients(Message.RecipientType.TO, addresses);msg.setSubject(subject);msg.setText(text);if (null != sendDate) {msg.setSentDate(sendDate.before(new Date()) ? new Date() : sendDate);}// 开启传输,发送邮件Transport transport = getTransport();transport.sendMessage(msg, msg.getRecipients(Message.RecipientType.TO));// 关闭链接transport.close();log.info("[邮件发送]: 邮件已发送!");} catch (MessagingException e) {log.error("[邮件发送]: 普通文本邮件发送异常, {}", e.getMessage());}}/*** @description: 发送普通文本消息(指定接收人,抄送人,密送人)* @param subject   邮件主题* @param text      邮件内容* @param receiverEmailList 邮件接收人* @param carbonCopyList    邮件抄送人* @param blindCarbonCopyList   邮件密送人* @param sendDate  邮件发送时间* @return: void* @author: niaonao* @date: 2019/7/25*/public static void sendEmailByText(String subject, String text, List<String> receiverEmailList, List<String> carbonCopyList, List<String> blindCarbonCopyList, Date sendDate) {InternetAddress[] receiverAddresses = tranAddressByList(receiverEmailList);InternetAddress[] carbonCopyAddresses = tranAddressByList(carbonCopyList);InternetAddress[] blindCarbonCopyAddresses = tranAddressByList(blindCarbonCopyList);try {// 邮件对象MimeMessage msg = new MimeMessage(getSession());msg.setFrom(getDefaultSender());// 发送方式,接收人msg.setRecipients(Message.RecipientType.TO, receiverAddresses);msg.setRecipients(Message.RecipientType.CC, carbonCopyAddresses);msg.setRecipients(Message.RecipientType.BCC, blindCarbonCopyAddresses);// 消息msg.setSubject(subject);msg.setText(text);if (null != sendDate) {msg.setSentDate(sendDate.before(new Date()) ? new Date() : sendDate);}// 开启传输,发送邮件Transport transport = getTransport();transport.sendMessage(msg, msg.getAllRecipients());// 关闭链接transport.close();log.info("[邮件发送]: 邮件已发送!");} catch (MessagingException e) {log.error("[邮件发送]: 普通文本邮件发送异常, {}", e.getMessage());}}/*** @description: 发送网页HTML 格式内容* @param subject   邮件标题* @param html      邮件内容, 语法HTML* @param receiverEmailList* @param carbonCopyList* @param blindCarbonCopyList* @param sendDate* @return: void* @author: niaonao* @date: 2019/7/25*/public static void sendEmailByHtml(String subject, String html, List<String> receiverEmailList, List<String> carbonCopyList, List<String> blindCarbonCopyList, Date sendDate) {InternetAddress[] receiverAddresses = tranAddressByList(receiverEmailList);InternetAddress[] carbonCopyAddresses = tranAddressByList(carbonCopyList);InternetAddress[] blindCarbonCopyaddresses = tranAddressByList(blindCarbonCopyList);try {MimeMessage mimeMessage = new MimeMessage(getSession());// 发送方式,接收人mimeMessage.setRecipients(Message.RecipientType.TO, receiverAddresses);mimeMessage.setRecipients(Message.RecipientType.CC, carbonCopyAddresses);mimeMessage.setRecipients(Message.RecipientType.BCC, blindCarbonCopyaddresses);mimeMessage.setFrom(getDefaultSender());mimeMessage.setSubject(subject);mimeMessage.setContent(html, SystemConstant.CHARSET_TYPE_HTML);if (null != sendDate) {mimeMessage.setSentDate(sendDate.before(new Date()) ? new Date() : sendDate);}Transport transport = getTransport();transport.sendMessage(mimeMessage, mimeMessage.getAllRecipients());transport.close();log.info("[邮件发送]: HTML 网页邮件已发送!");} catch (MessagingException e) {log.error("[邮件发送]: HTML 网页邮件发送异常, {}", e.getMessage());e.printStackTrace();}}/*** @description: 发送携带附件的邮件* @param subject   邮件标题* @param html      邮件内容, 语法HTML* @param receiverEmailList* @param carbonCopyList* @param blindCarbonCopyList* @param sendDate* @return: void* @author: niaonao* @date: 2019/7/25*/public static void sendEmailByEnclosure(String subject, String html, List<String> fileUrlList, List<String> receiverEmailList, List<String> carbonCopyList, List<String> blindCarbonCopyList, Date sendDate) {InternetAddress[] receiverAddresses = tranAddressByList(receiverEmailList);InternetAddress[] carbonCopyAddresses = tranAddressByList(carbonCopyList);InternetAddress[] blindCarbonCopyaddresses = tranAddressByList(blindCarbonCopyList);try {// html 节点MimeBodyPart contentPart = new MimeBodyPart();contentPart.setContent(html, SystemConstant.CHARSET_TYPE_HTML);// 组合节点MimeMultipart multipart = new MimeMultipart();for (String url:fileUrlList) {// 附件节点MimeBodyPart enclosure = new MimeBodyPart();// 读取文件// 将附件数据添加到"节点"DataHandler dataHandler = new DataHandler(new FileDataSource(url));enclosure.setDataHandler(dataHandler);enclosure.setFileName(MimeUtility.encodeText(dataHandler.getName()));multipart.addBodyPart(enclosure);}multipart.addBodyPart(contentPart);multipart.setSubType(SystemConstant.SUB_TYPE_MIXED);// 邮件对象MimeMessage mimeMessage = new MimeMessage(getSession());mimeMessage.setRecipients(Message.RecipientType.TO, receiverAddresses);mimeMessage.setRecipients(Message.RecipientType.CC, carbonCopyAddresses);mimeMessage.setRecipients(Message.RecipientType.BCC, blindCarbonCopyaddresses);mimeMessage.setFrom(getDefaultSender());mimeMessage.setSubject(subject);mimeMessage.setContent(multipart);if (null != sendDate) {mimeMessage.setSentDate(sendDate.before(new Date()) ? new Date() : sendDate);}Transport transport = getTransport();transport.sendMessage(mimeMessage, mimeMessage.getAllRecipients());transport.close();log.info("[邮件发送]: HTML 网页邮件已发送!");} catch (MessagingException e) {log.error("[邮件发送]: HTML 网页邮件发送异常, {}", e.getMessage());e.printStackTrace();} catch (UnsupportedEncodingException e) {e.printStackTrace();}}
}

4. 工具类测试及效果演示

在src/test/ 下新建测试类SMTPEmailUtilTest.java
    测试发送附件的方法

@Test
public void sendEmailByEnclosure() {List<String> receiverList = Arrays.asList("22221111@163.com");List<String> carbonCopyList = Arrays.asList("22221111@qq.com");String subject = "宝儿姐喊你查阅附件";String content = "<img width=\"300\" height=\"400\" src=\"https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1564045091&di=57335f2e16c0a670b26c72aa9eb61b0c&src=http://imglf5.nosdn.127.net/img/UUZTMkZCa0pWZEE1Ri9yT1Rhc0hmMnUzdU1KellDZTNOOE1WMlE3N01XMCtrdm1HM0pSZVFBPT0.jpg?imageView&thumbnail=500x0&quality=96&stripmeta=0&type=jpg\"/>";// 项目内相对路径String smtpFileUrl = "src\\main\\resources\\static\\smtp.properties";// 本机D盘文件String LocalFileUrl = "D:\\download\\原始数据.csv";List<String> fileDataSourceList = Arrays.asList(smtpFileUrl, LocalFileUrl);SMTPEmailUtil.sendEmailByEnclosure(subject, content, fileDataSourceList, receiverList, carbonCopyList,null,null);
}

测试结果如图所示

图4-1.邮件发送工具类部分方法测试图

图4-2.测试发送邮件成功图

5. 邮件发送API 测试及效果演示

在src/main/java/pers/niaonao/email/web 下新建EmailController.java
    测试邮件发送接口

@PostMapping("/sendEmailByEnclosure")
public String sendEmailByEnclosure(@RequestBody EmailRequestVo emailRequest){if (StringUtils.isEmpty(emailRequest.getSubject())){return "请维护邮件主题!";}if (CollectionUtils.isEmpty(emailRequest.getFileUrlList())) {return "请添加附件!";}if (CollectionUtils.isEmpty(emailRequest.getReceiverList())) {return "请维护收件人!";}SMTPEmailUtil.sendEmailByEnclosure(emailRequest.getSubject(), emailRequest.getHtml(), emailRequest.getFileUrlList(), emailRequest.getReceiverList(), emailRequest.getCarbonCopyList(), emailRequest.getBlindCarbonCopyList(), emailRequest.getSendDate());return "发送完成!";
}

使用postman 调用接口发送邮件成功图

图5-1.Postman 测试邮件发送API 图

收件如下

图5-2.Postman 调用接口发送邮件成功图 The End.

SMTP 协议邮件发送工具封装相关推荐

  1. 发送邮件(支持所有smtp协议邮件发送)

    1.所需包: javax.mail.jar maven : <!-- https://mvnrepository.com/artifact/javax.mail/mail --> < ...

  2. 基于Java的SMTP协议邮件发送模拟系统

    目录 1. 原理分析 2. 前端页面 3. 数据库设计 4. 后端数据处理 5. 参考文献 6. 注意事项 1. 原理分析 SMTP协议 SMTP(Simple Mail Transfer Proto ...

  3. smtp协议——邮件发送

    根据自己使用的邮件服务器,完成smtp协议的服务开启 给特定邮箱发送图文并茂的邮件,邮件正文包含的表格如下所示,显示的图片自己确定. 给特定邮箱发送邮件,邮件附件为"实验报告7 smtp协议 ...

  4. Java 基于mail.jar 和 activation.jar 封装的邮件发送工具类

    准备工作 发送邮件需要获得协议和支持! 开启服务 POP3/SMTP 服务 如何开启 POP3/SMTP 服务:https://blog.csdn.net/weixin_44953227/articl ...

  5. SMTP协议及POP3协议-邮件发送和接收原理(转)

    本文转自https://blog.csdn.net/qq_15646957/article/details/52544099 感谢作者 一. 邮件开发涉及到的一些基本概念 1.1.邮件服务器和电子邮箱 ...

  6. 封装一个邮件发送工具类,一个字,巴适

    系列文章目录 文章目录 系列文章目录 前言 一. 介绍 二.二话不说开始干 1.引入库 2. 邮件发送实体(Mail) 3. 邮件发送类型枚举(MailType ) 4.邮件发送抽象类(Abstrac ...

  7. JAVA 邮件发送工具类

    1.封装邮件接收地址MODEL和邮件信息MODEL package com.sicdt.jnzxgzc.common.mail.model;import java.io.Serializable; / ...

  8. [Java工具] 邮件发送工具

    注册邮箱 去163邮箱(或其他邮箱)注册一个邮箱,并开启SMTP授权码. 程序 需要注意的是,由于阿里云服务器不让使用默认的25端口,所以会出现Windows下测试发送邮件成功,Linux服务器下发送 ...

  9. kali 邮箱攻击_kali下邮件发送工具swaks入坑

    Swaks是一个功能强大,灵活,可编写脚本,面向事务的SMTP测试工具, 目前Swaks托管在私有svn存储库中.官方项目页面是 牛刀小试 kali下默认自带,无需安装. 01 测试邮箱的连通性swa ...

最新文章

  1. 函数计算新功能-----支持C#函数
  2. Android Bitmap 研究与思考(上篇)
  3. MVC + AJAX请求失败的问题
  4. 深拷贝与浅拷贝Object.assign()
  5. Upload LABS Pass-5
  6. 打java包需要对应服务器么_java打war包、部署服务器
  7. php接收表单post数据由于数据字段太多导致丢失的案例
  8. Win10系统启动Markdown Pad2 报‘Awesomium.Windows.Controls.WebControl’
  9. SPH(光滑粒子流体动力学)流体模拟实现五:PCISPH
  10. 2022年最新BIM计费标准,涉及14省市
  11. UI设计工作流程步骤详解,让你快速了解UI设计!
  12. 【面经】2018金山WPS前端笔试题 面试题
  13. hustoj安装16种判题语言
  14. 2022-11-09:给定怪兽的血量为hp 第i回合如果用刀砍,怪兽在这回合会直接掉血,没有后续效果 第i回合如果用毒,怪兽在这回合不会掉血, 但是之后每回合都会掉血,并且所有中毒的后续效果会叠加 给
  15. mezzanine-一个功能强大且易于扩展性的Django框架构建的内容管理平台
  16. 110115-07-6,Ac-LLM-CHOCalpain 抑制剂
  17. Python数据分析 2.Matplotlib绘图—常用统计图
  18. 转换cdm为mysql_详解PowerDesigner之CDM、PDM、SQL之间转换
  19. 【matlab 求极限】limit函数求极限
  20. 怎么清理IE浏览器缓存

热门文章

  1. python兔子和獾_Pygame-依葫芦画瓢之兔獾大战
  2. Oracle comment添加注释
  3. Xcode怎么退回旧版本?
  4. Apple store安装旧版本的软件
  5. linux格式化光盘找不到介质,Linux挂载光盘的问题解决方案(mount: you must specify the filesystemnbs...
  6. 【HGNN】北邮循序渐进研究HGNN
  7. NexusJar包私服
  8. 关于编写公司软件测试规范操作手册计划书
  9. 为什么要学习Linux?
  10. 计蒜客-蒜头君回家(bfs)