From 662df23d4ddb9260670cb30b88c5eaaffa2a9e36 Mon Sep 17 00:00:00 2001
From: 疯狂的狮子Li <15040126243@163.com>
Date: 星期日, 12 三月 2023 18:21:30 +0800
Subject: [PATCH] fix 修复 hutool MailUtils 未适配 jakarta 问题

---
 ruoyi-common/ruoyi-common-mail/src/main/java/com/ruoyi/common/mail/utils/InternalMailUtil.java |  108 ++++++++++
 ruoyi-common/ruoyi-common-mail/src/main/java/com/ruoyi/common/mail/utils/Mail.java             |  486 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 594 insertions(+), 0 deletions(-)

diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/com/ruoyi/common/mail/utils/InternalMailUtil.java b/ruoyi-common/ruoyi-common-mail/src/main/java/com/ruoyi/common/mail/utils/InternalMailUtil.java
new file mode 100644
index 0000000..28543c0
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-mail/src/main/java/com/ruoyi/common/mail/utils/InternalMailUtil.java
@@ -0,0 +1,108 @@
+package com.ruoyi.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]);
+	}
+
+	/**
+	 * 瑙f瀽绗竴涓湴鍧�
+	 *
+	 * @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;
+	}
+}
diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/com/ruoyi/common/mail/utils/Mail.java b/ruoyi-common/ruoyi-common-mail/src/main/java/com/ruoyi/common/mail/utils/Mail.java
new file mode 100644
index 0000000..5599be3
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-mail/src/main/java/com/ruoyi/common/mail/utils/Mail.java
@@ -0,0 +1,486 @@
+package com.ruoyi.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;
+	/**
+	 * 鎶勯�佷汉鍒楄〃锛坈arbon copy锛�
+	 */
+	private String[] ccs;
+	/**
+	 * 瀵嗛�佷汉鍒楄〃锛坆lind carbon copy锛�
+	 */
+	private String[] bccs;
+	/**
+	 * 鍥炲鍦板潃(reply-to)
+	 */
+	private String[] reply;
+	/**
+	 * 鏍囬
+	 */
+	private String title;
+	/**
+	 * 鍐呭
+	 */
+	private String content;
+	/**
+	 * 鏄惁涓篐TML
+	 */
+	private boolean isHtml;
+	/**
+	 * 姝f枃銆侀檮浠跺拰鍥剧墖鐨勬贩鍚堥儴鍒�
+	 */
+	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;
+	}
+
+	/**
+	 * 璁剧疆澶氫釜鎶勯�佷汉锛坈arbon copy锛�
+	 *
+	 * @param ccs 鎶勯�佷汉鍒楄〃
+	 * @return this
+	 * @since 4.0.3
+	 */
+	public Mail setCcs(String... ccs) {
+		this.ccs = ccs;
+		return this;
+	}
+
+	/**
+	 * 璁剧疆澶氫釜瀵嗛�佷汉锛坆lind 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;
+	}
+
+	/**
+	 * 璁剧疆姝f枃<br>
+	 * 姝f枃鍙互鏄櫘閫氭枃鏈篃鍙互鏄疕TML锛堥粯璁ゆ櫘閫氭枃鏈級锛屽彲浠ラ�氳繃璋冪敤{@link #setHtml(boolean)} 璁剧疆鏄惁涓篐TML
+	 *
+	 * @param content 姝f枃
+	 * @return this
+	 */
+	public Mail setContent(String content) {
+		this.content = content;
+		return this;
+	}
+
+	/**
+	 * 璁剧疆鏄惁鏄疕TML
+	 *
+	 * @param isHtml 鏄惁涓篐TML
+	 * @return this
+	 */
+	public Mail setHtml(boolean isHtml) {
+		this.isHtml = isHtml;
+		return this;
+	}
+
+	/**
+	 * 璁剧疆姝f枃
+	 *
+	 * @param content 姝f枃鍐呭
+	 * @param isHtml  鏄惁涓篐TML
+	 * @return this
+	 */
+	public Mail setContent(String content, boolean isHtml) {
+		setContent(content);
+		return setHtml(isHtml);
+	}
+
+	/**
+	 * 璁剧疆鏂囦欢绫诲瀷闄勪欢锛屾枃浠跺彲浠ユ槸鍥剧墖鏂囦欢锛屾鏃惰嚜鍔ㄨ缃甤id锛堟鏂囦腑寮曠敤鍥剧墖锛夛紝榛樿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 = 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         鍥剧墖涓庡崰浣嶇锛屽崰浣嶇鏍煎紡涓篶id:${cid}
+	 * @param imageStream 鍥剧墖鏂囦欢
+	 * @return this
+	 * @since 4.6.3
+	 */
+	public Mail addImage(String cid, InputStream imageStream) {
+		return addImage(cid, imageStream, null);
+	}
+
+	/**
+	 * 澧炲姞鍥剧墖锛屽浘鐗囩殑閿搴斿埌閭欢妯℃澘涓殑鍗犱綅瀛楃涓�
+	 *
+	 * @param cid         鍥剧墖涓庡崰浣嶇锛屽崰浣嶇鏍煎紡涓篶id:${cid}
+	 * @param imageStream 鍥剧墖娴侊紝涓嶅叧闂�
+	 * @param contentType 鍥剧墖绫诲瀷锛宯ull璧嬪�奸粯璁ょ殑"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       鍥剧墖涓庡崰浣嶇锛屽崰浣嶇鏍煎紡涓篶id:${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)) {
+			// 鐢ㄦ埛鏈彁渚涘彂閫佹柟锛屽垯浠嶴ession涓嚜鍔ㄨ幏鍙�
+			msg.setFrom();
+		} else {
+			msg.setFrom(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, InternalMailUtil.parseAddressFromStrs(this.tos, charset));
+		// 鎶勯�佷汉
+		if (ArrayUtil.isNotEmpty(this.ccs)) {
+			msg.setRecipients(MimeMessage.RecipientType.CC, InternalMailUtil.parseAddressFromStrs(this.ccs, charset));
+		}
+		// 瀵嗛�佷汉
+		if (ArrayUtil.isNotEmpty(this.bccs)) {
+			msg.setRecipients(MimeMessage.RecipientType.BCC, 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();
+		// 姝f枃
+		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
+}

--
Gitblit v1.9.3