From 99db6dceea69a0959d447569d95e4cda1b1c29e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=96=AF=E7=8B=82=E7=9A=84=E7=8B=AE=E5=AD=90Li?= <15040126243@163.com> Date: Sat, 16 May 2026 14:25:34 +0800 Subject: [PATCH] =?UTF-8?q?refactor(common-mail):=20=E4=BD=BF=E7=94=A8=20M?= =?UTF-8?q?ailBuilder=20=E6=9B=BF=E4=BB=A3=20MailUtils?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增链式 MailBuilder,统一邮件发送入口 - 删除 MailUtils,业务代码全部切换为 builder 调用 - 默认邮件账户改为发送时获取,避免类加载阶段依赖 Bean - 自定义发件账号时复制默认配置,避免污染全局 MailAccount - 增加收件人、标题和正文参数校验 - 调整内联图片流关闭时机,发送结束后统一关闭 - 将 MailAccount 构建逻辑下沉到 MailProperties --- .../web/controller/CaptchaController.java | 8 +- .../common/mail/config/MailConfig.java | 14 +- .../config/properties/MailProperties.java | 22 + .../dromara/common/mail/core/MailBuilder.java | 347 +++++++++++++ .../dromara/common/mail/utils/MailUtils.java | 473 ------------------ .../demo/controller/MailSendController.java | 8 +- .../service/impl/FlwCommonServiceImpl.java | 4 +- 7 files changed, 382 insertions(+), 494 deletions(-) create mode 100644 ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/core/MailBuilder.java delete mode 100644 ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailUtils.java diff --git a/ruoyi-admin/src/main/java/org/dromara/web/controller/CaptchaController.java b/ruoyi-admin/src/main/java/org/dromara/web/controller/CaptchaController.java index 472217a6f..f1e5c32bb 100644 --- a/ruoyi-admin/src/main/java/org/dromara/web/controller/CaptchaController.java +++ b/ruoyi-admin/src/main/java/org/dromara/web/controller/CaptchaController.java @@ -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()); diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/MailConfig.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/MailConfig.java index 0ea3007b9..a0042dddd 100644 --- a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/MailConfig.java +++ b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/MailConfig.java @@ -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(); } } diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/properties/MailProperties.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/properties/MailProperties.java index e44aa3da3..8347effb0 100644 --- a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/properties/MailProperties.java +++ b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/properties/MailProperties.java @@ -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; + } } diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/core/MailBuilder.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/core/MailBuilder.java new file mode 100644 index 000000000..2cd98de7b --- /dev/null +++ b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/core/MailBuilder.java @@ -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 tos = new ArrayList<>(); + + private final List ccs = new ArrayList<>(); + + private final List bccs = new ArrayList<>(); + + private final Map 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 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 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 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 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 splitAddress(String addresses) { + if (StrUtil.isBlank(addresses)) { + return Collections.emptyList(); + } + return normalizeAddresses(StrUtil.splitTrim(addresses.replace(';', ','), ',')); + } + + private List normalizeAddresses(Collection addresses) { + if (CollUtil.isEmpty(addresses)) { + return Collections.emptyList(); + } + List result = new ArrayList<>(addresses.size()); + for (String address : addresses) { + if (StrUtil.isNotBlank(address)) { + result.add(address.trim()); + } + } + return result; + } + +} diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailUtils.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailUtils.java deleted file mode 100644 index 06343bda0..000000000 --- a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailUtils.java +++ /dev/null @@ -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; - } - - /** - * 使用配置文件中设置的账户发送文本邮件,发送给单个或多个收件人
- * 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔 - * - * @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邮件,发送给单个或多个收件人
- * 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔 - * - * @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); - } - - /** - * 使用配置文件中设置的账户发送邮件,发送单个或多个收件人
- * 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔 - * - * @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); - } - - /** - * 使用配置文件中设置的账户发送邮件,发送单个或多个收件人
- * 多个收件人、抄送人、密送人可以使用逗号“,”分隔,也可以通过分号“;”分隔 - * - * @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 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 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 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 tos, Collection ccs, Collection 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 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 tos, Collection ccs, Collection bccs, String subject, String content, boolean isHtml, File... files) { - return send(mailAccount, false, tos, ccs, bccs, subject, content, null, isHtml, files); - } - - /** - * 使用配置文件中设置的账户发送HTML邮件,发送给单个或多个收件人
- * 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔 - * - * @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 imageMap, File... files) { - return send(to, subject, content, imageMap, true, files); - } - - /** - * 使用配置文件中设置的账户发送邮件,发送单个或多个收件人
- * 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔 - * - * @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 imageMap, boolean isHtml, File... files) { - return send(splitAddress(to), subject, content, imageMap, isHtml, files); - } - - /** - * 使用配置文件中设置的账户发送邮件,发送单个或多个收件人
- * 多个收件人、抄送人、密送人可以使用逗号“,”分隔,也可以通过分号“;”分隔 - * - * @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 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 tos, String subject, String content, Map 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 tos, String subject, String content, Map 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 tos, Collection ccs, Collection bccs, String subject, String content, Map 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 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 tos, String subject, String content, Map 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 tos, Collection ccs, Collection bccs, String subject, String content, Map 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 tos, Collection ccs, Collection bccs, String subject, String content, - Map 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 entry : imageMap.entrySet()) { - mail.addImage(entry.getKey(), entry.getValue()); - // 关闭流 - IoUtil.close(entry.getValue()); - } - } - - return mail.send(); - } - - /** - * 将多个联系人转为列表,分隔符为逗号或者分号 - * - * @param addresses 多个联系人,如果为空返回null - * @return 联系人列表 - */ - private static List splitAddress(String addresses) { - if (StrUtil.isBlank(addresses)) { - return null; - } - - List 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 -} diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/MailSendController.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/MailSendController.java index 48365a350..9bf51afa2 100644 --- a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/MailSendController.java +++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/MailSendController.java @@ -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 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 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(); } diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCommonServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCommonServiceImpl.java index a1abc472d..9f790c187 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCommonServiceImpl.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCommonServiceImpl.java @@ -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 map = new LinkedHashMap<>(1); // // 根据具体短信服务商参数用法传参