mirror of
https://gitee.com/dromara/sms4j.git
synced 2025-12-06 17:08:40 +08:00
!125 add 新增sms4j-email-jakarta分支
* update 删除多余的内容 * add 新增sms4j-email-jakarta分支
This commit is contained in:
parent
135459c544
commit
a36cc7eeca
23
pom.xml
23
pom.xml
@ -22,6 +22,7 @@
|
||||
<module>sms4j-javase-plugin</module>
|
||||
<module>sms4j-Email-plugin</module>
|
||||
<module>sms4j-oa-plugin</module>
|
||||
<module>sms4j-email-jakarta</module>
|
||||
</modules>
|
||||
|
||||
<!-- 开源协议 Apache 2.0 -->
|
||||
@ -55,16 +56,15 @@
|
||||
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<spring.boot.version>2.7.15</spring.boot.version>
|
||||
<spring.boot.version>2.7.18</spring.boot.version>
|
||||
<solon.version>2.5.4</solon.version>
|
||||
<redisson.version>3.17.0</redisson.version>
|
||||
<jdcloud.version>1.3.3</jdcloud.version>
|
||||
<hutool.version>5.8.20</hutool.version>
|
||||
<hutool.version>5.8.24</hutool.version>
|
||||
<xmlblend.version>2.3.0</xmlblend.version>
|
||||
<activation.version>1.1.1</activation.version>
|
||||
<mail.version>1.6.2</mail.version>
|
||||
<sunactivation.version>1.2.0</sunactivation.version>
|
||||
<jakarta.activation.version>1.2.2</jakarta.activation.version>
|
||||
<snakeyaml.version>2.0</snakeyaml.version>
|
||||
</properties>
|
||||
|
||||
@ -77,6 +77,16 @@
|
||||
<version>${spring.boot.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>jakarta.activation</groupId>
|
||||
<artifactId>jakarta.activation-api</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>jakarta.mail</groupId>
|
||||
<artifactId>jakarta.mail-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@ -169,12 +179,6 @@
|
||||
<version>${sunactivation.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jakarta.activation</groupId>
|
||||
<artifactId>jakarta.activation-api</artifactId>
|
||||
<version>${jakarta.activation.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
@ -311,4 +315,5 @@
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
||||
@ -57,11 +57,6 @@
|
||||
<version>${sunactivation.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jakarta.activation</groupId>
|
||||
<artifactId>jakarta.activation-api</artifactId>
|
||||
<version>${jakarta.activation.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-cron</artifactId>
|
||||
|
||||
@ -13,10 +13,6 @@
|
||||
<name>sms4j-Email-core</name>
|
||||
<description>sms4j-Email-core</description>
|
||||
|
||||
<properties>
|
||||
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.dromara.sms4j</groupId>
|
||||
@ -27,13 +23,6 @@
|
||||
<groupId>com.sun.activation</groupId>
|
||||
<artifactId>javax.activation</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jakarta.activation</groupId>
|
||||
<artifactId>jakarta.activation-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
</project>
|
||||
|
||||
63
sms4j-email-jakarta/pom.xml
Normal file
63
sms4j-email-jakarta/pom.xml
Normal file
@ -0,0 +1,63 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.dromara.sms4j</groupId>
|
||||
<artifactId>sms4j</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<packaging>pom</packaging>
|
||||
<artifactId>sms4j-email-jakarta</artifactId>
|
||||
|
||||
<modules>
|
||||
<module>sms4j-email-jakarta-api</module>
|
||||
<module>sms4j-email-jakarta-comm</module>
|
||||
<module>sms4j-email-jakarta-core</module>
|
||||
</modules>
|
||||
|
||||
<name>sms4j-email-jakarta</name>
|
||||
<description>JDK 11 或更高版本中使用</description>
|
||||
|
||||
<properties>
|
||||
<jakarta-mail.version>2.1.2</jakarta-mail.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara.sms4j</groupId>
|
||||
<artifactId>sms4j-email-jakarta-api</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara.sms4j</groupId>
|
||||
<artifactId>sms4j-email-jakarta-comm</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara.sms4j</groupId>
|
||||
<artifactId>sms4j-email-jakarta-core</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jakarta.activation</groupId>
|
||||
<artifactId>jakarta.activation-api</artifactId>
|
||||
<version>${jakarta-mail.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jakarta.mail</groupId>
|
||||
<artifactId>jakarta.mail-api</artifactId>
|
||||
<version>${jakarta-mail.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
</project>
|
||||
23
sms4j-email-jakarta/sms4j-email-jakarta-api/pom.xml
Normal file
23
sms4j-email-jakarta/sms4j-email-jakarta-api/pom.xml
Normal file
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.dromara.sms4j</groupId>
|
||||
<artifactId>sms4j-email-jakarta</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>sms4j-email-jakarta-api</artifactId>
|
||||
<description>email-api</description>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara.sms4j</groupId>
|
||||
<artifactId>sms4j-email-jakarta-comm</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@ -0,0 +1,14 @@
|
||||
package org.dromara.email.jakarta.api;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Blacklist
|
||||
* <p> 黑名单实现 实现此接口,发送邮件时将自动排除调黑名单中的收件人
|
||||
* @author :Wind
|
||||
* 2023/6/8 23:05
|
||||
**/
|
||||
public interface Blacklist {
|
||||
|
||||
List<String> getBlacklist();
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package org.dromara.email.jakarta.api;
|
||||
|
||||
import org.dromara.email.jakarta.comm.entity.MailMessage;
|
||||
|
||||
public interface MailClient {
|
||||
|
||||
/**
|
||||
* 发送邮件,可以通过对象构造群体发送或者单体发送,取决于添加进去的收件人,同时可以添加
|
||||
* 密送人,抄送人,附件等参数
|
||||
* @param mailMessage 发送邮件参数对象
|
||||
* @author :Wind
|
||||
*/
|
||||
void send(MailMessage mailMessage);
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
package org.dromara.email.jakarta.api;
|
||||
|
||||
import org.dromara.email.jakarta.comm.entity.MonitorMessage;
|
||||
|
||||
/**
|
||||
* Monitor
|
||||
* <p> 监听接口,实现此接口用于监听并获取邮件消息
|
||||
* @author :Wind
|
||||
* 2023/7/18 15:57
|
||||
**/
|
||||
public interface Monitor {
|
||||
|
||||
/**
|
||||
* monitor
|
||||
* <p> 监听系统的邮件消息,
|
||||
* @param monitorMessage 系统监听到的消息内容
|
||||
* @return true为标记已读,否则不标记
|
||||
* @author :Wind
|
||||
*/
|
||||
boolean monitor(MonitorMessage monitorMessage);
|
||||
}
|
||||
33
sms4j-email-jakarta/sms4j-email-jakarta-comm/pom.xml
Normal file
33
sms4j-email-jakarta/sms4j-email-jakarta-comm/pom.xml
Normal file
@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.dromara.sms4j</groupId>
|
||||
<artifactId>sms4j-email-jakarta</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>sms4j-email-jakarta-comm</artifactId>
|
||||
<description>email通用配置</description>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-cron</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-http</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jakarta.mail</groupId>
|
||||
<artifactId>jakarta.mail-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@ -0,0 +1,19 @@
|
||||
package org.dromara.email.jakarta.comm.config;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class MailImapConfig {
|
||||
|
||||
/** imap服务地址*/
|
||||
private String imapServer;
|
||||
|
||||
/** 要监听的邮箱账号*/
|
||||
private String username;
|
||||
|
||||
/** 要监听的邮箱授权码或密码*/
|
||||
private String accessToken;
|
||||
|
||||
/** 监听周期(秒)*/
|
||||
private Integer cycle = 5;
|
||||
}
|
||||
@ -0,0 +1,67 @@
|
||||
package org.dromara.email.jakarta.comm.config;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* MailSmtpConfig
|
||||
* <p> smtp协议配置文件
|
||||
* @author :Wind
|
||||
* 2023/6/7 21:19
|
||||
**/
|
||||
@Builder
|
||||
@ToString
|
||||
@Getter
|
||||
@EqualsAndHashCode
|
||||
public class MailSmtpConfig {
|
||||
/**
|
||||
* 端口号
|
||||
* */
|
||||
private String port;
|
||||
|
||||
/**
|
||||
* 发件人地址
|
||||
* */
|
||||
private String fromAddress;
|
||||
|
||||
/**
|
||||
* 服务器地址
|
||||
* */
|
||||
private String smtpServer;
|
||||
|
||||
/**
|
||||
* 账号
|
||||
* */
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 密码
|
||||
* */
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* 是否开启ssl 默认开启
|
||||
* */
|
||||
@Builder.Default
|
||||
private String isSSL = "true";
|
||||
|
||||
/**
|
||||
* 是否开启验证 默认开启
|
||||
* */
|
||||
@Builder.Default
|
||||
private String isAuth = "true";
|
||||
|
||||
/**
|
||||
* 重试间隔(单位:秒),默认为5秒
|
||||
*/
|
||||
@Builder.Default
|
||||
private int retryInterval = 5;
|
||||
|
||||
/**
|
||||
* 重试次数,默认为1次
|
||||
*/
|
||||
@Builder.Default
|
||||
private int maxRetries = 1;
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
package org.dromara.email.jakarta.comm.constants;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class FileConstants {
|
||||
public static final String IO_FILE_TYPE = "application/octet-stream";
|
||||
}
|
||||
@ -0,0 +1,178 @@
|
||||
package org.dromara.email.jakarta.comm.entity;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.dromara.email.jakarta.comm.utils.ReflectUtil;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Getter
|
||||
public class MailMessage {
|
||||
|
||||
/** 收件人地址*/
|
||||
private List<String> mailAddress;
|
||||
|
||||
/** 邮件主题*/
|
||||
private String title;
|
||||
|
||||
/** 文字正文*/
|
||||
private String body;
|
||||
|
||||
/** html模板文件路径(resources目录下的路径)*/
|
||||
private String htmlPath;
|
||||
|
||||
/** html模板文件的输入流,可来自任意可读取位置*/
|
||||
private InputStream htmlInputStream;
|
||||
|
||||
/** html 模板参数*/
|
||||
private Map<String,String> htmlValues;
|
||||
|
||||
/** 抄送人*/
|
||||
private List<String> cc;
|
||||
|
||||
/** 密送人*/
|
||||
private List<String> bcc;
|
||||
|
||||
/** 附件*/
|
||||
private Map<String,String> files;
|
||||
|
||||
/** 压缩文件名称*/
|
||||
private String zipName;
|
||||
|
||||
public static MailsBuilder Builder(){
|
||||
return new MailsBuilder();
|
||||
}
|
||||
|
||||
public static class MailsBuilder{
|
||||
private final MailMessage mailMessage = new MailMessage();
|
||||
public MailsBuilder() {
|
||||
}
|
||||
public MailMessage build(){
|
||||
return mailMessage;
|
||||
}
|
||||
|
||||
/** 收件人地址*/
|
||||
public MailsBuilder mailAddress(List<String> mailAddress) {
|
||||
mailMessage.mailAddress = mailAddress;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** 收件人地址*/
|
||||
public MailsBuilder mailAddress(String mailAddress){
|
||||
if ( mailMessage.mailAddress == null){
|
||||
mailMessage.mailAddress = new ArrayList<>();
|
||||
}
|
||||
mailMessage.mailAddress.add(mailAddress);
|
||||
return this;
|
||||
}
|
||||
|
||||
/** 邮件主题*/
|
||||
public MailsBuilder title(String title){
|
||||
mailMessage.title = title;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** 文字正文*/
|
||||
public MailsBuilder body(String body){
|
||||
mailMessage.body = body;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** 抄送人*/
|
||||
public MailsBuilder cc(List<String> cc){
|
||||
mailMessage.cc = cc;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** 抄送人*/
|
||||
public MailsBuilder cc(String cc){
|
||||
if (mailMessage.cc == null){
|
||||
mailMessage.cc = new ArrayList<>();
|
||||
}
|
||||
mailMessage.cc.add(cc);
|
||||
return this;
|
||||
}
|
||||
|
||||
/** 密送人*/
|
||||
public MailsBuilder bcc(List<String> bcc){
|
||||
mailMessage.bcc = bcc;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** 密送人*/
|
||||
public MailsBuilder bcc(String bcc){
|
||||
if (mailMessage.bcc == null){
|
||||
mailMessage.bcc = new ArrayList<>();
|
||||
}
|
||||
mailMessage.bcc.add(bcc);
|
||||
return this;
|
||||
}
|
||||
|
||||
/** 附件*/
|
||||
public MailsBuilder files(Map<String, String> files){
|
||||
if (mailMessage.files == null){
|
||||
mailMessage.files = new HashMap<>();
|
||||
}
|
||||
mailMessage.files.putAll(files);
|
||||
return this;
|
||||
}
|
||||
|
||||
/** 附件*/
|
||||
public MailsBuilder files(String fileName,String filePath){
|
||||
if (mailMessage.files == null){
|
||||
mailMessage.files = new HashMap<>();
|
||||
}
|
||||
mailMessage.files.put(fileName,filePath);
|
||||
return this;
|
||||
}
|
||||
|
||||
/** html模板文件路径(resources目录下的路径)*/
|
||||
public MailsBuilder html(String htmlPath){
|
||||
mailMessage.htmlPath = htmlPath;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** html模板文件的输入流,可来自任意可读取位置*/
|
||||
public MailsBuilder html(InputStream htmlInputStream){
|
||||
mailMessage.htmlInputStream = htmlInputStream;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** html 模板参数*/
|
||||
public MailsBuilder htmlValues(String key, String value){
|
||||
if (mailMessage.htmlValues == null){
|
||||
mailMessage.htmlValues = new HashMap<>();
|
||||
}
|
||||
mailMessage.htmlValues.put(key,value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/** html 模板参数*/
|
||||
public MailsBuilder htmlValues(Map<String,String> htmlValues){
|
||||
if (mailMessage.htmlValues == null){
|
||||
mailMessage.htmlValues = new HashMap<>();
|
||||
}
|
||||
mailMessage.htmlValues.putAll(htmlValues);
|
||||
return this;
|
||||
}
|
||||
|
||||
/** html 模板参数*/
|
||||
public MailsBuilder htmlValues(Parameter parameter){
|
||||
Map<String, String> values = ReflectUtil.getValues(parameter);
|
||||
if (mailMessage.htmlValues == null){
|
||||
mailMessage.htmlValues = new HashMap<>();
|
||||
}
|
||||
mailMessage.htmlValues.putAll(values);
|
||||
return this;
|
||||
}
|
||||
|
||||
/** 压缩文件名称*/
|
||||
public MailsBuilder zipName(String zipName){
|
||||
mailMessage.zipName = zipName;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
package org.dromara.email.jakarta.comm.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import jakarta.mail.Multipart;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* MonitorMessage
|
||||
* <p> 监听获取到的邮件内容
|
||||
* @author :Wind
|
||||
* 2023/7/18 15:59
|
||||
**/
|
||||
@Data
|
||||
public class MonitorMessage {
|
||||
|
||||
/** 邮件主题*/
|
||||
private String title;
|
||||
|
||||
/** 邮件文字内容*/
|
||||
private String text;
|
||||
|
||||
/** 解析的html内容*/
|
||||
private String htmlText;
|
||||
|
||||
/** 邮件发送时间*/
|
||||
private Date sendDate;
|
||||
|
||||
/** 邮件内容(复杂内容)*/
|
||||
private Multipart body;
|
||||
|
||||
/** 发送人*/
|
||||
private String fromAddress;
|
||||
|
||||
/** 邮件消息编号*/
|
||||
private Integer messageIndex;
|
||||
|
||||
/** 接收时间*/
|
||||
private Long acceptTime;
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
package org.dromara.email.jakarta.comm.entity;
|
||||
|
||||
/**
|
||||
* Parameter
|
||||
* <p> 空接口,用于标定用户自己的实体类型
|
||||
* 用于发送html模板邮件时候 用户传递自己的实体序列化进行的类型标定
|
||||
* @author :Wind
|
||||
* 2023/6/8 19:36
|
||||
**/
|
||||
public interface Parameter {
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
package org.dromara.email.jakarta.comm.errors;
|
||||
|
||||
public class MailException extends RuntimeException {
|
||||
public MailException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public MailException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public MailException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public MailException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
protected MailException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
package org.dromara.email.jakarta.comm.utils;
|
||||
|
||||
public class BaseUtil {
|
||||
|
||||
/**
|
||||
* getPathName
|
||||
* <p>分隔文件路径,并获取文件名
|
||||
* @param path 文件路径
|
||||
* @author :Wind
|
||||
*/
|
||||
public static String getPathName(String path) {
|
||||
String[] split = path.split("/");
|
||||
return split[split.length - 1];
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,130 @@
|
||||
package org.dromara.email.jakarta.comm.utils;
|
||||
|
||||
import org.dromara.email.jakarta.comm.errors.MailException;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* HtmlUtil
|
||||
* <p> Html相关工具
|
||||
*
|
||||
* @author :Wind
|
||||
* 2023/6/7 20:15
|
||||
**/
|
||||
public final class HtmlUtil {
|
||||
|
||||
private static final HtmlUtil htmlUtil = new HtmlUtil();
|
||||
|
||||
private HtmlUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* readHtml
|
||||
* <p>从resource读取模板文件
|
||||
*
|
||||
* @param name 模板文件名
|
||||
* @author :Wind
|
||||
*/
|
||||
public static List<String> readHtml(String name) throws MailException {
|
||||
try (InputStream is = HtmlUtil.class.getResourceAsStream("/template/" + name)) {
|
||||
return readHtml(is);
|
||||
} catch (IOException e) {
|
||||
throw new MailException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* readHtml
|
||||
* <p>从自定义路径读取模板文件
|
||||
*
|
||||
* @param file 自定义路径file
|
||||
* @author :Wind
|
||||
*/
|
||||
public static List<String> readHtml(File file) throws MailException {
|
||||
try (InputStream ip = Files.newInputStream(file.toPath())) {
|
||||
return readHtml(ip);
|
||||
} catch (IOException e) {
|
||||
throw new MailException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* readHtml
|
||||
* <p>从输入流读取模板文件
|
||||
*
|
||||
* @param inputStream 输入流
|
||||
* @author :Wind
|
||||
*/
|
||||
public static List<String> readHtml(InputStream inputStream) throws MailException {
|
||||
List<String> data = new ArrayList<>();
|
||||
if (Objects.isNull(inputStream)) {
|
||||
throw new MailException("The template could not be found!");
|
||||
}
|
||||
try (BufferedReader br = new BufferedReader(new InputStreamReader(inputStream))) {
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
data.add(line);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new MailException(e);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* replacePlaceholder
|
||||
* <p>将所包含占位符的字符串替换为固定值
|
||||
*
|
||||
* @param data 源数据
|
||||
* @param parameter key为占位符名称 value为占位符应替换的值
|
||||
* @author :Wind
|
||||
*/
|
||||
public static List<String> replacePlaceholder(List<String> data, Map<String, String> parameter) {
|
||||
for (int i = 0; i < data.size(); i++) {
|
||||
for (Map.Entry<String, String> s : parameter.entrySet()) {
|
||||
String piece = piece(s.getKey());
|
||||
if (data.get(i).contains(piece)){
|
||||
String replace = data.get(i).replace(piece, s.getValue());
|
||||
data.set(i,replace);
|
||||
}
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* pieceHtml
|
||||
* <p>将数据拼合为html
|
||||
*
|
||||
* @param data 需要拼合的数据
|
||||
* @author :Wind
|
||||
*/
|
||||
public static String pieceHtml(List<String> data) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String datum : data) {
|
||||
sb.append(datum);
|
||||
sb.append("\r\n");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* piece
|
||||
* <p>将参数拼合为完整占位符
|
||||
*
|
||||
* @author :Wind
|
||||
*/
|
||||
public static String piece(String parameter) {
|
||||
return "#{" + parameter + "}";
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package org.dromara.email.jakarta.comm.utils;
|
||||
|
||||
import org.dromara.email.jakarta.comm.entity.Parameter;
|
||||
import org.dromara.email.jakarta.comm.errors.MailException;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class ReflectUtil {
|
||||
|
||||
/**
|
||||
* 反射获取接口对象的原类名
|
||||
*/
|
||||
public static String getObjectName(Parameter parameter) {
|
||||
return parameter.getClass().getTypeName();
|
||||
}
|
||||
|
||||
/**
|
||||
* 将对象的属性和属性值变为map
|
||||
* */
|
||||
public static Map<String, String> getValues(Parameter parameter) {
|
||||
try {
|
||||
Map<String ,String> map = new HashMap<>();
|
||||
Class<?> clazz = Class.forName(getObjectName(parameter));
|
||||
Field[] declaredFields = clazz.getDeclaredFields();
|
||||
for (Field declaredField : declaredFields) {
|
||||
declaredField.setAccessible(true);
|
||||
map.put(declaredField.getName(), (String) declaredField.get(parameter));
|
||||
}
|
||||
return map;
|
||||
} catch (Exception e) {
|
||||
throw new MailException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,111 @@
|
||||
package org.dromara.email.jakarta.comm.utils;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.core.util.ZipUtil;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.channels.Pipe;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
/**
|
||||
* 压缩包处理类
|
||||
*
|
||||
* @author Bleachtred
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class ZipUtils extends ZipUtil {
|
||||
private final static Integer TEMP_SIZE = 2048;
|
||||
|
||||
/**
|
||||
* 压缩方法(支持 本地文件/目录 + oss网络路径 混合)
|
||||
* @param files 文件列表
|
||||
* @author Bleachtred
|
||||
*/
|
||||
public static void zipFilePip(Map<String, String> files, OutputStream outputStream) {
|
||||
try(WritableByteChannel out = Channels.newChannel(outputStream)) {
|
||||
Pipe pipe = Pipe.open();
|
||||
//异步任务
|
||||
CompletableFuture.runAsync(() -> runTask(pipe, files));
|
||||
//获取读通道
|
||||
try (ReadableByteChannel readableByteChannel = pipe.source()) {
|
||||
ByteBuffer buffer = ByteBuffer.allocate(TEMP_SIZE);
|
||||
while (readableByteChannel.read(buffer) >= 0) {
|
||||
buffer.flip();
|
||||
out.write(buffer);
|
||||
buffer.clear();
|
||||
}
|
||||
}
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static void runTask(Pipe pipe, Map<String, String> files) {
|
||||
try(ZipOutputStream zos = new ZipOutputStream(Channels.newOutputStream(pipe.sink()));
|
||||
WritableByteChannel out = Channels.newChannel(zos)) {
|
||||
for (Map.Entry<String, String> entry : files.entrySet()) {
|
||||
taskFunction(zos, out, entry.getKey(), entry.getValue());
|
||||
}
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 打包文件
|
||||
* @param zos 压缩包输出
|
||||
* @param out 缓冲区通道
|
||||
* @param fileName 文件名称
|
||||
* @param file 文件
|
||||
* @throws IOException IOException
|
||||
*/
|
||||
private static void taskFunction(ZipOutputStream zos, WritableByteChannel out, String fileName, File file) throws IOException {
|
||||
// 是否为目录
|
||||
if (file.isDirectory()) {
|
||||
File[] files = file.listFiles();
|
||||
fileName = StrUtil.isEmpty(fileName) ? file.getName() + "/" : fileName + "/";
|
||||
if (files == null || files.length == 0){
|
||||
return;
|
||||
}
|
||||
for (File child : files) {
|
||||
taskFunction(zos, out, fileName + child.getName(), child);
|
||||
}
|
||||
} else {
|
||||
fileName = StrUtil.isEmpty(fileName) ? file.getName() : fileName;
|
||||
zos.putNextEntry(new ZipEntry(fileName));
|
||||
try(FileInputStream fis = new FileInputStream(file.getAbsolutePath())){
|
||||
FileChannel fileChannel = fis.getChannel();
|
||||
fileChannel.transferTo(0, fileChannel.size(), out);
|
||||
fileChannel.close();
|
||||
}catch (IOException e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void taskFunction(ZipOutputStream zos, WritableByteChannel out, String fileName, String file) throws IOException {
|
||||
// 网络文件
|
||||
if (file.startsWith("http")) {
|
||||
zos.putNextEntry(new ZipEntry(fileName));
|
||||
byte[] bytes = HttpUtil.downloadBytes(file);
|
||||
out.write(ByteBuffer.wrap(bytes));
|
||||
}else {
|
||||
taskFunction(zos, out, fileName, new File(file));
|
||||
}
|
||||
}
|
||||
}
|
||||
27
sms4j-email-jakarta/sms4j-email-jakarta-core/pom.xml
Normal file
27
sms4j-email-jakarta/sms4j-email-jakarta-core/pom.xml
Normal file
@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.dromara.sms4j</groupId>
|
||||
<artifactId>sms4j-email-jakarta</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>sms4j-email-jakarta-core</artifactId>
|
||||
<description>email依赖引入包</description>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara.sms4j</groupId>
|
||||
<artifactId>sms4j-email-jakarta-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jakarta.activation</groupId>
|
||||
<artifactId>jakarta.activation-api</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@ -0,0 +1,63 @@
|
||||
package org.dromara.email.jakarta.core.factory;
|
||||
|
||||
import org.dromara.email.jakarta.api.Blacklist;
|
||||
import org.dromara.email.jakarta.api.MailClient;
|
||||
import org.dromara.email.jakarta.comm.config.MailSmtpConfig;
|
||||
import org.dromara.email.jakarta.comm.errors.MailException;
|
||||
import org.dromara.email.jakarta.core.service.MailBuild;
|
||||
|
||||
import jakarta.mail.MessagingException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* MailFactory
|
||||
* <p> 配置工厂
|
||||
* @author :Wind
|
||||
* 2023/6/8 22:35
|
||||
**/
|
||||
public class MailFactory{
|
||||
private static final Map<Object,MailSmtpConfig> configs = new HashMap<>();
|
||||
|
||||
/**
|
||||
* createMailClient
|
||||
* <p>从工厂获取一个邮件发送实例
|
||||
* @param key 配置的标识key
|
||||
* @author :Wind
|
||||
*/
|
||||
public static MailClient createMailClient(Object key){
|
||||
try {
|
||||
return MailBuild.build(configs.get(key));
|
||||
} catch (MessagingException e) {
|
||||
throw new MailException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* createMailClient
|
||||
* <p>从工厂获取一个邮件发送实例,该实例发送短信将依照黑名单中的数据进行过滤
|
||||
* @param key 配置的标识key
|
||||
* @param blacklist 黑名单接口,实例将从这里获取黑名单数据
|
||||
* @author :Wind
|
||||
*/
|
||||
public static MailClient createMailClient(Object key, Blacklist blacklist){
|
||||
try {
|
||||
return MailBuild.build(configs.get(key),blacklist);
|
||||
} catch (MessagingException e) {
|
||||
throw new MailException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set
|
||||
* <p>将一个配置对象交给工厂
|
||||
* @param key 标识
|
||||
* @param config 配置对象
|
||||
* @author :Wind
|
||||
*/
|
||||
public static void put(Object key, MailSmtpConfig config){
|
||||
configs.put(key,config);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,65 @@
|
||||
package org.dromara.email.jakarta.core.factory;
|
||||
|
||||
import org.dromara.email.jakarta.api.Monitor;
|
||||
import org.dromara.email.jakarta.comm.config.MailImapConfig;
|
||||
import org.dromara.email.jakarta.core.service.MonitorService;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* MonitorFactory
|
||||
* <p> 监听系统工厂,通过向工厂添加配置,可以启动或关闭监听
|
||||
* 监听器通过连接指定的imap服务器监听指定的邮箱,并以异步轮询的形式进行消息的监听,除去轮询时间开销外,个别imap服务器本身存在延迟,故而邮件的监听可能存在较大延迟,
|
||||
* 在配置中可以设置轮询的间隔时间,以增大或缩小监听灵敏度。灵敏度调节周期为秒级,默认周期为5秒。
|
||||
* <p>需要注意的是,监听器所使用的线程并非任何线程池中的线程,如想停止某邮箱的监听,只需要调用stop方法即可,他会在完成当前接收的任务后正常的终结线程。
|
||||
* 现成终结后可以通过调用start方法重新启用。
|
||||
* @author :Wind
|
||||
* 2023/7/18 17:06
|
||||
**/
|
||||
public class MonitorFactory {
|
||||
|
||||
private final static Map<String, MonitorService> services = new HashMap<>();
|
||||
|
||||
/**
|
||||
* put
|
||||
* <p> 添加一个配置至系统中,并绑定接收消息的对象
|
||||
* @param key 监听标识
|
||||
* @param config 监听配置
|
||||
* @param monitor 回调对象
|
||||
* @author :Wind
|
||||
*/
|
||||
public static void put(String key, MailImapConfig config, Monitor monitor){
|
||||
services.put(key,new MonitorService(config,monitor));
|
||||
}
|
||||
|
||||
/**
|
||||
* start
|
||||
* <p> 开始监听指定标识的邮箱
|
||||
* @param key 标识
|
||||
* @author :Wind
|
||||
*/
|
||||
public static void start(String key){
|
||||
services.get(key).start();
|
||||
}
|
||||
|
||||
/**
|
||||
* stop
|
||||
* <p> 停止监听指定标识的邮箱
|
||||
* @param key 标识
|
||||
* @author :Wind
|
||||
*/
|
||||
public static void stop(String key){
|
||||
services.get(key).stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* getConfig
|
||||
* <p> 获取指定标识的配置信息
|
||||
* @param key 标识
|
||||
* @author :Wind
|
||||
*/
|
||||
public static MailImapConfig getConfig(String key) {
|
||||
return services.get(key).getMailImapConfig();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
/**
|
||||
* <p> 邮件插件核心模块
|
||||
* @author :Wind
|
||||
* 2023/7/27 10:58
|
||||
**/
|
||||
package org.dromara.email.jakarta.core;
|
||||
@ -0,0 +1,107 @@
|
||||
package org.dromara.email.jakarta.core.service;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import lombok.Data;
|
||||
import org.dromara.email.jakarta.api.Blacklist;
|
||||
import org.dromara.email.jakarta.api.MailClient;
|
||||
import org.dromara.email.jakarta.comm.config.MailSmtpConfig;
|
||||
import org.dromara.email.jakarta.comm.errors.MailException;
|
||||
|
||||
import jakarta.mail.Authenticator;
|
||||
import jakarta.mail.Message;
|
||||
import jakarta.mail.MessagingException;
|
||||
import jakarta.mail.PasswordAuthentication;
|
||||
import jakarta.mail.Session;
|
||||
import jakarta.mail.internet.AddressException;
|
||||
import jakarta.mail.internet.InternetAddress;
|
||||
import jakarta.mail.internet.MimeMessage;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Properties;
|
||||
|
||||
@Data
|
||||
public class MailBuild {
|
||||
|
||||
private Message message;
|
||||
|
||||
private Session session;
|
||||
|
||||
private MailSmtpConfig config;
|
||||
|
||||
private Blacklist blacklist;
|
||||
|
||||
private int retryInterval;
|
||||
|
||||
private int maxRetries;
|
||||
|
||||
private MailBuild(MailSmtpConfig config) throws MessagingException {
|
||||
Properties props = new Properties();
|
||||
props.put("mail.smtp.host", config.getSmtpServer());
|
||||
props.put("mail.smtp.auth", config.getIsAuth());
|
||||
props.put("mail.smtp.port", config.getPort());
|
||||
props.put("mail.smtp.ssl.enable", config.getIsSSL());
|
||||
// props.put("mail.smtp.ssl.socketFactory", new MailSSLSocketFactory());
|
||||
this.session = Session.getInstance(props, new Authenticator() {
|
||||
protected PasswordAuthentication getPasswordAuthentication() {
|
||||
return new PasswordAuthentication(config.getUsername(), config.getPassword());
|
||||
}
|
||||
});
|
||||
this.message = new MimeMessage(session);
|
||||
this.message.setFrom(new InternetAddress(config.getFromAddress()));
|
||||
this.config = config;
|
||||
this.retryInterval = config.getRetryInterval();
|
||||
this.maxRetries = config.getMaxRetries();
|
||||
}
|
||||
|
||||
private MailBuild(MailSmtpConfig config,Blacklist blacklist)throws MessagingException{
|
||||
Properties props = new Properties();
|
||||
props.put("mail.smtp.host", config.getSmtpServer());
|
||||
props.put("mail.smtp.auth", config.getIsAuth());
|
||||
props.put("mail.smtp.port", config.getPort());
|
||||
props.put("mail.smtp.ssl.enable", config.getIsSSL());
|
||||
// props.put("mail.smtp.ssl.socketFactory", new MailSSLSocketFactory());
|
||||
this.session = Session.getInstance(props,
|
||||
new Authenticator() {
|
||||
protected PasswordAuthentication getPasswordAuthentication() {
|
||||
return new PasswordAuthentication(config.getUsername(), config.getPassword());
|
||||
}
|
||||
});
|
||||
this.message = new MimeMessage(session);
|
||||
this.message.setFrom(new InternetAddress(config.getFromAddress()));
|
||||
this.config = config;
|
||||
this.blacklist = blacklist;
|
||||
this.retryInterval = config.getRetryInterval();
|
||||
this.maxRetries = config.getMaxRetries();
|
||||
}
|
||||
|
||||
public static MailClient build(MailSmtpConfig config) throws MessagingException {
|
||||
return MailService.instance(new MailBuild(config));
|
||||
}
|
||||
public static MailClient build(MailSmtpConfig config,Blacklist blacklist)throws MessagingException {
|
||||
return MailService.instance(new MailBuild(config,blacklist));
|
||||
}
|
||||
|
||||
/**
|
||||
* eliminate
|
||||
* <p>过滤黑名单内容
|
||||
* @param source 需要过滤的源数据
|
||||
* @author :Wind
|
||||
*/
|
||||
public InternetAddress[] eliminate(List<String> source) {
|
||||
List<String> list = new ArrayList<>();
|
||||
try {
|
||||
if (Objects.isNull(blacklist)) {
|
||||
return InternetAddress.parse(Objects.requireNonNull(CollUtil.join(source, ",")));
|
||||
}
|
||||
for (String s : blacklist.getBlacklist()) {
|
||||
if (!source.contains(s)) {
|
||||
list.add(s);
|
||||
}
|
||||
}
|
||||
return InternetAddress.parse(CollUtil.join(list, ","));
|
||||
} catch (AddressException e) {
|
||||
throw new MailException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,227 @@
|
||||
package org.dromara.email.jakarta.core.service;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.lang.UUID;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import jakarta.mail.util.ByteArrayDataSource;
|
||||
import org.dromara.email.jakarta.api.MailClient;
|
||||
import org.dromara.email.jakarta.comm.constants.FileConstants;
|
||||
import org.dromara.email.jakarta.comm.entity.MailMessage;
|
||||
import org.dromara.email.jakarta.comm.errors.MailException;
|
||||
import org.dromara.email.jakarta.comm.utils.HtmlUtil;
|
||||
import org.dromara.email.jakarta.comm.utils.ZipUtils;
|
||||
|
||||
import jakarta.activation.DataHandler;
|
||||
import jakarta.activation.DataSource;
|
||||
import jakarta.activation.FileDataSource;
|
||||
import jakarta.mail.Message;
|
||||
import jakarta.mail.MessagingException;
|
||||
import jakarta.mail.Multipart;
|
||||
import jakarta.mail.Transport;
|
||||
import jakarta.mail.internet.MimeBodyPart;
|
||||
import jakarta.mail.internet.MimeMultipart;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class MailService implements MailClient {
|
||||
|
||||
private static Logger logger = Logger.getLogger("mailLog");
|
||||
private MailBuild mailBuild;
|
||||
|
||||
private MailService(MailBuild mailBuild) {
|
||||
this.mailBuild = mailBuild;
|
||||
}
|
||||
|
||||
public static MailClient instance(MailBuild mailBuild) {
|
||||
return new MailService(mailBuild);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(MailMessage mailMessage) {
|
||||
List<String> html = null;
|
||||
if (mailMessage.getHtmlInputStream() != null) {
|
||||
html = HtmlUtil.readHtml(mailMessage.getHtmlInputStream());
|
||||
}
|
||||
if (StrUtil.isNotBlank(mailMessage.getHtmlPath())){
|
||||
html = HtmlUtil.readHtml(mailMessage.getHtmlPath());
|
||||
}
|
||||
send(mailMessage.getMailAddress(),
|
||||
mailMessage.getTitle(),
|
||||
mailMessage.getBody(),
|
||||
html,
|
||||
mailMessage.getHtmlValues(),
|
||||
mailMessage.getZipName(),
|
||||
mailMessage.getFiles(),
|
||||
mailMessage.getCc(),
|
||||
mailMessage.getBcc()
|
||||
);
|
||||
}
|
||||
|
||||
private void forFiles(Multipart multipart, Map<String, String> files) throws MessagingException {
|
||||
for (Map.Entry<String, String> entry : files.entrySet()) {
|
||||
String k = entry.getKey();
|
||||
String v = entry.getValue();
|
||||
// 设置附件消息部分
|
||||
MimeBodyPart messageBodyPart = new MimeBodyPart();
|
||||
DataSource source;
|
||||
if (v.startsWith("http")) {
|
||||
byte[] bytes = HttpUtil.downloadBytes(v);
|
||||
source = new ByteArrayDataSource(bytes, FileConstants.IO_FILE_TYPE);
|
||||
} else {
|
||||
source = new FileDataSource(v);
|
||||
}
|
||||
messageBodyPart.setDataHandler(new DataHandler(source));
|
||||
messageBodyPart.setFileName(k);
|
||||
multipart.addBodyPart(messageBodyPart);
|
||||
}
|
||||
}
|
||||
|
||||
private void zipFiles(Multipart multipart, String zipName, Map<String, String> files) throws MessagingException, IOException {
|
||||
// 设置附件消息部分
|
||||
MimeBodyPart messageBodyPart = new MimeBodyPart();
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
ZipUtils.zipFilePip(files, os);
|
||||
ByteArrayInputStream stream = IoUtil.toStream(os);
|
||||
DataSource source = new ByteArrayDataSource(stream, FileConstants.IO_FILE_TYPE);
|
||||
messageBodyPart.setDataHandler(new DataHandler(source));
|
||||
messageBodyPart.setFileName(StrUtil.isNotBlank(zipName) ? zipName : UUID.fastUUID() + ".zip");
|
||||
multipart.addBodyPart(messageBodyPart);
|
||||
}
|
||||
|
||||
private void send(List<String> mailAddress,
|
||||
String title,
|
||||
String body,
|
||||
List<String> html,
|
||||
Map<String, String> parameter,
|
||||
String zipName,
|
||||
Map<String, String> files,
|
||||
List<String> cc,
|
||||
List<String> bcc) {
|
||||
try {
|
||||
Message message = messageBuild(mailAddress, title, body, html, parameter, zipName, cc, bcc, files);
|
||||
Transport.send(message);
|
||||
logger.info("邮件发送成功!^_^");
|
||||
} catch (MessagingException | IOException e) {
|
||||
// 防止 maxRetries 数值小于0带来的其他问题
|
||||
if (mailBuild.getMaxRetries() > 0) {
|
||||
ReSendList(mailAddress, title, body, html, parameter, zipName, files, cc, bcc);
|
||||
} else {
|
||||
logger.warning(e.getMessage());
|
||||
throw new MailException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ReSendList(List<String> mailAddress,
|
||||
String title,
|
||||
String body,
|
||||
List<String> html,
|
||||
Map<String, String> parameter,
|
||||
String zipName,
|
||||
Map<String, String> files,
|
||||
List<String> cc,
|
||||
List<String> bcc) {
|
||||
int maxRetries = mailBuild.getMaxRetries();
|
||||
int retryCount = 1; // 初始值为1;则while循环中少发送一次,最后一次发送在判断 retryCount >= maxRetries 这里。
|
||||
boolean retryOnFailure = true;
|
||||
|
||||
while (retryOnFailure && retryCount < maxRetries) {
|
||||
try {
|
||||
logger.warning("邮件第 {" + retryCount + "} 次重新发送");
|
||||
Message message;
|
||||
if (html != null || parameter != null) {
|
||||
message = messageBuild(mailAddress, title, body, html, parameter, zipName, cc, bcc, files);
|
||||
} else {
|
||||
message = messageBuild(mailAddress, title, body, null, null, zipName, cc, bcc, files);
|
||||
}
|
||||
Transport.send(message);
|
||||
retryOnFailure = false; // 发送成功,停止重试
|
||||
} catch (MessagingException | IOException e) {
|
||||
retryCount++;
|
||||
try {
|
||||
// 间隔秒数
|
||||
TimeUnit.SECONDS.sleep(mailBuild.getRetryInterval());
|
||||
} catch (InterruptedException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (retryCount >= maxRetries) {
|
||||
try {
|
||||
Message message;
|
||||
if (html != null || parameter != null) {
|
||||
message = messageBuild(mailAddress, title, body, html, parameter, null, cc, bcc, files);
|
||||
} else {
|
||||
message = messageBuild(mailAddress, title, body, null, null, null, cc, bcc, files);
|
||||
}
|
||||
Transport.send(message);
|
||||
} catch (MessagingException | IOException e) {
|
||||
throw new MailException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Message messageBuild(List<String> mailAddress,
|
||||
String title,
|
||||
String body,
|
||||
List<String> html,
|
||||
Map<String, String> parameter,
|
||||
String zipName,
|
||||
List<String> cc,
|
||||
List<String> bcc,
|
||||
Map<String, String> files) throws MessagingException, IOException {
|
||||
Message message = mailBuild.getMessage();
|
||||
message.setRecipients(Message.RecipientType.TO, mailBuild.eliminate(mailAddress));
|
||||
message.setSubject(title);
|
||||
|
||||
Multipart multipart = new MimeMultipart("alternative");
|
||||
if (CollUtil.isNotEmpty(html) && MapUtil.isNotEmpty(parameter)) {
|
||||
//读取模板并进行变量替换
|
||||
List<String> strings = HtmlUtil.replacePlaceholder(html, parameter);
|
||||
//拼合HTML数据
|
||||
String htmlData = HtmlUtil.pieceHtml(strings);
|
||||
MimeBodyPart htmlPart = new MimeBodyPart();
|
||||
htmlPart.setContent(htmlData, "text/html;charset=UTF-8");
|
||||
multipart.addBodyPart(htmlPart);
|
||||
}
|
||||
|
||||
if (StrUtil.isNotBlank(body)) {
|
||||
// 创建文本正文部分
|
||||
MimeBodyPart textPart = new MimeBodyPart();
|
||||
textPart.setText(body);
|
||||
multipart.addBodyPart(textPart);
|
||||
}
|
||||
//添加附件
|
||||
if (MapUtil.isNotEmpty(files) && StrUtil.isNotBlank(zipName)) {
|
||||
zipFiles(multipart, zipName, files);
|
||||
} else {
|
||||
if (MapUtil.isNotEmpty(files)) {
|
||||
forFiles(multipart, files);
|
||||
message.setContent(multipart);
|
||||
}
|
||||
}
|
||||
if (CollUtil.isNotEmpty(cc) || CollUtil.isNotEmpty(bcc)) {
|
||||
addCC(cc, bcc, message);
|
||||
}
|
||||
message.setContent(multipart);
|
||||
return message;
|
||||
}
|
||||
|
||||
private void addCC(List<String> cc, List<String> bcc, Message message) throws MessagingException {
|
||||
if (CollUtil.isNotEmpty(cc)) {
|
||||
message.addRecipients(Message.RecipientType.CC, mailBuild.eliminate(cc));
|
||||
}
|
||||
if (CollUtil.isNotEmpty(bcc)) {
|
||||
message.addRecipients(Message.RecipientType.BCC, mailBuild.eliminate(bcc));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,133 @@
|
||||
package org.dromara.email.jakarta.core.service;
|
||||
|
||||
import org.dromara.email.jakarta.api.Monitor;
|
||||
import org.dromara.email.jakarta.comm.config.MailImapConfig;
|
||||
import org.dromara.email.jakarta.comm.entity.MonitorMessage;
|
||||
import org.dromara.email.jakarta.comm.errors.MailException;
|
||||
|
||||
import jakarta.mail.BodyPart;
|
||||
import jakarta.mail.Flags;
|
||||
import jakarta.mail.Folder;
|
||||
import jakarta.mail.Message;
|
||||
import jakarta.mail.MessagingException;
|
||||
import jakarta.mail.Multipart;
|
||||
import jakarta.mail.Session;
|
||||
import jakarta.mail.Store;
|
||||
import jakarta.mail.search.FlagTerm;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Properties;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
/**
|
||||
* MonitorService
|
||||
* <p> 监听器服务
|
||||
*
|
||||
* @author :Wind
|
||||
* 2023/7/18 16:10
|
||||
**/
|
||||
public class MonitorService{
|
||||
private final Store store;
|
||||
private Monitor monitor;
|
||||
private MailImapConfig mailImapConfig;
|
||||
private Timer timer;
|
||||
|
||||
public MonitorService(MailImapConfig config, Monitor monitor) {
|
||||
Properties props = System.getProperties();
|
||||
props.setProperty("mail.store.protocol", "imaps");
|
||||
try {
|
||||
Session session = Session.getDefaultInstance(props, null);
|
||||
Store store = session.getStore("imaps");
|
||||
store.connect(config.getImapServer(), config.getUsername(), config.getAccessToken());
|
||||
this.store = store;
|
||||
this.monitor = monitor;
|
||||
this.mailImapConfig = config;
|
||||
} catch (Exception e) {
|
||||
throw new MailException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void startListening() {
|
||||
try {
|
||||
Folder inbox = store.getFolder("Inbox");
|
||||
inbox.open(Folder.READ_WRITE);
|
||||
Message[] messages = inbox.search(new FlagTerm(new Flags(Flags.Flag.SEEN), false));
|
||||
for (Message message : messages) {
|
||||
MonitorMessage monitorMessage = new MonitorMessage();
|
||||
// 获取邮件的发送者
|
||||
monitorMessage.setFromAddress(message.getFrom()[0].toString());
|
||||
// 获取邮件主题
|
||||
monitorMessage.setTitle(message.getSubject());
|
||||
// 获取邮件的内容
|
||||
if (message.isMimeType("text/plain")) {
|
||||
Object content = message.getContent();
|
||||
if (content == null){
|
||||
StringBuilder stringBuilder = getStringBuilder(message);
|
||||
content = stringBuilder.toString();
|
||||
}
|
||||
monitorMessage.setText(content.toString());
|
||||
} else if (message.isMimeType("multipart/*")) {
|
||||
Multipart mp = (Multipart) message.getContent();
|
||||
for (int i = 0; i < mp.getCount();i++){
|
||||
BodyPart bodyPart = mp.getBodyPart(i);
|
||||
String contentType = bodyPart.getContentType().toLowerCase();
|
||||
if (contentType.startsWith("text/plain")) {
|
||||
// 纯文本内容
|
||||
monitorMessage.setText(bodyPart.getContent().toString());
|
||||
} else if (contentType.startsWith("text/html")) {
|
||||
// HTML内容
|
||||
monitorMessage.setHtmlText(bodyPart.getContent().toString());
|
||||
}
|
||||
}
|
||||
monitorMessage.setBody(mp);
|
||||
}
|
||||
monitorMessage.setMessageIndex(message.getMessageNumber());
|
||||
monitorMessage.setSendDate(message.getSentDate());
|
||||
monitorMessage.setAcceptTime(System.currentTimeMillis());
|
||||
if (this.monitor.monitor(monitorMessage)) {
|
||||
message.setFlag(Flags.Flag.SEEN, true);
|
||||
}
|
||||
}
|
||||
inbox.close();
|
||||
} catch (Exception e) {
|
||||
throw new MailException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static StringBuilder getStringBuilder(Message message) throws IOException, MessagingException {
|
||||
InputStream inputStream = message.getInputStream();
|
||||
|
||||
// 解析输入流以获取内容
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
stringBuilder.append(line);
|
||||
}
|
||||
}
|
||||
return stringBuilder;
|
||||
}
|
||||
|
||||
public MonitorService start(){
|
||||
Timer timer = new Timer();
|
||||
this.timer = timer;
|
||||
timer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
startListening();
|
||||
}
|
||||
},0,mailImapConfig.getCycle()*1000);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void stop(){
|
||||
timer.cancel();
|
||||
}
|
||||
|
||||
public MailImapConfig getMailImapConfig() {
|
||||
return mailImapConfig;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user