Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
Y
yd-email
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
xingmin
yd-email
Commits
4be82047
Commit
4be82047
authored
Sep 28, 2025
by
zhangxingmin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
push
parent
237b5e3f
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
186 additions
and
54 deletions
+186
-54
yd-email-api/src/main/java/com/yd/email/api/handler/EmailSendJobHandler.java
+4
-0
yd-email-api/src/main/java/com/yd/email/api/service/impl/ApiEmailSendServiceImpl.java
+5
-0
yd-email-api/src/main/java/com/yd/email/api/service/impl/ApiEmailServiceImpl.java
+177
-54
No files found.
yd-email-api/src/main/java/com/yd/email/api/handler/EmailSendJobHandler.java
View file @
4be82047
...
...
@@ -95,6 +95,10 @@ public class EmailSendJobHandler {
// 遍历所有收件人,逐个发送邮件
for
(
EmailTaskRecipients
recipient
:
recipients
)
{
try
{
// 添加发送间隔,避免频率过高
if
(
successCount
>
0
)
{
Thread
.
sleep
(
2000
);
// 2秒间隔
}
// 处理抄送人列表:将数据库中的逗号分隔字符串转换为List
List
<
String
>
ccEmailList
=
StringUtils
.
isNotBlank
(
recipient
.
getCcEmail
())
?
Arrays
.
asList
(
recipient
.
getCcEmail
().
split
(
";"
))
:
...
...
yd-email-api/src/main/java/com/yd/email/api/service/impl/ApiEmailSendServiceImpl.java
View file @
4be82047
...
...
@@ -123,6 +123,11 @@ public class ApiEmailSendServiceImpl implements ApiEmailSendService {
// 遍历所有收件人,逐个发送邮件
for
(
EmailTaskRecipients
recipient
:
recipients
)
{
try
{
// 添加发送间隔,避免频率过高
if
(
successCount
>
0
)
{
Thread
.
sleep
(
2000
);
// 2秒间隔
}
// 处理抄送人列表:将数据库中的逗号分隔字符串转换为List
List
<
String
>
ccEmailList
=
StringUtils
.
isNotBlank
(
recipient
.
getCcEmail
())
?
Arrays
.
asList
(
recipient
.
getCcEmail
().
split
(
";"
))
:
...
...
yd-email-api/src/main/java/com/yd/email/api/service/impl/ApiEmailServiceImpl.java
View file @
4be82047
...
...
@@ -53,65 +53,88 @@ public class ApiEmailServiceImpl implements ApiEmailService {
+
JSON
.
toJSONString
(
dto
.
getCcEmailList
())
+
";"
+
dto
.
getSubject
()
+
";"
+
dto
.
getContent
()
);
//
创建邮件配置属性对象
//
添加邮件服务器配置
Properties
props
=
new
Properties
();
// 设置SMTP需要身份验证
props
.
put
(
"mail.smtp.auth"
,
dto
.
getMailSmtpAuth
());
// 启用TLS加密传输
props
.
put
(
"mail.smtp.starttls.enable"
,
dto
.
getStarttlsEnable
());
// 设置邮件服务器主机名(发件人邮箱-SMTP服务器地址)
props
.
put
(
"mail.smtp.host"
,
dto
.
getSmtpHost
());
log
.
info
(
"mail.smtp.host:{}"
,
dto
.
getSmtpHost
());
//发件人邮箱(单个)
log
.
info
(
"spring.mail.username:{}"
,
dto
.
getSendEmail
());
//发件人邮箱密码或授权码
log
.
info
(
"spring.mail.password:{}"
,
dto
.
getPassword
());
// 设置邮件服务器端口号(587是TLS标准端口)
//发件人邮箱-SMTP服务器端口
props
.
put
(
"mail.smtp.port"
,
dto
.
getSmtpPort
());
// 创建邮件会话对象,传入配置和认证器
// 添加连接超时和读写超时设置
props
.
put
(
"mail.smtp.connectiontimeout"
,
"10000"
);
// 10秒连接超时
props
.
put
(
"mail.smtp.timeout"
,
"30000"
);
// 30秒读写超时
props
.
put
(
"mail.smtp.writetimeout"
,
"30000"
);
// 30秒写超时
// 对于 TLS 连接,添加额外的安全配置
props
.
put
(
"mail.smtp.ssl.trust"
,
dto
.
getSmtpHost
());
props
.
put
(
"mail.smtp.ssl.protocols"
,
"TLSv1.2 TLSv1.3"
);
Session
session
=
Session
.
getInstance
(
props
,
new
Authenticator
()
{
// 重写获取密码认证的方法
protected
PasswordAuthentication
getPasswordAuthentication
()
{
// 返回用户名密码认证对象
return
new
PasswordAuthentication
(
dto
.
getSendEmail
(),
dto
.
getPassword
());
}
});
// 使用try-catch块处理邮件发送异常
// 添加重试机制
int
retryCount
=
0
;
int
maxRetries
=
2
;
boolean
sentSuccessfully
=
false
;
while
(
retryCount
<=
maxRetries
&&
!
sentSuccessfully
)
{
try
{
retryCount
++;
log
.
info
(
"尝试第 {} 次发送邮件"
,
retryCount
);
sendMailWithRetry
(
session
,
dto
);
sentSuccessfully
=
true
;
log
.
info
(
"邮件发送成功: {} -> {}"
,
dto
.
getSendEmail
(),
dto
.
getReceiveEmail
());
}
catch
(
AuthenticationFailedException
e
)
{
log
.
error
(
"第 {} 次认证失败: {}"
,
retryCount
,
e
.
getMessage
());
if
(
retryCount
>
maxRetries
)
{
throw
new
RuntimeException
(
"邮件发送失败: 认证失败,请检查邮箱配置"
,
e
);
}
// 等待后重试
Thread
.
sleep
(
5000
);
}
catch
(
MessagingException
e
)
{
log
.
error
(
"第 {} 次发送失败: {}"
,
retryCount
,
e
.
getMessage
());
if
(
retryCount
>
maxRetries
)
{
throw
new
RuntimeException
(
"邮件发送失败: "
+
e
.
getMessage
(),
e
);
}
// 等待后重试
Thread
.
sleep
(
3000
);
}
}
}
/**
* 发送邮件侏主要逻辑
* @param session
* @param dto
* @throws Exception
*/
private
void
sendMailWithRetry
(
Session
session
,
ApiSendMailDto
dto
)
throws
Exception
{
// 原有的邮件发送逻辑移到这里
try
{
// 创建MIME类型邮件消息对象
Message
message
=
new
MimeMessage
(
session
);
// 设置发件人地址
message
.
setFrom
(
new
InternetAddress
(
dto
.
getSendEmail
()));
// 设置收件人地址(支持多个收件人,用逗号分隔)
message
.
setRecipients
(
Message
.
RecipientType
.
TO
,
InternetAddress
.
parse
(
dto
.
getReceiveEmail
()));
// 判断是否有抄送人
if
(!
CollectionUtils
.
isEmpty
(
dto
.
getCcEmailList
()))
{
// 将抄送人列表转换为逗号分隔的字符串
String
ccAddresses
=
String
.
join
(
","
,
dto
.
getCcEmailList
());
// 设置抄送人地址
message
.
setRecipients
(
Message
.
RecipientType
.
CC
,
InternetAddress
.
parse
(
ccAddresses
));
}
// 设置邮件主题
message
.
setSubject
(
dto
.
getSubject
());
// 设置邮件发送时间(当前时间)
message
.
setSentDate
(
new
Date
());
// 创建邮件正文部分
MimeBodyPart
messageBodyPart
=
new
MimeBodyPart
();
// 设置正文内容,指定HTML格式和UTF-8编码
messageBodyPart
.
setContent
(
dto
.
getContent
(),
"text/html;charset=utf-8"
);
// 创建多部分内容容器(用于组合正文和附件)
Multipart
multipart
=
new
MimeMultipart
();
// 将正文部分添加到多部分容器中
multipart
.
addBodyPart
(
messageBodyPart
);
//
修改附件处理部分:
//
多附件处理逻辑(您之前添加的)
if
(
StringUtils
.
isNotBlank
(
dto
.
getAttachmentPath
()))
{
String
[]
attachmentPaths
=
dto
.
getAttachmentPath
().
split
(
";"
);
for
(
String
attachmentPath
:
attachmentPaths
)
{
...
...
@@ -119,49 +142,149 @@ public class ApiEmailServiceImpl implements ApiEmailService {
if
(
StringUtils
.
isNotBlank
(
attachmentPath
))
{
try
{
MimeBodyPart
attachmentPart
=
new
MimeBodyPart
();
DataSource
source
;
String
fileName
;
if
(
attachmentPath
.
startsWith
(
"http://"
)
||
attachmentPath
.
startsWith
(
"https://"
))
{
// 使用URLDataSource处理网络附件
URL
url
=
new
URL
(
attachmentPath
);
source
=
new
URLDataSource
(
url
);
fileName
=
getFileNameFromUrl
(
attachmentPath
);
}
else
{
// 处理本地文件附件
source
=
new
FileDataSource
(
attachmentPath
);
fileName
=
new
File
(
attachmentPath
).
getName
();
}
DataSource
source
=
new
FileDataSource
(
attachmentPath
);
attachmentPart
.
setDataHandler
(
new
DataHandler
(
source
));
attachmentPart
.
setFileName
(
fileName
);
attachmentPart
.
setFileName
(
new
File
(
attachmentPath
).
getName
()
);
multipart
.
addBodyPart
(
attachmentPart
);
log
.
info
(
"添加附件: {}"
,
attachmentPath
);
log
.
info
(
"
成功
添加附件: {}"
,
attachmentPath
);
}
catch
(
Exception
e
)
{
log
.
error
(
"添加附件失败: {}"
,
attachmentPath
,
e
);
throw
new
RuntimeException
(
"添加附件失败: "
+
attachmentPath
,
e
);
}
}
}
}
// 将多部分内容设置为邮件的完整内容
message
.
setContent
(
multipart
);
// 发送邮件
Transport
.
send
(
message
);
// 记录成功日志
log
.
info
(
"邮件发送成功: {} -> {}"
,
dto
.
getSendEmail
(),
dto
.
getReceiveEmail
());
// log.info("发送邮件Transport.send(message) {}", JSON.toJSONString(message));
}
catch
(
MessagingException
e
)
{
// 记录失败日志,包含异常信息
log
.
error
(
"邮件发送失败: {} -> {}"
,
dto
.
getSendEmail
(),
dto
.
getReceiveEmail
(),
e
);
// 抛出运行时异常
throw
new
RuntimeException
(
"邮件发送失败: "
+
e
.
getMessage
());
throw
e
;
}
}
// /**
// * 发送邮件
// * @param dto
// * @throws Exception
// */
// @Override
// public void sendMail(ApiSendMailDto dto) throws Exception {
// log.info("发送邮件的主要方法参数: {}: "
// + dto.getSendEmail() + ";"
// + dto.getReceiveEmail() + ";"
// + JSON.toJSONString(dto.getCcEmailList())
// + ";" + dto.getSubject() + ";" + dto.getContent() );
//
// // 创建邮件配置属性对象
// Properties props = new Properties();
// // 设置SMTP需要身份验证
// props.put("mail.smtp.auth", dto.getMailSmtpAuth());
// // 启用TLS加密传输
// props.put("mail.smtp.starttls.enable", dto.getStarttlsEnable());
// // 设置邮件服务器主机名(发件人邮箱-SMTP服务器地址)
// props.put("mail.smtp.host", dto.getSmtpHost());
// log.info("mail.smtp.host:{}",dto.getSmtpHost());
// //发件人邮箱(单个)
// log.info("spring.mail.username:{}",dto.getSendEmail());
// //发件人邮箱密码或授权码
// log.info("spring.mail.password:{}",dto.getPassword());
// // 设置邮件服务器端口号(587是TLS标准端口)
// //发件人邮箱-SMTP服务器端口
// props.put("mail.smtp.port", dto.getSmtpPort());
//
// // 创建邮件会话对象,传入配置和认证器
// Session session = Session.getInstance(props, new Authenticator() {
// // 重写获取密码认证的方法
// protected PasswordAuthentication getPasswordAuthentication() {
// // 返回用户名密码认证对象
// return new PasswordAuthentication(dto.getSendEmail(), dto.getPassword());
// }
// });
//
// // 使用try-catch块处理邮件发送异常
// try {
// // 创建MIME类型邮件消息对象
// Message message = new MimeMessage(session);
// // 设置发件人地址
// message.setFrom(new InternetAddress(dto.getSendEmail()));
// // 设置收件人地址(支持多个收件人,用逗号分隔)
// message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(dto.getReceiveEmail()));
//
// // 判断是否有抄送人
// if (!CollectionUtils.isEmpty(dto.getCcEmailList())) {
// // 将抄送人列表转换为逗号分隔的字符串
// String ccAddresses = String.join(",", dto.getCcEmailList());
// // 设置抄送人地址
// message.setRecipients(Message.RecipientType.CC, InternetAddress.parse(ccAddresses));
// }
//
// // 设置邮件主题
// message.setSubject(dto.getSubject());
// // 设置邮件发送时间(当前时间)
// message.setSentDate(new Date());
//
// // 创建邮件正文部分
// MimeBodyPart messageBodyPart = new MimeBodyPart();
// // 设置正文内容,指定HTML格式和UTF-8编码
// messageBodyPart.setContent(dto.getContent(), "text/html;charset=utf-8");
//
// // 创建多部分内容容器(用于组合正文和附件)
// Multipart multipart = new MimeMultipart();
// // 将正文部分添加到多部分容器中
// multipart.addBodyPart(messageBodyPart);
//
// // 修改附件处理部分:
// if (StringUtils.isNotBlank(dto.getAttachmentPath())) {
// String[] attachmentPaths = dto.getAttachmentPath().split(";");
// for (String attachmentPath : attachmentPaths) {
// attachmentPath = attachmentPath.trim();
// if (StringUtils.isNotBlank(attachmentPath)) {
// try {
// MimeBodyPart attachmentPart = new MimeBodyPart();
// DataSource source;
// String fileName;
//
// if (attachmentPath.startsWith("http://") || attachmentPath.startsWith("https://")) {
// // 使用URLDataSource处理网络附件
// URL url = new URL(attachmentPath);
// source = new URLDataSource(url);
// fileName = getFileNameFromUrl(attachmentPath);
// } else {
// // 处理本地文件附件
// source = new FileDataSource(attachmentPath);
// fileName = new File(attachmentPath).getName();
// }
//
// attachmentPart.setDataHandler(new DataHandler(source));
// attachmentPart.setFileName(fileName);
// multipart.addBodyPart(attachmentPart);
// log.info("添加附件: {}", attachmentPath);
// } catch (Exception e) {
// log.error("添加附件失败: {}", attachmentPath, e);
// throw new RuntimeException("添加附件失败: " + attachmentPath, e);
// }
// }
// }
// }
//
// // 将多部分内容设置为邮件的完整内容
// message.setContent(multipart);
//
// // 发送邮件
// Transport.send(message);
// // 记录成功日志
// log.info("邮件发送成功: {} -> {}", dto.getSendEmail(), dto.getReceiveEmail());
//// log.info("发送邮件Transport.send(message) {}", JSON.toJSONString(message));
//
// } catch (MessagingException e) {
// // 记录失败日志,包含异常信息
// log.error("邮件发送失败: {} -> {}", dto.getSendEmail(), dto.getReceiveEmail(), e);
// // 抛出运行时异常
// throw new RuntimeException("邮件发送失败: " + e.getMessage());
// }
// }
// 辅助方法:从URL中提取文件名
private
String
getFileNameFromUrl
(
String
url
)
{
try
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment