mirror of
https://gitee.com/dromara/RuoYi-Vue-Plus.git
synced 2026-09-21 02:25:56 +08:00
Pre Merge pull request !328 from 余阳/5.X
This commit is contained in:
commit
6c64ceffcb
8
pom.xml
8
pom.xml
@ -50,7 +50,7 @@
|
|||||||
<!-- SMS 配置 -->
|
<!-- SMS 配置 -->
|
||||||
<aliyun.sms.version>2.0.23</aliyun.sms.version>
|
<aliyun.sms.version>2.0.23</aliyun.sms.version>
|
||||||
<tencent.sms.version>3.1.687</tencent.sms.version>
|
<tencent.sms.version>3.1.687</tencent.sms.version>
|
||||||
|
<javax.mail.version>1.6.2</javax.mail.version>
|
||||||
<!-- 插件版本 -->
|
<!-- 插件版本 -->
|
||||||
<maven-jar-plugin.version>3.2.2</maven-jar-plugin.version>
|
<maven-jar-plugin.version>3.2.2</maven-jar-plugin.version>
|
||||||
<maven-war-plugin.version>3.2.2</maven-war-plugin.version>
|
<maven-war-plugin.version>3.2.2</maven-war-plugin.version>
|
||||||
@ -311,6 +311,12 @@
|
|||||||
<version>${ip2region.version}</version>
|
<version>${ip2region.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.sun.mail</groupId>
|
||||||
|
<artifactId>javax.mail</artifactId>
|
||||||
|
<version>${javax.mail.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.dromara</groupId>
|
<groupId>org.dromara</groupId>
|
||||||
<artifactId>ruoyi-system</artifactId>
|
<artifactId>ruoyi-system</artifactId>
|
||||||
|
|||||||
@ -5,6 +5,10 @@ import cn.hutool.captcha.AbstractCaptcha;
|
|||||||
import cn.hutool.captcha.generator.CodeGenerator;
|
import cn.hutool.captcha.generator.CodeGenerator;
|
||||||
import cn.hutool.core.util.IdUtil;
|
import cn.hutool.core.util.IdUtil;
|
||||||
import cn.hutool.core.util.RandomUtil;
|
import cn.hutool.core.util.RandomUtil;
|
||||||
|
import cn.hutool.extra.mail.MailAccount;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.dromara.common.core.constant.Constants;
|
import org.dromara.common.core.constant.Constants;
|
||||||
import org.dromara.common.core.constant.GlobalConstants;
|
import org.dromara.common.core.constant.GlobalConstants;
|
||||||
import org.dromara.common.core.domain.R;
|
import org.dromara.common.core.domain.R;
|
||||||
@ -20,9 +24,6 @@ import org.dromara.common.sms.entity.SmsResult;
|
|||||||
import org.dromara.common.web.config.properties.CaptchaProperties;
|
import org.dromara.common.web.config.properties.CaptchaProperties;
|
||||||
import org.dromara.common.web.enums.CaptchaType;
|
import org.dromara.common.web.enums.CaptchaType;
|
||||||
import org.dromara.web.domain.vo.CaptchaVo;
|
import org.dromara.web.domain.vo.CaptchaVo;
|
||||||
import jakarta.validation.constraints.NotBlank;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.expression.Expression;
|
import org.springframework.expression.Expression;
|
||||||
import org.springframework.expression.ExpressionParser;
|
import org.springframework.expression.ExpressionParser;
|
||||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||||
@ -49,7 +50,7 @@ public class CaptchaController {
|
|||||||
private final CaptchaProperties captchaProperties;
|
private final CaptchaProperties captchaProperties;
|
||||||
private final SmsProperties smsProperties;
|
private final SmsProperties smsProperties;
|
||||||
private final MailProperties mailProperties;
|
private final MailProperties mailProperties;
|
||||||
|
private final MailAccount mailAccount;
|
||||||
/**
|
/**
|
||||||
* 短信验证码
|
* 短信验证码
|
||||||
*
|
*
|
||||||
@ -90,7 +91,7 @@ public class CaptchaController {
|
|||||||
String code = RandomUtil.randomNumbers(4);
|
String code = RandomUtil.randomNumbers(4);
|
||||||
RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
|
RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
|
||||||
try {
|
try {
|
||||||
MailUtils.sendText(email, "登录验证码", "您本次验证码为:" + code + ",有效性为" + Constants.CAPTCHA_EXPIRATION + "分钟,请尽快填写。");
|
MailUtils.sendText(mailAccount, email, "登录验证码", "您本次验证码为:" + code + ",有效性为" + Constants.CAPTCHA_EXPIRATION + "分钟,请尽快填写。");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("验证码短信发送异常 => {}", e.getMessage());
|
log.error("验证码短信发送异常 => {}", e.getMessage());
|
||||||
return R.fail(e.getMessage());
|
return R.fail(e.getMessage());
|
||||||
|
|||||||
@ -23,8 +23,8 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>jakarta.mail</groupId>
|
<groupId>com.sun.mail</groupId>
|
||||||
<artifactId>jakarta.mail-api</artifactId>
|
<artifactId>javax.mail</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|||||||
@ -1,108 +0,0 @@
|
|||||||
package org.dromara.common.mail.utils;
|
|
||||||
|
|
||||||
import cn.hutool.core.util.ArrayUtil;
|
|
||||||
import cn.hutool.extra.mail.MailException;
|
|
||||||
import jakarta.mail.internet.AddressException;
|
|
||||||
import jakarta.mail.internet.InternetAddress;
|
|
||||||
import jakarta.mail.internet.MimeUtility;
|
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 邮件内部工具类
|
|
||||||
* @author looly
|
|
||||||
* @since 3.2.3
|
|
||||||
*/
|
|
||||||
public class InternalMailUtil {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将多个字符串邮件地址转为{@link InternetAddress}列表<br>
|
|
||||||
* 单个字符串地址可以是多个地址合并的字符串
|
|
||||||
*
|
|
||||||
* @param addrStrs 地址数组
|
|
||||||
* @param charset 编码(主要用于中文用户名的编码)
|
|
||||||
* @return 地址数组
|
|
||||||
* @since 4.0.3
|
|
||||||
*/
|
|
||||||
public static InternetAddress[] parseAddressFromStrs(String[] addrStrs, Charset charset) {
|
|
||||||
final List<InternetAddress> resultList = new ArrayList<>(addrStrs.length);
|
|
||||||
InternetAddress[] addrs;
|
|
||||||
for (String addrStr : addrStrs) {
|
|
||||||
addrs = parseAddress(addrStr, charset);
|
|
||||||
if (ArrayUtil.isNotEmpty(addrs)) {
|
|
||||||
Collections.addAll(resultList, addrs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return resultList.toArray(new InternetAddress[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 解析第一个地址
|
|
||||||
*
|
|
||||||
* @param address 地址字符串
|
|
||||||
* @param charset 编码,{@code null}表示使用系统属性定义的编码或系统编码
|
|
||||||
* @return 地址列表
|
|
||||||
*/
|
|
||||||
public static InternetAddress parseFirstAddress(String address, Charset charset) {
|
|
||||||
final InternetAddress[] internetAddresses = parseAddress(address, charset);
|
|
||||||
if (ArrayUtil.isEmpty(internetAddresses)) {
|
|
||||||
try {
|
|
||||||
return new InternetAddress(address);
|
|
||||||
} catch (AddressException e) {
|
|
||||||
throw new MailException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return internetAddresses[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将一个地址字符串解析为多个地址<br>
|
|
||||||
* 地址间使用" "、","、";"分隔
|
|
||||||
*
|
|
||||||
* @param address 地址字符串
|
|
||||||
* @param charset 编码,{@code null}表示使用系统属性定义的编码或系统编码
|
|
||||||
* @return 地址列表
|
|
||||||
*/
|
|
||||||
public static InternetAddress[] parseAddress(String address, Charset charset) {
|
|
||||||
InternetAddress[] addresses;
|
|
||||||
try {
|
|
||||||
addresses = InternetAddress.parse(address);
|
|
||||||
} catch (AddressException e) {
|
|
||||||
throw new MailException(e);
|
|
||||||
}
|
|
||||||
//编码用户名
|
|
||||||
if (ArrayUtil.isNotEmpty(addresses)) {
|
|
||||||
final String charsetStr = null == charset ? null : charset.name();
|
|
||||||
for (InternetAddress internetAddress : addresses) {
|
|
||||||
try {
|
|
||||||
internetAddress.setPersonal(internetAddress.getPersonal(), charsetStr);
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
throw new MailException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return addresses;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 编码中文字符<br>
|
|
||||||
* 编码失败返回原字符串
|
|
||||||
*
|
|
||||||
* @param text 被编码的文本
|
|
||||||
* @param charset 编码
|
|
||||||
* @return 编码后的结果
|
|
||||||
*/
|
|
||||||
public static String encodeText(String text, Charset charset) {
|
|
||||||
try {
|
|
||||||
return MimeUtility.encodeText(text, charset.name(), null);
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,486 +0,0 @@
|
|||||||
package org.dromara.common.mail.utils;
|
|
||||||
|
|
||||||
import cn.hutool.core.builder.Builder;
|
|
||||||
import cn.hutool.core.io.FileUtil;
|
|
||||||
import cn.hutool.core.io.IORuntimeException;
|
|
||||||
import cn.hutool.core.io.IoUtil;
|
|
||||||
import cn.hutool.core.util.ArrayUtil;
|
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import cn.hutool.extra.mail.*;
|
|
||||||
import jakarta.activation.DataHandler;
|
|
||||||
import jakarta.activation.DataSource;
|
|
||||||
import jakarta.activation.FileDataSource;
|
|
||||||
import jakarta.activation.FileTypeMap;
|
|
||||||
import jakarta.mail.*;
|
|
||||||
import jakarta.mail.internet.MimeBodyPart;
|
|
||||||
import jakarta.mail.internet.MimeMessage;
|
|
||||||
import jakarta.mail.internet.MimeMultipart;
|
|
||||||
import jakarta.mail.internet.MimeUtility;
|
|
||||||
import jakarta.mail.util.ByteArrayDataSource;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.PrintStream;
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 邮件发送客户端
|
|
||||||
*
|
|
||||||
* @author looly
|
|
||||||
* @since 3.2.0
|
|
||||||
*/
|
|
||||||
public class Mail implements Builder<MimeMessage> {
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 邮箱帐户信息以及一些客户端配置信息
|
|
||||||
*/
|
|
||||||
private final MailAccount mailAccount;
|
|
||||||
/**
|
|
||||||
* 收件人列表
|
|
||||||
*/
|
|
||||||
private String[] tos;
|
|
||||||
/**
|
|
||||||
* 抄送人列表(carbon copy)
|
|
||||||
*/
|
|
||||||
private String[] ccs;
|
|
||||||
/**
|
|
||||||
* 密送人列表(blind carbon copy)
|
|
||||||
*/
|
|
||||||
private String[] bccs;
|
|
||||||
/**
|
|
||||||
* 回复地址(reply-to)
|
|
||||||
*/
|
|
||||||
private String[] reply;
|
|
||||||
/**
|
|
||||||
* 标题
|
|
||||||
*/
|
|
||||||
private String title;
|
|
||||||
/**
|
|
||||||
* 内容
|
|
||||||
*/
|
|
||||||
private String content;
|
|
||||||
/**
|
|
||||||
* 是否为HTML
|
|
||||||
*/
|
|
||||||
private boolean isHtml;
|
|
||||||
/**
|
|
||||||
* 正文、附件和图片的混合部分
|
|
||||||
*/
|
|
||||||
private final Multipart multipart = new MimeMultipart();
|
|
||||||
/**
|
|
||||||
* 是否使用全局会话,默认为false
|
|
||||||
*/
|
|
||||||
private boolean useGlobalSession = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* debug输出位置,可以自定义debug日志
|
|
||||||
*/
|
|
||||||
private PrintStream debugOutput;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建邮件客户端
|
|
||||||
*
|
|
||||||
* @param mailAccount 邮件帐号
|
|
||||||
* @return Mail
|
|
||||||
*/
|
|
||||||
public static Mail create(MailAccount mailAccount) {
|
|
||||||
return new Mail(mailAccount);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建邮件客户端,使用全局邮件帐户
|
|
||||||
*
|
|
||||||
* @return Mail
|
|
||||||
*/
|
|
||||||
public static Mail create() {
|
|
||||||
return new Mail();
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------------------------------------------------------- Constructor start
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构造,使用全局邮件帐户
|
|
||||||
*/
|
|
||||||
public Mail() {
|
|
||||||
this(GlobalMailAccount.INSTANCE.getAccount());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构造
|
|
||||||
*
|
|
||||||
* @param mailAccount 邮件帐户,如果为null使用默认配置文件的全局邮件配置
|
|
||||||
*/
|
|
||||||
public Mail(MailAccount mailAccount) {
|
|
||||||
mailAccount = (null != mailAccount) ? mailAccount : GlobalMailAccount.INSTANCE.getAccount();
|
|
||||||
this.mailAccount = mailAccount.defaultIfEmpty();
|
|
||||||
}
|
|
||||||
// --------------------------------------------------------------- Constructor end
|
|
||||||
|
|
||||||
// --------------------------------------------------------------- Getters and Setters start
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置收件人
|
|
||||||
*
|
|
||||||
* @param tos 收件人列表
|
|
||||||
* @return this
|
|
||||||
* @see #setTos(String...)
|
|
||||||
*/
|
|
||||||
public Mail to(String... tos) {
|
|
||||||
return setTos(tos);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置多个收件人
|
|
||||||
*
|
|
||||||
* @param tos 收件人列表
|
|
||||||
* @return this
|
|
||||||
*/
|
|
||||||
public Mail setTos(String... tos) {
|
|
||||||
this.tos = tos;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置多个抄送人(carbon copy)
|
|
||||||
*
|
|
||||||
* @param ccs 抄送人列表
|
|
||||||
* @return this
|
|
||||||
* @since 4.0.3
|
|
||||||
*/
|
|
||||||
public Mail setCcs(String... ccs) {
|
|
||||||
this.ccs = ccs;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置多个密送人(blind carbon copy)
|
|
||||||
*
|
|
||||||
* @param bccs 密送人列表
|
|
||||||
* @return this
|
|
||||||
* @since 4.0.3
|
|
||||||
*/
|
|
||||||
public Mail setBccs(String... bccs) {
|
|
||||||
this.bccs = bccs;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置多个回复地址(reply-to)
|
|
||||||
*
|
|
||||||
* @param reply 回复地址(reply-to)列表
|
|
||||||
* @return this
|
|
||||||
* @since 4.6.0
|
|
||||||
*/
|
|
||||||
public Mail setReply(String... reply) {
|
|
||||||
this.reply = reply;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置标题
|
|
||||||
*
|
|
||||||
* @param title 标题
|
|
||||||
* @return this
|
|
||||||
*/
|
|
||||||
public Mail setTitle(String title) {
|
|
||||||
this.title = title;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置正文<br>
|
|
||||||
* 正文可以是普通文本也可以是HTML(默认普通文本),可以通过调用{@link #setHtml(boolean)} 设置是否为HTML
|
|
||||||
*
|
|
||||||
* @param content 正文
|
|
||||||
* @return this
|
|
||||||
*/
|
|
||||||
public Mail setContent(String content) {
|
|
||||||
this.content = content;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置是否是HTML
|
|
||||||
*
|
|
||||||
* @param isHtml 是否为HTML
|
|
||||||
* @return this
|
|
||||||
*/
|
|
||||||
public Mail setHtml(boolean isHtml) {
|
|
||||||
this.isHtml = isHtml;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置正文
|
|
||||||
*
|
|
||||||
* @param content 正文内容
|
|
||||||
* @param isHtml 是否为HTML
|
|
||||||
* @return this
|
|
||||||
*/
|
|
||||||
public Mail setContent(String content, boolean isHtml) {
|
|
||||||
setContent(content);
|
|
||||||
return setHtml(isHtml);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置文件类型附件,文件可以是图片文件,此时自动设置cid(正文中引用图片),默认cid为文件名
|
|
||||||
*
|
|
||||||
* @param files 附件文件列表
|
|
||||||
* @return this
|
|
||||||
*/
|
|
||||||
public Mail setFiles(File... files) {
|
|
||||||
if (ArrayUtil.isEmpty(files)) {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
final DataSource[] attachments = new DataSource[files.length];
|
|
||||||
for (int i = 0; i < files.length; i++) {
|
|
||||||
attachments[i] = new FileDataSource(files[i]);
|
|
||||||
}
|
|
||||||
return setAttachments(attachments);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 增加附件或图片,附件使用{@link DataSource} 形式表示,可以使用{@link FileDataSource}包装文件表示文件附件
|
|
||||||
*
|
|
||||||
* @param attachments 附件列表
|
|
||||||
* @return this
|
|
||||||
* @since 4.0.9
|
|
||||||
*/
|
|
||||||
public Mail setAttachments(DataSource... attachments) {
|
|
||||||
if (ArrayUtil.isNotEmpty(attachments)) {
|
|
||||||
final Charset charset = this.mailAccount.getCharset();
|
|
||||||
MimeBodyPart bodyPart;
|
|
||||||
String nameEncoded;
|
|
||||||
try {
|
|
||||||
for (DataSource attachment : attachments) {
|
|
||||||
bodyPart = new MimeBodyPart();
|
|
||||||
bodyPart.setDataHandler(new DataHandler(attachment));
|
|
||||||
nameEncoded = attachment.getName();
|
|
||||||
if (this.mailAccount.isEncodefilename()) {
|
|
||||||
nameEncoded = org.dromara.common.mail.utils.InternalMailUtil.encodeText(nameEncoded, charset);
|
|
||||||
}
|
|
||||||
// 普通附件文件名
|
|
||||||
bodyPart.setFileName(nameEncoded);
|
|
||||||
if (StrUtil.startWith(attachment.getContentType(), "image/")) {
|
|
||||||
// 图片附件,用于正文中引用图片
|
|
||||||
bodyPart.setContentID(nameEncoded);
|
|
||||||
}
|
|
||||||
this.multipart.addBodyPart(bodyPart);
|
|
||||||
}
|
|
||||||
} catch (MessagingException e) {
|
|
||||||
throw new MailException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 增加图片,图片的键对应到邮件模板中的占位字符串,图片类型默认为"image/jpeg"
|
|
||||||
*
|
|
||||||
* @param cid 图片与占位符,占位符格式为cid:${cid}
|
|
||||||
* @param imageStream 图片文件
|
|
||||||
* @return this
|
|
||||||
* @since 4.6.3
|
|
||||||
*/
|
|
||||||
public Mail addImage(String cid, InputStream imageStream) {
|
|
||||||
return addImage(cid, imageStream, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 增加图片,图片的键对应到邮件模板中的占位字符串
|
|
||||||
*
|
|
||||||
* @param cid 图片与占位符,占位符格式为cid:${cid}
|
|
||||||
* @param imageStream 图片流,不关闭
|
|
||||||
* @param contentType 图片类型,null赋值默认的"image/jpeg"
|
|
||||||
* @return this
|
|
||||||
* @since 4.6.3
|
|
||||||
*/
|
|
||||||
public Mail addImage(String cid, InputStream imageStream, String contentType) {
|
|
||||||
ByteArrayDataSource imgSource;
|
|
||||||
try {
|
|
||||||
imgSource = new ByteArrayDataSource(imageStream, ObjectUtil.defaultIfNull(contentType, "image/jpeg"));
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new IORuntimeException(e);
|
|
||||||
}
|
|
||||||
imgSource.setName(cid);
|
|
||||||
return setAttachments(imgSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 增加图片,图片的键对应到邮件模板中的占位字符串
|
|
||||||
*
|
|
||||||
* @param cid 图片与占位符,占位符格式为cid:${cid}
|
|
||||||
* @param imageFile 图片文件
|
|
||||||
* @return this
|
|
||||||
* @since 4.6.3
|
|
||||||
*/
|
|
||||||
public Mail addImage(String cid, File imageFile) {
|
|
||||||
InputStream in = null;
|
|
||||||
try {
|
|
||||||
in = FileUtil.getInputStream(imageFile);
|
|
||||||
return addImage(cid, in, FileTypeMap.getDefaultFileTypeMap().getContentType(imageFile));
|
|
||||||
} finally {
|
|
||||||
IoUtil.close(in);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置字符集编码
|
|
||||||
*
|
|
||||||
* @param charset 字符集编码
|
|
||||||
* @return this
|
|
||||||
* @see MailAccount#setCharset(Charset)
|
|
||||||
*/
|
|
||||||
public Mail setCharset(Charset charset) {
|
|
||||||
this.mailAccount.setCharset(charset);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置是否使用全局会话,默认为true
|
|
||||||
*
|
|
||||||
* @param isUseGlobalSession 是否使用全局会话,默认为true
|
|
||||||
* @return this
|
|
||||||
* @since 4.0.2
|
|
||||||
*/
|
|
||||||
public Mail setUseGlobalSession(boolean isUseGlobalSession) {
|
|
||||||
this.useGlobalSession = isUseGlobalSession;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置debug输出位置,可以自定义debug日志
|
|
||||||
*
|
|
||||||
* @param debugOutput debug输出位置
|
|
||||||
* @return this
|
|
||||||
* @since 5.5.6
|
|
||||||
*/
|
|
||||||
public Mail setDebugOutput(PrintStream debugOutput) {
|
|
||||||
this.debugOutput = debugOutput;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
// --------------------------------------------------------------- Getters and Setters end
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MimeMessage build() {
|
|
||||||
try {
|
|
||||||
return buildMsg();
|
|
||||||
} catch (MessagingException e) {
|
|
||||||
throw new MailException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 发送
|
|
||||||
*
|
|
||||||
* @return message-id
|
|
||||||
* @throws MailException 邮件发送异常
|
|
||||||
*/
|
|
||||||
public String send() throws MailException {
|
|
||||||
try {
|
|
||||||
return doSend();
|
|
||||||
} catch (MessagingException e) {
|
|
||||||
if (e instanceof SendFailedException) {
|
|
||||||
// 当地址无效时,显示更加详细的无效地址信息
|
|
||||||
final Address[] invalidAddresses = ((SendFailedException) e).getInvalidAddresses();
|
|
||||||
final String msg = StrUtil.format("Invalid Addresses: {}", ArrayUtil.toString(invalidAddresses));
|
|
||||||
throw new MailException(msg, e);
|
|
||||||
}
|
|
||||||
throw new MailException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------------------------------------------------------- Private method start
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 执行发送
|
|
||||||
*
|
|
||||||
* @return message-id
|
|
||||||
* @throws MessagingException 发送异常
|
|
||||||
*/
|
|
||||||
private String doSend() throws MessagingException {
|
|
||||||
final MimeMessage mimeMessage = buildMsg();
|
|
||||||
Transport.send(mimeMessage);
|
|
||||||
return mimeMessage.getMessageID();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构建消息
|
|
||||||
*
|
|
||||||
* @return {@link MimeMessage}消息
|
|
||||||
* @throws MessagingException 消息异常
|
|
||||||
*/
|
|
||||||
private MimeMessage buildMsg() throws MessagingException {
|
|
||||||
final Charset charset = this.mailAccount.getCharset();
|
|
||||||
final MimeMessage msg = new MimeMessage(getSession());
|
|
||||||
// 发件人
|
|
||||||
final String from = this.mailAccount.getFrom();
|
|
||||||
if (StrUtil.isEmpty(from)) {
|
|
||||||
// 用户未提供发送方,则从Session中自动获取
|
|
||||||
msg.setFrom();
|
|
||||||
} else {
|
|
||||||
msg.setFrom(org.dromara.common.mail.utils.InternalMailUtil.parseFirstAddress(from, charset));
|
|
||||||
}
|
|
||||||
// 标题
|
|
||||||
msg.setSubject(this.title, (null == charset) ? null : charset.name());
|
|
||||||
// 发送时间
|
|
||||||
msg.setSentDate(new Date());
|
|
||||||
// 内容和附件
|
|
||||||
msg.setContent(buildContent(charset));
|
|
||||||
// 收件人
|
|
||||||
msg.setRecipients(MimeMessage.RecipientType.TO, org.dromara.common.mail.utils.InternalMailUtil.parseAddressFromStrs(this.tos, charset));
|
|
||||||
// 抄送人
|
|
||||||
if (ArrayUtil.isNotEmpty(this.ccs)) {
|
|
||||||
msg.setRecipients(MimeMessage.RecipientType.CC, org.dromara.common.mail.utils.InternalMailUtil.parseAddressFromStrs(this.ccs, charset));
|
|
||||||
}
|
|
||||||
// 密送人
|
|
||||||
if (ArrayUtil.isNotEmpty(this.bccs)) {
|
|
||||||
msg.setRecipients(MimeMessage.RecipientType.BCC, org.dromara.common.mail.utils.InternalMailUtil.parseAddressFromStrs(this.bccs, charset));
|
|
||||||
}
|
|
||||||
// 回复地址(reply-to)
|
|
||||||
if (ArrayUtil.isNotEmpty(this.reply)) {
|
|
||||||
msg.setReplyTo(InternalMailUtil.parseAddressFromStrs(this.reply, charset));
|
|
||||||
}
|
|
||||||
|
|
||||||
return msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构建邮件信息主体
|
|
||||||
*
|
|
||||||
* @param charset 编码,{@code null}则使用{@link MimeUtility#getDefaultJavaCharset()}
|
|
||||||
* @return 邮件信息主体
|
|
||||||
* @throws MessagingException 消息异常
|
|
||||||
*/
|
|
||||||
private Multipart buildContent(Charset charset) throws MessagingException {
|
|
||||||
final String charsetStr = null != charset ? charset.name() : MimeUtility.getDefaultJavaCharset();
|
|
||||||
// 正文
|
|
||||||
final MimeBodyPart body = new MimeBodyPart();
|
|
||||||
body.setContent(content, StrUtil.format("text/{}; charset={}", isHtml ? "html" : "plain", charsetStr));
|
|
||||||
this.multipart.addBodyPart(body);
|
|
||||||
|
|
||||||
return this.multipart;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取默认邮件会话<br>
|
|
||||||
* 如果为全局单例的会话,则全局只允许一个邮件帐号,否则每次发送邮件会新建一个新的会话
|
|
||||||
*
|
|
||||||
* @return 邮件会话 {@link Session}
|
|
||||||
*/
|
|
||||||
private Session getSession() {
|
|
||||||
final Session session = MailUtils.getSession(this.mailAccount, this.useGlobalSession);
|
|
||||||
|
|
||||||
if (null != this.debugOutput) {
|
|
||||||
session.setDebugOut(debugOutput);
|
|
||||||
}
|
|
||||||
|
|
||||||
return session;
|
|
||||||
}
|
|
||||||
// --------------------------------------------------------------- Private method end
|
|
||||||
}
|
|
||||||
@ -1,54 +1,15 @@
|
|||||||
package org.dromara.common.mail.utils;
|
package org.dromara.common.mail.utils;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.extra.mail.MailAccount;
|
||||||
import cn.hutool.core.io.IoUtil;
|
import cn.hutool.extra.mail.MailUtil;
|
||||||
import cn.hutool.core.map.MapUtil;
|
|
||||||
import cn.hutool.core.util.CharUtil;
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import cn.hutool.extra.mail.*;
|
|
||||||
import org.dromara.common.core.utils.SpringUtils;
|
|
||||||
import org.dromara.common.core.utils.StringUtils;
|
|
||||||
import lombok.AccessLevel;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
|
|
||||||
import jakarta.mail.Authenticator;
|
|
||||||
import jakarta.mail.Session;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 邮件工具类
|
* @author yuyang
|
||||||
|
* @date 2023-04-03
|
||||||
*/
|
*/
|
||||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
|
||||||
public class MailUtils {
|
public class MailUtils {
|
||||||
|
|
||||||
private static final MailAccount ACCOUNT = SpringUtils.getBean(MailAccount.class);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取邮件发送实例
|
|
||||||
*/
|
|
||||||
public static MailAccount getMailAccount() {
|
|
||||||
return ACCOUNT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取邮件发送实例 (自定义发送人以及授权码)
|
|
||||||
*
|
|
||||||
* @param user 发送人
|
|
||||||
* @param pass 授权码
|
|
||||||
*/
|
|
||||||
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>
|
* 使用配置文件中设置的账户发送文本邮件,发送给单个或多个收件人<br>
|
||||||
* 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔
|
* 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔
|
||||||
@ -60,410 +21,7 @@ public class MailUtils {
|
|||||||
* @return message-id
|
* @return message-id
|
||||||
* @since 3.2.0
|
* @since 3.2.0
|
||||||
*/
|
*/
|
||||||
public static String sendText(String to, String subject, String content, File... files) {
|
public static String sendText(MailAccount mailAccount, String to, String subject, String content, File... files) {
|
||||||
return send(to, subject, content, false, files);
|
return MailUtil.send(mailAccount, 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 UserPassAuthenticator(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 org.dromara.common.mail.utils.Mail mail = Mail.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 (Map.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
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,33 +0,0 @@
|
|||||||
package org.dromara.common.mail.utils;
|
|
||||||
|
|
||||||
import jakarta.mail.Authenticator;
|
|
||||||
import jakarta.mail.PasswordAuthentication;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户名密码验证器
|
|
||||||
*
|
|
||||||
* @author looly
|
|
||||||
* @since 3.1.2
|
|
||||||
*/
|
|
||||||
public class UserPassAuthenticator extends Authenticator {
|
|
||||||
|
|
||||||
private final String user;
|
|
||||||
private final String pass;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构造
|
|
||||||
*
|
|
||||||
* @param user 用户名
|
|
||||||
* @param pass 密码
|
|
||||||
*/
|
|
||||||
public UserPassAuthenticator(String user, String pass) {
|
|
||||||
this.user = user;
|
|
||||||
this.pass = pass;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected PasswordAuthentication getPasswordAuthentication() {
|
|
||||||
return new PasswordAuthentication(this.user, this.pass);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,8 +1,9 @@
|
|||||||
package org.dromara.demo.controller;
|
package org.dromara.demo.controller;
|
||||||
|
|
||||||
|
import cn.hutool.extra.mail.MailAccount;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.dromara.common.core.domain.R;
|
import org.dromara.common.core.domain.R;
|
||||||
import org.dromara.common.mail.utils.MailUtils;
|
import org.dromara.common.mail.utils.MailUtils;
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
@ -21,7 +22,7 @@ import java.io.File;
|
|||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/demo/mail")
|
@RequestMapping("/demo/mail")
|
||||||
public class MailController {
|
public class MailController {
|
||||||
|
private final MailAccount mailAccount;
|
||||||
/**
|
/**
|
||||||
* 发送邮件
|
* 发送邮件
|
||||||
*
|
*
|
||||||
@ -31,7 +32,7 @@ public class MailController {
|
|||||||
*/
|
*/
|
||||||
@GetMapping("/sendSimpleMessage")
|
@GetMapping("/sendSimpleMessage")
|
||||||
public R<Void> sendSimpleMessage(String to, String subject, String text) {
|
public R<Void> sendSimpleMessage(String to, String subject, String text) {
|
||||||
MailUtils.sendText(to, subject, text);
|
MailUtils.sendText(mailAccount, to, subject, text);
|
||||||
return R.ok();
|
return R.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,7 +46,7 @@ public class MailController {
|
|||||||
*/
|
*/
|
||||||
@GetMapping("/sendMessageWithAttachment")
|
@GetMapping("/sendMessageWithAttachment")
|
||||||
public R<Void> sendMessageWithAttachment(String to, String subject, String text, String filePath) {
|
public R<Void> sendMessageWithAttachment(String to, String subject, String text, String filePath) {
|
||||||
MailUtils.sendText(to, subject, text, new File(filePath));
|
MailUtils.sendText(mailAccount, to, subject, text, new File(filePath));
|
||||||
return R.ok();
|
return R.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user