refactor(common-mail): 使用 MailBuilder 替代 MailUtils

- 新增链式 MailBuilder,统一邮件发送入口
  - 删除 MailUtils,业务代码全部切换为 builder 调用
  - 默认邮件账户改为发送时获取,避免类加载阶段依赖 Bean
  - 自定义发件账号时复制默认配置,避免污染全局 MailAccount
  - 增加收件人、标题和正文参数校验
  - 调整内联图片流关闭时机,发送结束后统一关闭
  - 将 MailAccount 构建逻辑下沉到 MailProperties
This commit is contained in:
疯狂的狮子Li
2026-05-16 14:25:34 +08:00
parent f4b4c710c5
commit 99db6dceea
7 changed files with 382 additions and 494 deletions

View File

@@ -17,7 +17,7 @@ import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.regex.RegexValidator;
import org.dromara.common.mail.config.properties.MailProperties;
import org.dromara.common.mail.utils.MailUtils;
import org.dromara.common.mail.core.MailBuilder;
import org.dromara.common.redis.annotation.RateLimiter;
import org.dromara.common.redis.enums.LimitType;
import org.dromara.common.redis.utils.RedisUtils;
@@ -109,7 +109,11 @@ public class CaptchaController {
String code = RandomUtil.randomNumbers(4);
RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
try {
MailUtils.sendText(email, "登录验证码", "您本次验证码为:" + code + ",有效性为" + Constants.CAPTCHA_EXPIRATION + "分钟,请尽快填写。");
MailBuilder.of()
.to(email)
.subject("登录验证码")
.text("您本次验证码为:" + code + ",有效性为" + Constants.CAPTCHA_EXPIRATION + "分钟,请尽快填写。")
.send();
} catch (Exception e) {
log.error("验证码短信发送异常 => {}", e.getMessage());
throw new ServiceException(e.getMessage());

View File

@@ -19,19 +19,7 @@ public class MailConfig {
@Bean
@ConditionalOnProperty(value = "mail.enabled", havingValue = "true")
public MailAccount mailAccount(MailProperties mailProperties) {
MailAccount account = new MailAccount();
account.setHost(mailProperties.getHost());
account.setPort(mailProperties.getPort());
account.setAuth(mailProperties.getAuth());
account.setFrom(mailProperties.getFrom());
account.setUser(mailProperties.getUser());
account.setPass(mailProperties.getPass());
account.setSocketFactoryPort(mailProperties.getPort());
account.setStarttlsEnable(mailProperties.getStarttlsEnable());
account.setSslEnable(mailProperties.getSslEnable());
account.setTimeout(mailProperties.getTimeout());
account.setConnectionTimeout(mailProperties.getConnectionTimeout());
return account;
return mailProperties.toMailAccount();
}
}

View File

@@ -1,5 +1,6 @@
package org.dromara.common.mail.config.properties;
import cn.hutool.extra.mail.MailAccount;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
@@ -72,4 +73,25 @@ public class MailProperties {
* Socket连接超时值单位毫秒缺省值不超时
*/
private Long connectionTimeout;
/**
* 转换为 Hutool 邮件账户配置。
*
* @return 邮件账户配置
*/
public MailAccount toMailAccount() {
MailAccount account = new MailAccount();
account.setHost(host);
account.setPort(port);
account.setAuth(auth);
account.setFrom(from);
account.setUser(user);
account.setPass(pass);
account.setSocketFactoryPort(port);
account.setStarttlsEnable(starttlsEnable);
account.setSslEnable(sslEnable);
account.setTimeout(timeout);
account.setConnectionTimeout(connectionTimeout);
return account;
}
}

View File

@@ -0,0 +1,347 @@
package org.dromara.common.mail.core;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.mail.JakartaMail;
import cn.hutool.extra.mail.MailAccount;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.StringUtils;
import java.io.File;
import java.io.InputStream;
import java.util.*;
/**
* 邮件发送构建器。
*/
public final class MailBuilder {
private MailAccount mailAccount;
private boolean useGlobalSession = true;
private final List<String> tos = new ArrayList<>();
private final List<String> ccs = new ArrayList<>();
private final List<String> bccs = new ArrayList<>();
private final Map<String, InputStream> images = new LinkedHashMap<>();
private File[] files = new File[0];
private String from;
private String user;
private String pass;
private String subject;
private String content;
private boolean html;
private MailBuilder() {
}
/**
* 创建邮件构建器,默认使用配置文件中的邮件账户。
*
* @return 邮件构建器
*/
public static MailBuilder of() {
return new MailBuilder();
}
/**
* 创建邮件构建器,使用指定邮件账户。
*
* @param mailAccount 邮件账户
* @return 邮件构建器
*/
public static MailBuilder of(MailAccount mailAccount) {
return new MailBuilder().account(mailAccount);
}
/**
* 设置自定义邮件账户。
*
* @param mailAccount 邮件账户
* @return 当前构建器
*/
public MailBuilder account(MailAccount mailAccount) {
this.mailAccount = Objects.requireNonNull(mailAccount, "mailAccount must not be null");
this.useGlobalSession = false;
return this;
}
/**
* 覆盖发件人。
*
* @param from 发件人
* @return 当前构建器
*/
public MailBuilder from(String from) {
this.from = from;
this.useGlobalSession = false;
return this;
}
/**
* 覆盖登录用户名。
*
* @param user 用户名
* @return 当前构建器
*/
public MailBuilder user(String user) {
this.user = user;
this.useGlobalSession = false;
return this;
}
/**
* 覆盖登录密码或授权码。
*
* @param pass 密码或授权码
* @return 当前构建器
*/
public MailBuilder pass(String pass) {
this.pass = pass;
this.useGlobalSession = false;
return this;
}
/**
* 添加收件人,多个邮箱可使用逗号或分号分隔。
*
* @param addresses 收件人
* @return 当前构建器
*/
public MailBuilder to(String addresses) {
this.tos.addAll(splitAddress(addresses));
return this;
}
/**
* 添加收件人。
*
* @param addresses 收件人集合
* @return 当前构建器
*/
public MailBuilder to(Collection<String> addresses) {
this.tos.addAll(normalizeAddresses(addresses));
return this;
}
/**
* 添加抄送人,多个邮箱可使用逗号或分号分隔。
*
* @param addresses 抄送人
* @return 当前构建器
*/
public MailBuilder cc(String addresses) {
this.ccs.addAll(splitAddress(addresses));
return this;
}
/**
* 添加抄送人。
*
* @param addresses 抄送人集合
* @return 当前构建器
*/
public MailBuilder cc(Collection<String> addresses) {
this.ccs.addAll(normalizeAddresses(addresses));
return this;
}
/**
* 添加密送人,多个邮箱可使用逗号或分号分隔。
*
* @param addresses 密送人
* @return 当前构建器
*/
public MailBuilder bcc(String addresses) {
this.bccs.addAll(splitAddress(addresses));
return this;
}
/**
* 添加密送人。
*
* @param addresses 密送人集合
* @return 当前构建器
*/
public MailBuilder bcc(Collection<String> addresses) {
this.bccs.addAll(normalizeAddresses(addresses));
return this;
}
/**
* 设置邮件标题。
*
* @param subject 标题
* @return 当前构建器
*/
public MailBuilder subject(String subject) {
this.subject = subject;
return this;
}
/**
* 设置文本正文。
*
* @param content 正文
* @return 当前构建器
*/
public MailBuilder text(String content) {
this.content = content;
this.html = false;
return this;
}
/**
* 设置 HTML 正文。
*
* @param content 正文
* @return 当前构建器
*/
public MailBuilder html(String content) {
this.content = content;
this.html = true;
return this;
}
/**
* 设置正文。
*
* @param content 正文
* @param html 是否 HTML
* @return 当前构建器
*/
public MailBuilder content(String content, boolean html) {
this.content = content;
this.html = html;
return this;
}
/**
* 添加内联图片。
*
* @param cid 图片 cid
* @param inputStream 图片输入流
* @return 当前构建器
*/
public MailBuilder image(String cid, InputStream inputStream) {
if (StrUtil.isNotBlank(cid) && inputStream != null) {
this.images.put(cid, inputStream);
}
return this;
}
/**
* 添加内联图片。
*
* @param imageMap 图片 cid 与输入流映射
* @return 当前构建器
*/
public MailBuilder images(Map<String, InputStream> imageMap) {
if (MapUtil.isNotEmpty(imageMap)) {
imageMap.forEach(this::image);
}
return this;
}
/**
* 设置附件。
*
* @param files 附件列表
* @return 当前构建器
*/
public MailBuilder files(File... files) {
this.files = files == null ? new File[0] : files;
return this;
}
/**
* 发送邮件。
*
* @return message-id
*/
public String send() {
validate();
MailAccount account = resolveMailAccount();
JakartaMail mail = JakartaMail.create(account).setUseGlobalSession(useGlobalSession);
mail.setTos(tos.toArray(new String[0]));
if (CollUtil.isNotEmpty(ccs)) {
mail.setCcs(ccs.toArray(new String[0]));
}
if (CollUtil.isNotEmpty(bccs)) {
mail.setBccs(bccs.toArray(new String[0]));
}
mail.setTitle(subject);
mail.setContent(content);
mail.setHtml(html);
mail.setFiles(files);
try {
if (MapUtil.isNotEmpty(images)) {
images.forEach(mail::addImage);
}
return mail.send();
} finally {
images.values().forEach(IoUtil::close);
}
}
private void validate() {
if (CollUtil.isEmpty(tos)) {
throw new IllegalArgumentException("邮件收件人不能为空");
}
if (StrUtil.isBlank(subject)) {
throw new IllegalArgumentException("邮件标题不能为空");
}
if (content == null) {
throw new IllegalArgumentException("邮件正文不能为空");
}
}
private MailAccount resolveMailAccount() {
MailAccount account = mailAccount;
if (account == null) {
account = SpringUtils.getBean(MailAccount.class);
}
if (StringUtils.isAllBlank(from, user, pass)) {
return account;
}
MailAccount copy = ObjectUtil.clone(account);
copy.setFrom(StringUtils.blankToDefault(from, copy.getFrom()));
copy.setUser(StringUtils.blankToDefault(user, copy.getUser()));
copy.setPass(StringUtils.blankToDefault(pass, copy.getPass()));
return copy;
}
private List<String> splitAddress(String addresses) {
if (StrUtil.isBlank(addresses)) {
return Collections.emptyList();
}
return normalizeAddresses(StrUtil.splitTrim(addresses.replace(';', ','), ','));
}
private List<String> normalizeAddresses(Collection<String> addresses) {
if (CollUtil.isEmpty(addresses)) {
return Collections.emptyList();
}
List<String> result = new ArrayList<>(addresses.size());
for (String address : addresses) {
if (StrUtil.isNotBlank(address)) {
result.add(address.trim());
}
}
return result;
}
}

View File

@@ -1,473 +0,0 @@
package org.dromara.common.mail.utils;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.CharUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.mail.JakartaMail;
import cn.hutool.extra.mail.JakartaUserPassAuthenticator;
import cn.hutool.extra.mail.MailAccount;
import jakarta.mail.Authenticator;
import jakarta.mail.Session;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.StringUtils;
import java.io.File;
import java.io.InputStream;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
/**
* 邮件工具类
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class MailUtils {
private static final MailAccount ACCOUNT = SpringUtils.getBean(MailAccount.class);
/**
* 获取默认邮件账户配置。
*
* @return 邮件账户配置
*/
public static MailAccount getMailAccount() {
return ACCOUNT;
}
/**
* 获取邮件发送实例 (自定义发送人以及授权码)
*
* @param from 发送人
* @param user 发送人
* @param pass 授权码
* @return 邮件账户配置
*/
public static MailAccount getMailAccount(String from, String user, String pass) {
ACCOUNT.setFrom(StringUtils.blankToDefault(from, ACCOUNT.getFrom()));
ACCOUNT.setUser(StringUtils.blankToDefault(user, ACCOUNT.getUser()));
ACCOUNT.setPass(StringUtils.blankToDefault(pass, ACCOUNT.getPass()));
return ACCOUNT;
}
/**
* 使用配置文件中设置的账户发送文本邮件,发送给单个或多个收件人<br>
* 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔
*
* @param to 收件人
* @param subject 标题
* @param content 正文
* @param files 附件列表
* @return message-id
* @since 3.2.0
*/
public static String sendText(String to, String subject, String content, File... files) {
return send(to, subject, content, false, files);
}
/**
* 使用配置文件中设置的账户发送HTML邮件发送给单个或多个收件人<br>
* 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔
*
* @param to 收件人
* @param subject 标题
* @param content 正文
* @param files 附件列表
* @return message-id
* @since 3.2.0
*/
public static String sendHtml(String to, String subject, String content, File... files) {
return send(to, subject, content, true, files);
}
/**
* 使用配置文件中设置的账户发送邮件,发送单个或多个收件人<br>
* 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔
*
* @param to 收件人
* @param subject 标题
* @param content 正文
* @param isHtml 是否为HTML
* @param files 附件列表
* @return message-id
*/
public static String send(String to, String subject, String content, boolean isHtml, File... files) {
return send(splitAddress(to), subject, content, isHtml, files);
}
/**
* 使用配置文件中设置的账户发送邮件,发送单个或多个收件人<br>
* 多个收件人、抄送人、密送人可以使用逗号“,”分隔,也可以通过分号“;”分隔
*
* @param to 收件人,可以使用逗号“,”分隔,也可以通过分号“;”分隔
* @param cc 抄送人,可以使用逗号“,”分隔,也可以通过分号“;”分隔
* @param bcc 密送人,可以使用逗号“,”分隔,也可以通过分号“;”分隔
* @param subject 标题
* @param content 正文
* @param isHtml 是否为HTML
* @param files 附件列表
* @return message-id
* @since 4.0.3
*/
public static String send(String to, String cc, String bcc, String subject, String content, boolean isHtml, File... files) {
return send(splitAddress(to), splitAddress(cc), splitAddress(bcc), subject, content, isHtml, files);
}
/**
* 使用配置文件中设置的账户发送文本邮件,发送给多人
*
* @param tos 收件人列表
* @param subject 标题
* @param content 正文
* @param files 附件列表
* @return message-id
*/
public static String sendText(Collection<String> tos, String subject, String content, File... files) {
return send(tos, subject, content, false, files);
}
/**
* 使用配置文件中设置的账户发送HTML邮件发送给多人
*
* @param tos 收件人列表
* @param subject 标题
* @param content 正文
* @param files 附件列表
* @return message-id
* @since 3.2.0
*/
public static String sendHtml(Collection<String> tos, String subject, String content, File... files) {
return send(tos, subject, content, true, files);
}
/**
* 使用配置文件中设置的账户发送邮件,发送给多人
*
* @param tos 收件人列表
* @param subject 标题
* @param content 正文
* @param isHtml 是否为HTML
* @param files 附件列表
* @return message-id
*/
public static String send(Collection<String> tos, String subject, String content, boolean isHtml, File... files) {
return send(tos, null, null, subject, content, isHtml, files);
}
/**
* 使用配置文件中设置的账户发送邮件,发送给多人
*
* @param tos 收件人列表
* @param ccs 抄送人列表可以为null或空
* @param bccs 密送人列表可以为null或空
* @param subject 标题
* @param content 正文
* @param isHtml 是否为HTML
* @param files 附件列表
* @return message-id
* @since 4.0.3
*/
public static String send(Collection<String> tos, Collection<String> ccs, Collection<String> bccs, String subject, String content, boolean isHtml, File... files) {
return send(getMailAccount(), true, tos, ccs, bccs, subject, content, null, isHtml, files);
}
// ------------------------------------------------------------------------------------------------------------------------------- Custom MailAccount
/**
* 发送邮件给多人
*
* @param mailAccount 邮件认证对象
* @param to 收件人,多个收件人逗号或者分号隔开
* @param subject 标题
* @param content 正文
* @param isHtml 是否为HTML格式
* @param files 附件列表
* @return message-id
* @since 3.2.0
*/
public static String send(MailAccount mailAccount, String to, String subject, String content, boolean isHtml, File... files) {
return send(mailAccount, splitAddress(to), subject, content, isHtml, files);
}
/**
* 发送邮件给多人
*
* @param mailAccount 邮件账户信息
* @param tos 收件人列表
* @param subject 标题
* @param content 正文
* @param isHtml 是否为HTML格式
* @param files 附件列表
* @return message-id
*/
public static String send(MailAccount mailAccount, Collection<String> tos, String subject, String content, boolean isHtml, File... files) {
return send(mailAccount, tos, null, null, subject, content, isHtml, files);
}
/**
* 发送邮件给多人
*
* @param mailAccount 邮件账户信息
* @param tos 收件人列表
* @param ccs 抄送人列表可以为null或空
* @param bccs 密送人列表可以为null或空
* @param subject 标题
* @param content 正文
* @param isHtml 是否为HTML格式
* @param files 附件列表
* @return message-id
* @since 4.0.3
*/
public static String send(MailAccount mailAccount, Collection<String> tos, Collection<String> ccs, Collection<String> bccs, String subject, String content, boolean isHtml, File... files) {
return send(mailAccount, false, tos, ccs, bccs, subject, content, null, isHtml, files);
}
/**
* 使用配置文件中设置的账户发送HTML邮件发送给单个或多个收件人<br>
* 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔
*
* @param to 收件人
* @param subject 标题
* @param content 正文
* @param imageMap 图片与占位符占位符格式为cid:$IMAGE_PLACEHOLDER
* @param files 附件列表
* @return message-id
* @since 3.2.0
*/
public static String sendHtml(String to, String subject, String content, Map<String, InputStream> imageMap, File... files) {
return send(to, subject, content, imageMap, true, files);
}
/**
* 使用配置文件中设置的账户发送邮件,发送单个或多个收件人<br>
* 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔
*
* @param to 收件人
* @param subject 标题
* @param content 正文
* @param imageMap 图片与占位符占位符格式为cid:$IMAGE_PLACEHOLDER
* @param isHtml 是否为HTML
* @param files 附件列表
* @return message-id
*/
public static String send(String to, String subject, String content, Map<String, InputStream> imageMap, boolean isHtml, File... files) {
return send(splitAddress(to), subject, content, imageMap, isHtml, files);
}
/**
* 使用配置文件中设置的账户发送邮件,发送单个或多个收件人<br>
* 多个收件人、抄送人、密送人可以使用逗号“,”分隔,也可以通过分号“;”分隔
*
* @param to 收件人,可以使用逗号“,”分隔,也可以通过分号“;”分隔
* @param cc 抄送人,可以使用逗号“,”分隔,也可以通过分号“;”分隔
* @param bcc 密送人,可以使用逗号“,”分隔,也可以通过分号“;”分隔
* @param subject 标题
* @param content 正文
* @param imageMap 图片与占位符占位符格式为cid:$IMAGE_PLACEHOLDER
* @param isHtml 是否为HTML
* @param files 附件列表
* @return message-id
* @since 4.0.3
*/
public static String send(String to, String cc, String bcc, String subject, String content, Map<String, InputStream> imageMap, boolean isHtml, File... files) {
return send(splitAddress(to), splitAddress(cc), splitAddress(bcc), subject, content, imageMap, isHtml, files);
}
/**
* 使用配置文件中设置的账户发送HTML邮件发送给多人
*
* @param tos 收件人列表
* @param subject 标题
* @param content 正文
* @param imageMap 图片与占位符占位符格式为cid:$IMAGE_PLACEHOLDER
* @param files 附件列表
* @return message-id
* @since 3.2.0
*/
public static String sendHtml(Collection<String> tos, String subject, String content, Map<String, InputStream> imageMap, File... files) {
return send(tos, subject, content, imageMap, true, files);
}
/**
* 使用配置文件中设置的账户发送邮件,发送给多人
*
* @param tos 收件人列表
* @param subject 标题
* @param content 正文
* @param imageMap 图片与占位符占位符格式为cid:$IMAGE_PLACEHOLDER
* @param isHtml 是否为HTML
* @param files 附件列表
* @return message-id
*/
public static String send(Collection<String> tos, String subject, String content, Map<String, InputStream> imageMap, boolean isHtml, File... files) {
return send(tos, null, null, subject, content, imageMap, isHtml, files);
}
/**
* 使用配置文件中设置的账户发送邮件,发送给多人
*
* @param tos 收件人列表
* @param ccs 抄送人列表可以为null或空
* @param bccs 密送人列表可以为null或空
* @param subject 标题
* @param content 正文
* @param imageMap 图片与占位符占位符格式为cid:$IMAGE_PLACEHOLDER
* @param isHtml 是否为HTML
* @param files 附件列表
* @return message-id
* @since 4.0.3
*/
public static String send(Collection<String> tos, Collection<String> ccs, Collection<String> bccs, String subject, String content, Map<String, InputStream> imageMap, boolean isHtml, File... files) {
return send(getMailAccount(), true, tos, ccs, bccs, subject, content, imageMap, isHtml, files);
}
// ------------------------------------------------------------------------------------------------------------------------------- Custom MailAccount
/**
* 发送邮件给多人
*
* @param mailAccount 邮件认证对象
* @param to 收件人,多个收件人逗号或者分号隔开
* @param subject 标题
* @param content 正文
* @param imageMap 图片与占位符占位符格式为cid:$IMAGE_PLACEHOLDER
* @param isHtml 是否为HTML格式
* @param files 附件列表
* @return message-id
* @since 3.2.0
*/
public static String send(MailAccount mailAccount, String to, String subject, String content, Map<String, InputStream> imageMap, boolean isHtml, File... files) {
return send(mailAccount, splitAddress(to), subject, content, imageMap, isHtml, files);
}
/**
* 发送邮件给多人
*
* @param mailAccount 邮件账户信息
* @param tos 收件人列表
* @param subject 标题
* @param content 正文
* @param imageMap 图片与占位符占位符格式为cid:$IMAGE_PLACEHOLDER
* @param isHtml 是否为HTML格式
* @param files 附件列表
* @return message-id
* @since 4.6.3
*/
public static String send(MailAccount mailAccount, Collection<String> tos, String subject, String content, Map<String, InputStream> imageMap, boolean isHtml, File... files) {
return send(mailAccount, tos, null, null, subject, content, imageMap, isHtml, files);
}
/**
* 发送邮件给多人
*
* @param mailAccount 邮件账户信息
* @param tos 收件人列表
* @param ccs 抄送人列表可以为null或空
* @param bccs 密送人列表可以为null或空
* @param subject 标题
* @param content 正文
* @param imageMap 图片与占位符占位符格式为cid:$IMAGE_PLACEHOLDER
* @param isHtml 是否为HTML格式
* @param files 附件列表
* @return message-id
* @since 4.6.3
*/
public static String send(MailAccount mailAccount, Collection<String> tos, Collection<String> ccs, Collection<String> bccs, String subject, String content, Map<String, InputStream> imageMap,
boolean isHtml, File... files) {
return send(mailAccount, false, tos, ccs, bccs, subject, content, imageMap, isHtml, files);
}
/**
* 根据配置文件,获取邮件客户端会话
*
* @param mailAccount 邮件账户配置
* @param isSingleton 是否单例(全局共享会话)
* @return {@link Session}
* @since 5.5.7
*/
public static Session getSession(MailAccount mailAccount, boolean isSingleton) {
Authenticator authenticator = null;
if (mailAccount.isAuth()) {
authenticator = new JakartaUserPassAuthenticator(mailAccount.getUser(), mailAccount.getPass());
}
return isSingleton ? Session.getDefaultInstance(mailAccount.getSmtpProps(), authenticator) //
: Session.getInstance(mailAccount.getSmtpProps(), authenticator);
}
// ------------------------------------------------------------------------------------------------------------------------ Private method start
/**
* 发送邮件给多人
*
* @param mailAccount 邮件账户信息
* @param useGlobalSession 是否全局共享Session
* @param tos 收件人列表
* @param ccs 抄送人列表可以为null或空
* @param bccs 密送人列表可以为null或空
* @param subject 标题
* @param content 正文
* @param imageMap 图片与占位符占位符格式为cid:${cid}
* @param isHtml 是否为HTML格式
* @param files 附件列表
* @return message-id
* @since 4.6.3
*/
private static String send(MailAccount mailAccount, boolean useGlobalSession, Collection<String> tos, Collection<String> ccs, Collection<String> bccs, String subject, String content,
Map<String, InputStream> imageMap, boolean isHtml, File... files) {
final JakartaMail mail = JakartaMail.create(mailAccount).setUseGlobalSession(useGlobalSession);
// 可选抄送人
if (CollUtil.isNotEmpty(ccs)) {
mail.setCcs(ccs.toArray(new String[0]));
}
// 可选密送人
if (CollUtil.isNotEmpty(bccs)) {
mail.setBccs(bccs.toArray(new String[0]));
}
mail.setTos(tos.toArray(new String[0]));
mail.setTitle(subject);
mail.setContent(content);
mail.setHtml(isHtml);
mail.setFiles(files);
// 图片
if (MapUtil.isNotEmpty(imageMap)) {
for (Entry<String, InputStream> entry : imageMap.entrySet()) {
mail.addImage(entry.getKey(), entry.getValue());
// 关闭流
IoUtil.close(entry.getValue());
}
}
return mail.send();
}
/**
* 将多个联系人转为列表,分隔符为逗号或者分号
*
* @param addresses 多个联系人如果为空返回null
* @return 联系人列表
*/
private static List<String> splitAddress(String addresses) {
if (StrUtil.isBlank(addresses)) {
return null;
}
List<String> result;
if (StrUtil.contains(addresses, CharUtil.COMMA)) {
result = StrUtil.splitTrim(addresses, CharUtil.COMMA);
} else if (StrUtil.contains(addresses, ';')) {
result = StrUtil.splitTrim(addresses, ';');
} else {
result = CollUtil.newArrayList(addresses);
}
return result;
}
// ------------------------------------------------------------------------------------------------------------------------ Private method end
}

View File

@@ -2,7 +2,7 @@ package org.dromara.demo.controller;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.R;
import org.dromara.common.mail.utils.MailUtils;
import org.dromara.common.mail.core.MailBuilder;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -32,7 +32,7 @@ public class MailSendController {
*/
@GetMapping("/sendSimpleMessage")
public R<Void> sendSimpleMessage(String to, String subject, String text) {
MailUtils.sendText(to, subject, text);
MailBuilder.of().to(to).subject(subject).text(text).send();
return R.ok();
}
@@ -46,7 +46,7 @@ public class MailSendController {
@GetMapping("/sendMessageWithAttachment")
public R<Void> sendMessageWithAttachment(String to, String subject, String text) {
// 附件路径 禁止前端传递 有任意读取系统文件风险
MailUtils.sendText(to, subject, text, new File("/xxx/xxx"));
MailBuilder.of().to(to).subject(subject).text(text).files(new File("/xxx/xxx")).send();
return R.ok();
}
@@ -62,7 +62,7 @@ public class MailSendController {
// 附件路径 禁止前端传递 有任意读取系统文件风险
String[] paths = new String[]{"/xxx/xxx", "/xxx/xxx"};
File[] array = Arrays.stream(paths).map(File::new).toArray(File[]::new);
MailUtils.sendText(to, subject, text, array);
MailBuilder.of().to(to).subject(subject).text(text).files(array).send();
return R.ok();
}

View File

@@ -11,7 +11,7 @@ import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.StreamUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mail.utils.MailUtils;
import org.dromara.common.mail.core.MailBuilder;
import org.dromara.system.api.MessageService;
import org.dromara.system.api.domain.PushPayloadDTO;
import org.dromara.system.api.domain.UserDTO;
@@ -122,7 +122,7 @@ public class FlwCommonServiceImpl implements IFlwCommonService {
message, null, path
));
}
case EMAIL_MESSAGE -> MailUtils.sendText(emails, subject, message);
case EMAIL_MESSAGE -> MailBuilder.of().to(emails).subject(subject).text(message).send();
case SMS_MESSAGE -> {
// LinkedHashMap<String, String> map = new LinkedHashMap<>(1);
// // 根据具体短信服务商参数用法传参