当前位置:网站首页>通过SMTP协议和Exchange两种方式实现邮件的发送功能
通过SMTP协议和Exchange两种方式实现邮件的发送功能
2022-06-22 05:52:00 【暗夜91】
作者简介:
作者:暗夜91
🤟 个人主页:暗夜91的主页
微信公众号: 程序员的知识站 ,关注本人公众号,学习更多前沿知识。
SpringBoot通过smtp协议和exchange两种不同方式实现邮件的发送功能。
1、SMTP协议与Exchange
SMTP协议:
SMTP的全称是 “Simple Mail Transfer Protocol”,即简单邮件传输协议。它是一组用于从源地址到目的地址传输邮件的规范,通过它来控制邮件的中转方式。它的一个重要特点是它能够在传送中接力传送邮件,即邮件可以通过不同网络上的主机接力式传送。
SMTP认证,简单地说就是要求必须在提供了账户名和密码之后才可以登录SMTP服务器,这就使得那些垃圾邮件的散播者无可乘之机。增加SMTP认证的目的是为了使用户避免受到垃圾邮件的侵扰。SMTP已是事实上的E-Mail传输的标准。
Exchange
Exchange是微软公司推出的一套电子邮件处理组件,同样是通过smtp协议进行邮件的收发。
2、添加SMTP邮件发送的依赖
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.7</version>
</dependency>
3、添加Exchange协议依赖
<dependency>
<groupId>com.microsoft.ews-java-api</groupId>
<artifactId>ews-java-api</artifactId>
<version>2.0</version>
</dependency>
4、添加邮件配置
#smtp协议配置
[email protected]
smtp.send.password=BSNLVRFYDUMBJYNF
smtp.send.host=smtp.163.com
#exchange协议配置
[email protected]
exchange.send.password=Abc123456
exchange.send.host=mail.xxx.com
5、添加公共接口
package com.lll.common.mail;
import lombok.extern.slf4j.Slf4j;
import microsoft.exchange.webservices.data.core.ExchangeService;
import microsoft.exchange.webservices.data.core.enumeration.misc.ExchangeVersion;
import microsoft.exchange.webservices.data.core.enumeration.property.BodyType;
import microsoft.exchange.webservices.data.core.service.item.EmailMessage;
import microsoft.exchange.webservices.data.credential.ExchangeCredentials;
import microsoft.exchange.webservices.data.credential.WebCredentials;
import microsoft.exchange.webservices.data.property.complex.FileAttachment;
import microsoft.exchange.webservices.data.property.complex.MessageBody;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.*;
import javax.mail.internet.*;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URI;
import java.util.*;
@Slf4j
@Component
public class MailCommonService {
/** * * @param toList 收件人列表 * @param mailSubject 邮件主题 * @param contentList 邮件正文,会按照列表的顺序,在邮件中显示。 * 邮件内容有多行时,每行内容是一个MailContentVO * @param fileList 附件文件绝对路径 * @param type 邮件协议类型 */
public void sendMail(List<String> toList,String mailSubject,List<MailContentVO> contentList,List<String> fileList,MailProtocolType type) {
try {
Properties props = new Properties();
ClassPathResource classPathResource = new ClassPathResource("/mail.properties");
InputStream inputStream = classPathResource.getInputStream();
props.load(new InputStreamReader(inputStream, "UTF-8"));
if (type.equals(MailProtocolType.smtp)){
sendMailSmtp(toList,mailSubject,contentList,fileList,props);
} else if(type.equals(MailProtocolType.exchange)){
sendMailExchange(toList,mailSubject,contentList,fileList,props);
} else {
sendMailSmtp(toList,mailSubject,contentList,fileList,props);
}
log.info("邮件发送完成......");
} catch (IOException e) {
e.printStackTrace();
}
}
/** * 发送邮件 * @param toList 收件人列表 * @param mailSubject 邮件主题 * @param contentList 邮件正文,会按照列表的顺序,在邮件中显示。 * 邮件内容有多行时,每行内容是一个MailContentVO * @param fileList 附件文件绝对路径 * @param properties 发送邮箱相关配置 */
public void sendMailSmtp(List<String> toList, String mailSubject, List<MailContentVO> contentList, List<String> fileList, Properties properties) {
String senderAddress = properties.getProperty("smtp.send.address");
String senderPassword = properties.getProperty("smtp.send.password");
try {
//1、连接邮件服务器的参数配置
Properties props = new Properties();
//设置用户的认证方式
props.setProperty("mail.smtp.auth", "true");
//设置传输协议
props.setProperty("mail.transport.protocol", "smtp");
//设置发件人的SMTP服务器地址
props.setProperty("mail.smtp.host", properties.getProperty("smtp.send.host"));
//2、创建定义整个应用程序所需的环境信息的 Session 对象
Session session = Session.getInstance(props);
//设置调试信息在控制台打印出来
session.setDebug(true);
//3、创建邮件的实例对象
Message msg = getMimeMessage(session,senderAddress,toList,mailSubject,contentList,fileList);
//4、根据session对象获取邮件传输对象Transport
Transport transport = session.getTransport();
//设置发件人的账户名和密码
transport.connect(senderAddress, senderPassword);
//发送邮件,如果只想发送给指定的人,可以如下写法
Address[] addresses = new Address[toList.size()];
for (int i=0;i<toList.size();i++){
addresses[i] = new InternetAddress(toList.get(i));
}
transport.sendMessage(msg, addresses);
//5、关闭邮件连接
transport.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private MimeMessage getMimeMessage(Session session, String senderAddress, List<String> toList, String mailSubject, List<MailContentVO> contentList, List<String> fileList) throws Exception {
//1、创建一封邮件的实例对象
MimeMessage msg = new MimeMessage(session);
//2、设置发件人地址
msg.setFrom(new InternetAddress(senderAddress));
/** * 3、设置收件人地址(可以增加多个收件人、抄送、密送),即下面这一行代码书写多行 * MimeMessage.RecipientType.TO:发送 * MimeMessage.RecipientType.CC:抄送 * MimeMessage.RecipientType.BCC:密送 */
for (String to:toList){
msg.setRecipient(MimeMessage.RecipientType.TO, new InternetAddress(to));
}
//4、设置邮件主题
msg.setSubject(mailSubject, "UTF-8");
// 5、(文本+图片)设置 文本 和 图片"节点"的关系(将 文本 和 图片"节点"合成一个混合"节点")
MimeMultipart mm_text_image = new MimeMultipart();
//文本节点的内容组合
List<String> textContent = new ArrayList<>();
for (MailContentVO vo:contentList){
MailContentType type = vo.getType();
if (type.equals(MailContentType.txt)){
textContent.add(vo.getContent());
}else{
String uid = UUID.randomUUID().toString();
//创建图片"节点"
MimeBodyPart image = new MimeBodyPart();
//读取本地文件
DataHandler dh = new DataHandler(new FileDataSource(vo.getContent()));
//将图片数据添加到"节点"
image.setDataHandler(dh);
//为"节点"设置一个唯一编号(在文本"节点"将引用该ID)
image.setContentID(uid);
mm_text_image.addBodyPart(image);
//
String img = "<img src='cid:"+uid+"'/>";
textContent.add(img);
}
}
MimeBodyPart text = new MimeBodyPart();
// 这里添加图片的方式是将整个图片包含到邮件内容中, 实际上也可以以 http 链接的形式添加网络图片
text.setContent(StringUtils.join(textContent,"<br/>"), "text/html;charset=UTF-8");
mm_text_image.addBodyPart(text);
mm_text_image.setSubType("related"); //关联关系
// 8. 将 文本+图片 的混合"节点"封装成一个普通"节点"
// 最终添加到邮件的 Content 是由多个 BodyPart 组成的 Multipart, 所以我们需要的是 BodyPart,
MimeBodyPart text_image = new MimeBodyPart();
text_image.setContent(mm_text_image);
MimeMultipart mm = new MimeMultipart();
mm.addBodyPart(text_image);
//9、设置附件
for (String filePath:fileList){
File file = new File(filePath);
MimeBodyPart attachment = new MimeBodyPart();
DataSource source = new FileDataSource(filePath);
attachment.setDataHandler(new DataHandler(source));
attachment.setFileName(MimeUtility.encodeText(file.getName()));
mm.addBodyPart(attachment);
}
mm.setSubType("mixed"); // 混合关系
// 10、 设置整个邮件的关系(将最终的混合"节点"作为邮件的内容添加到邮件对象)
msg.setContent(mm);
//设置邮件的发送时间,默认立即发送
msg.setSentDate(new Date());
return msg;
}
/** * 发送邮件 * @param toList 收件人列表 * @param subject 邮件主题 * @param contentList 邮件正文,会按照列表的顺序,在邮件中显示。 * 邮件内容有多行时,每行内容是一个MailContentVO * @param filePath 附件文件绝对路径 * @param properties 发送邮箱相关配置 */
private void sendMailExchange(List<String> toList, String subject, List<MailContentVO> contentList, List<String> filePath, Properties properties) {
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2007_SP1);
ExchangeCredentials credentials = new WebCredentials(properties.getProperty("exchange.send.address"),properties.getProperty("exchange.send.password"));
service.setCredentials(credentials);
try {
String uri = "https://"+properties.getProperty("exchange.send.host")+"/ews/exchange.asmx";
service.setUrl(new URI(uri));
EmailMessage msg = new EmailMessage(service);
//设置邮件主题
msg.setSubject(subject);
//设置邮件正文
List<String> textContent = new ArrayList<>();
for (MailContentVO vo:contentList){
MailContentType type = vo.getType();
if (type.equals(MailContentType.txt)){
textContent.add(vo.getContent());
}else{
String uid = UUID.randomUUID().toString();
FileAttachment attachment = msg.getAttachments().addFileAttachment(vo.getContent());
attachment.setContentType("image");
attachment.setContentId(uid);
String img = "<img src='cid:"+uid+"'/>";
textContent.add(img);
}
}
//设置邮件附件
if (!CollectionUtils.isEmpty(filePath)){
for (String path:filePath){
String uid = UUID.randomUUID().toString();
FileAttachment attachment1 = msg.getAttachments().addFileAttachment(path);
attachment1.setContentType("image");
attachment1.setContentId(uid);
}
}
MessageBody body = MessageBody.getMessageBodyFromText(StringUtils.join(textContent,"<br/>")+"<hr/>");
body.setBodyType(BodyType.HTML);
msg.setBody(body);
//设置邮件收件人
for (String to : toList) {
msg.getToRecipients().add(to);
}
//邮件发送
msg.send();
} catch (Exception e) {
log.error(e.getMessage(),e);
}
}
}
6、支持协议枚举
public enum MailProtocolType {
smtp,exchange;
}
7、邮件正文内容枚举
public enum MailContentType {
txt("文本"),img("图片");
private String type;
MailContentType(String type) {
this.type = type;
}
}
8、邮件正文内容
@Data
public class MailContentVO {
/** * 正文信息类型 */
private MailContentType type;
/** * 正文信息 * txt内容或img绝对路径 */
private String content;
}
边栏推荐
- 机器学习概念梳理(无公式)
- Dos Bat 语法记录一
- Ethernet communication protocol
- I2C接口
- 从转载阿里开源项目 Egg.js 技术文档引发的“版权纠纷”,看宽松的 MIT 许可该如何用?
- 不务正业系列7:老照片去除斑点手法
- Market survey and future production and marketing demand analysis report of China's zinc oxide nanoparticle industry 2022-2027
- Test platform composed of time sequence
- Write optimized DSP code for cortex-m4
- 单细胞论文记录(part14)--CoSTA: unsupervised convolutional neural network learning for ST analysis
猜你喜欢

Creating GLSL Shaders at Runtime in Unity3D

从转载阿里开源项目 Egg.js 技术文档引发的“版权纠纷”,看宽松的 MIT 许可该如何用?

Unity development - scene asynchronous loading

【自己动手写CPU】异常相关指令的实现

400 hash table (1. sum of two numbers, 454. sum of four numbers II, 383. ransom letter)

关于jinja2 宏定义的小问题

System identification of automatic control principle

Unity app improves device availability

单细胞论文记录(part9)--Spatial charting of single-cell transcriptomes in tissues

Le contrôle MFC tabctrl modifie la taille de l'étiquette
随机推荐
Combinatorial logic described using SystemVerilog gate model
osg编译osgQt
vcpkg:If you are sure you want to rebuild the above packages, run the command with the --recurse opt
matlab 的离散pid控制
电热水壶坏了别扔,它很容易修好的!
What about computer jam?
Unity encrypts ASE game data
MFC tab control add Icon
虚职、架空、拖后腿,大厂开源办公室到底什么样?
不务正业系列7:老照片去除斑点手法
Creating GLSL Shaders at Runtime in Unity3D
性能优化最佳实践之缩减游戏大小
Academic circle of cattle II (daily question 49 in spring)
生信文献学习(part1)--PRECISE: a ... approach to transfer predictors of drug response from pre-clinical ...
组合逻辑块的测试平台
Using SystemVerilog to describe a state machine
D3D learning notes (1) - Introduction to the use conditions of autodraw at so stage
EPP (enhanced parallel port)
【云计算重点复习】
五大常考SQL面试题