@ -0,0 +1,657 @@
package org.dromara.common.mail.utils ;
import cn.hutool.core.util.CharsetUtil ;
import cn.hutool.core.util.ObjectUtil ;
import cn.hutool.core.util.StrUtil ;
import cn.hutool.setting.Setting ;
import java.io.Serializable ;
import java.nio.charset.Charset ;
import java.util.HashMap ;
import java.util.Map ;
import java.util.Properties ;
/**
* 邮件账户对象
*
* @author Luxiaolei
*/
public class MailAccount implements Serializable {
private static final long serialVersionUID = - 6937313421815719204L ;
private static final String MAIL_PROTOCOL = " mail.transport.protocol " ;
private static final String SMTP_HOST = " mail.smtp.host " ;
private static final String SMTP_PORT = " mail.smtp.port " ;
private static final String SMTP_AUTH = " mail.smtp.auth " ;
private static final String SMTP_TIMEOUT = " mail.smtp.timeout " ;
private static final String SMTP_CONNECTION_TIMEOUT = " mail.smtp.connectiontimeout " ;
private static final String SMTP_WRITE_TIMEOUT = " mail.smtp.writetimeout " ;
// SSL
private static final String STARTTLS_ENABLE = " mail.smtp.starttls.enable " ;
private static final String SSL_ENABLE = " mail.smtp.ssl.enable " ;
private static final String SSL_PROTOCOLS = " mail.smtp.ssl.protocols " ;
private static final String SOCKET_FACTORY = " mail.smtp.socketFactory.class " ;
private static final String SOCKET_FACTORY_FALLBACK = " mail.smtp.socketFactory.fallback " ;
private static final String SOCKET_FACTORY_PORT = " smtp.socketFactory.port " ;
// System Properties
private static final String SPLIT_LONG_PARAMS = " mail.mime.splitlongparameters " ;
//private static final String ENCODE_FILE_NAME = "mail.mime.encodefilename";
//private static final String CHARSET = "mail.mime.charset";
// 其他
private static final String MAIL_DEBUG = " mail.debug " ;
public static final String [ ] MAIL_SETTING_PATHS = new String [ ] { " config/mail.setting " , " config/mailAccount.setting " , " mail.setting " } ;
/**
* SMTP服务器域名
*/
private String host ;
/**
* SMTP服务端口
*/
private Integer port ;
/**
* 是否需要用户名密码验证
*/
private Boolean auth ;
/**
* 用户名
*/
private String user ;
/**
* 密码
*/
private String pass ;
/**
* 发送方, 遵循RFC-822标准
*/
private String from ;
/**
* 是否打开调试模式,调试模式会显示与邮件服务器通信过程,默认不开启
*/
private boolean debug ;
/**
* 编码用于编码邮件正文和发送人、收件人等中文
*/
private Charset charset = CharsetUtil . CHARSET_UTF_8 ;
/**
* 对于超长参数是否切分为多份, 默认为false( 国内邮箱附件不支持切分的附件名)
*/
private boolean splitlongparameters = false ;
/**
* 对于文件名是否使用{@link #charset}编码,默认为 {@code true}
*/
private boolean encodefilename = true ;
/**
* 使用 STARTTLS安全连接, STARTTLS是对纯文本通信协议的扩展。它将纯文本连接升级为加密连接( TLS或SSL) , 而不是使用一个单独的加密通信端口。
*/
private boolean starttlsEnable = false ;
/**
* 使用 SSL安全连接
*/
private Boolean sslEnable ;
/**
* SSL协议, 多个协议用空格分隔
*/
private String sslProtocols ;
/**
* 指定实现javax.net.SocketFactory接口的类的名称,这个类将被用于创建SMTP的套接字
*/
private String socketFactoryClass = " javax.net.ssl.SSLSocketFactory " ;
/**
* 如果设置为true,未能创建一个套接字使用指定的套接字工厂类将导致使用java.net.Socket创建的套接字类, 默认值为true
*/
private boolean socketFactoryFallback ;
/**
* 指定的端口连接到在使用指定的套接字工厂。如果没有设置,将使用默认端口
*/
private int socketFactoryPort = 465 ;
/**
* SMTP超时时长, 单位毫秒, 缺省值不超时
*/
private long timeout ;
/**
* Socket连接超时值, 单位毫秒, 缺省值不超时
*/
private long connectionTimeout ;
/**
* Socket写出超时值, 单位毫秒, 缺省值不超时
*/
private long writeTimeout ;
/**
* 自定义的其他属性,此自定义属性会覆盖默认属性
*/
private final Map < String , Object > customProperty = new HashMap < > ( ) ;
// -------------------------------------------------------------- Constructor start
/**
* 构造,所有参数需自行定义或保持默认值
*/
public MailAccount ( ) {
}
/**
* 构造
*
* @param settingPath 配置文件路径
*/
public MailAccount ( String settingPath ) {
this ( new Setting ( settingPath ) ) ;
}
/**
* 构造
*
* @param setting 配置文件
*/
public MailAccount ( Setting setting ) {
setting . toBean ( this ) ;
}
// -------------------------------------------------------------- Constructor end
/**
* 获得SMTP服务器域名
*
* @return SMTP服务器域名
*/
public String getHost ( ) {
return host ;
}
/**
* 设置SMTP服务器域名
*
* @param host SMTP服务器域名
* @return this
*/
public MailAccount setHost ( String host ) {
this . host = host ;
return this ;
}
/**
* 获得SMTP服务端口
*
* @return SMTP服务端口
*/
public Integer getPort ( ) {
return port ;
}
/**
* 设置SMTP服务端口
*
* @param port SMTP服务端口
* @return this
*/
public MailAccount setPort ( Integer port ) {
this . port = port ;
return this ;
}
/**
* 是否需要用户名密码验证
*
* @return 是否需要用户名密码验证
*/
public Boolean isAuth ( ) {
return auth ;
}
/**
* 设置是否需要用户名密码验证
*
* @param isAuth 是否需要用户名密码验证
* @return this
*/
public MailAccount setAuth ( boolean isAuth ) {
this . auth = isAuth ;
return this ;
}
/**
* 获取用户名
*
* @return 用户名
*/
public String getUser ( ) {
return user ;
}
/**
* 设置用户名
*
* @param user 用户名
* @return this
*/
public MailAccount setUser ( String user ) {
this . user = user ;
return this ;
}
/**
* 获取密码
*
* @return 密码
*/
public String getPass ( ) {
return pass ;
}
/**
* 设置密码
*
* @param pass 密码
* @return this
*/
public MailAccount setPass ( String pass ) {
this . pass = pass ;
return this ;
}
/**
* 获取发送方, 遵循RFC-822标准
*
* @return 发送方, 遵循RFC-822标准
*/
public String getFrom ( ) {
return from ;
}
/**
* 设置发送方, 遵循RFC-822标准<br>
* 发件人可以是以下形式:
*
* <pre>
* 1. user@xxx.xx
* 2. name <user@xxx.xx>
* </pre>
*
* @param from 发送方, 遵循RFC-822标准
* @return this
*/
public MailAccount setFrom ( String from ) {
this . from = from ;
return this ;
}
/**
* 是否打开调试模式,调试模式会显示与邮件服务器通信过程,默认不开启
*
* @return 是否打开调试模式,调试模式会显示与邮件服务器通信过程,默认不开启
* @since 4.0.2
*/
public boolean isDebug ( ) {
return debug ;
}
/**
* 设置是否打开调试模式,调试模式会显示与邮件服务器通信过程,默认不开启
*
* @param debug 是否打开调试模式,调试模式会显示与邮件服务器通信过程,默认不开启
* @return this
* @since 4.0.2
*/
public MailAccount setDebug ( boolean debug ) {
this . debug = debug ;
return this ;
}
/**
* 获取字符集编码
*
* @return 编码,可能为{@code null}
*/
public Charset getCharset ( ) {
return charset ;
}
/**
* 设置字符集编码,此选项不会修改全局配置,若修改全局配置,请设置此项为{@code null}并设置:
* <pre>
* System.setProperty("mail.mime.charset", charset);
* </pre>
*
* @param charset 字符集编码,{@code null} 则表示使用全局设置的默认编码, 全局编码为mail.mime.charset系统属性
* @return this
*/
public MailAccount setCharset ( Charset charset ) {
this . charset = charset ;
return this ;
}
/**
* 对于超长参数是否切分为多份, 默认为false( 国内邮箱附件不支持切分的附件名)
*
* @return 对于超长参数是否切分为多份
*/
public boolean isSplitlongparameters ( ) {
return splitlongparameters ;
}
/**
* 设置对于超长参数是否切分为多份, 默认为false( 国内邮箱附件不支持切分的附件名) <br>
* 注意此项为全局设置,此项会调用
* <pre>
* System.setProperty("mail.mime.splitlongparameters", true)
* </pre>
*
* @param splitlongparameters 对于超长参数是否切分为多份
*/
public void setSplitlongparameters ( boolean splitlongparameters ) {
this . splitlongparameters = splitlongparameters ;
}
/**
* 对于文件名是否使用{@link #charset}编码,默认为 {@code true}
*
* @return 对于文件名是否使用{@link #charset}编码,默认为 {@code true}
* @since 5.7.16
*/
public boolean isEncodefilename ( ) {
return encodefilename ;
}
/**
* 设置对于文件名是否使用{@link #charset}编码,此选项不会修改全局配置<br>
* 如果此选项设置为{@code false},则是否编码取决于两个系统属性:
* <ul>
* <li>mail.mime.encodefilename 是否编码附件文件名</li>
* <li>mail.mime.charset 编码文件名的编码</li>
* </ul>
*
* @param encodefilename 对于文件名是否使用{@link #charset}编码
* @since 5.7.16
*/
public void setEncodefilename ( boolean encodefilename ) {
this . encodefilename = encodefilename ;
}
/**
* 是否使用 STARTTLS安全连接, STARTTLS是对纯文本通信协议的扩展。它将纯文本连接升级为加密连接( TLS或SSL) , 而不是使用一个单独的加密通信端口。
*
* @return 是否使用 STARTTLS安全连接
*/
public boolean isStarttlsEnable ( ) {
return this . starttlsEnable ;
}
/**
* 设置是否使用STARTTLS安全连接, STARTTLS是对纯文本通信协议的扩展。它将纯文本连接升级为加密连接( TLS或SSL) , 而不是使用一个单独的加密通信端口。
*
* @param startttlsEnable 是否使用STARTTLS安全连接
* @return this
*/
public MailAccount setStarttlsEnable ( boolean startttlsEnable ) {
this . starttlsEnable = startttlsEnable ;
return this ;
}
/**
* 是否使用 SSL安全连接
*
* @return 是否使用 SSL安全连接
*/
public Boolean isSslEnable ( ) {
return this . sslEnable ;
}
/**
* 设置是否使用SSL安全连接
*
* @param sslEnable 是否使用SSL安全连接
* @return this
*/
public MailAccount setSslEnable ( Boolean sslEnable ) {
this . sslEnable = sslEnable ;
return this ;
}
/**
* 获取SSL协议, 多个协议用空格分隔
*
* @return SSL协议, 多个协议用空格分隔
* @since 5.5.7
*/
public String getSslProtocols ( ) {
return sslProtocols ;
}
/**
* 设置SSL协议, 多个协议用空格分隔
*
* @param sslProtocols SSL协议, 多个协议用空格分隔
* @since 5.5.7
*/
public void setSslProtocols ( String sslProtocols ) {
this . sslProtocols = sslProtocols ;
}
/**
* 获取指定实现javax.net.SocketFactory接口的类的名称,这个类将被用于创建SMTP的套接字
*
* @return 指定实现javax.net.SocketFactory接口的类的名称, 这个类将被用于创建SMTP的套接字
*/
public String getSocketFactoryClass ( ) {
return socketFactoryClass ;
}
/**
* 设置指定实现javax.net.SocketFactory接口的类的名称,这个类将被用于创建SMTP的套接字
*
* @param socketFactoryClass 指定实现javax.net.SocketFactory接口的类的名称,这个类将被用于创建SMTP的套接字
* @return this
*/
public MailAccount setSocketFactoryClass ( String socketFactoryClass ) {
this . socketFactoryClass = socketFactoryClass ;
return this ;
}
/**
* 如果设置为true,未能创建一个套接字使用指定的套接字工厂类将导致使用java.net.Socket创建的套接字类, 默认值为true
*
* @return 如果设置为true, 未能创建一个套接字使用指定的套接字工厂类将导致使用java.net.Socket创建的套接字类, 默认值为true
*/
public boolean isSocketFactoryFallback ( ) {
return socketFactoryFallback ;
}
/**
* 如果设置为true,未能创建一个套接字使用指定的套接字工厂类将导致使用java.net.Socket创建的套接字类, 默认值为true
*
* @param socketFactoryFallback 如果设置为true,未能创建一个套接字使用指定的套接字工厂类将导致使用java.net.Socket创建的套接字类, 默认值为true
* @return this
*/
public MailAccount setSocketFactoryFallback ( boolean socketFactoryFallback ) {
this . socketFactoryFallback = socketFactoryFallback ;
return this ;
}
/**
* 获取指定的端口连接到在使用指定的套接字工厂。如果没有设置,将使用默认端口
*
* @return 指定的端口连接到在使用指定的套接字工厂。如果没有设置,将使用默认端口
*/
public int getSocketFactoryPort ( ) {
return socketFactoryPort ;
}
/**
* 指定的端口连接到在使用指定的套接字工厂。如果没有设置,将使用默认端口
*
* @param socketFactoryPort 指定的端口连接到在使用指定的套接字工厂。如果没有设置,将使用默认端口
* @return this
*/
public MailAccount setSocketFactoryPort ( int socketFactoryPort ) {
this . socketFactoryPort = socketFactoryPort ;
return this ;
}
/**
* 设置SMTP超时时长, 单位毫秒, 缺省值不超时
*
* @param timeout SMTP超时时长, 单位毫秒, 缺省值不超时
* @return this
* @since 4.1.17
*/
public MailAccount setTimeout ( long timeout ) {
this . timeout = timeout ;
return this ;
}
/**
* 设置Socket连接超时值, 单位毫秒, 缺省值不超时
*
* @param connectionTimeout Socket连接超时值, 单位毫秒, 缺省值不超时
* @return this
* @since 4.1.17
*/
public MailAccount setConnectionTimeout ( long connectionTimeout ) {
this . connectionTimeout = connectionTimeout ;
return this ;
}
/**
* 设置Socket写出超时值, 单位毫秒, 缺省值不超时
*
* @param writeTimeout Socket写出超时值, 单位毫秒, 缺省值不超时
* @return this
* @since 5.8.3
*/
public MailAccount setWriteTimeout ( long writeTimeout ) {
this . writeTimeout = writeTimeout ;
return this ;
}
/**
* 获取自定义属性列表
*
* @return 自定义参数列表
* @since 5.6.4
*/
public Map < String , Object > getCustomProperty ( ) {
return customProperty ;
}
/**
* 设置自定义属性, 如mail.smtp.ssl.socketFactory
*
* @param key 属性名,空白被忽略
* @param value 属性值, null被忽略
* @return this
* @since 5.6.4
*/
public MailAccount setCustomProperty ( String key , Object value ) {
if ( StrUtil . isNotBlank ( key ) & & ObjectUtil . isNotNull ( value ) ) {
this . customProperty . put ( key , value ) ;
}
return this ;
}
/**
* 获得SMTP相关信息
*
* @return {@link Properties}
*/
public Properties getSmtpProps ( ) {
//全局系统参数
System . setProperty ( SPLIT_LONG_PARAMS , String . valueOf ( this . splitlongparameters ) ) ;
final Properties p = new Properties ( ) ;
p . put ( MAIL_PROTOCOL , " smtp " ) ;
p . put ( SMTP_HOST , this . host ) ;
p . put ( SMTP_PORT , String . valueOf ( this . port ) ) ;
p . put ( SMTP_AUTH , String . valueOf ( this . auth ) ) ;
if ( this . timeout > 0 ) {
p . put ( SMTP_TIMEOUT , String . valueOf ( this . timeout ) ) ;
}
if ( this . connectionTimeout > 0 ) {
p . put ( SMTP_CONNECTION_TIMEOUT , String . valueOf ( this . connectionTimeout ) ) ;
}
// issue#2355
if ( this . writeTimeout > 0 ) {
p . put ( SMTP_WRITE_TIMEOUT , String . valueOf ( this . writeTimeout ) ) ;
}
p . put ( MAIL_DEBUG , String . valueOf ( this . debug ) ) ;
if ( this . starttlsEnable ) {
//STARTTLS是对纯文本通信协议的扩展。它将纯文本连接升级为加密连接( TLS或SSL) , 而不是使用一个单独的加密通信端口。
p . put ( STARTTLS_ENABLE , " true " ) ;
if ( null = = this . sslEnable ) {
//为了兼容旧版本, 当用户没有此项配置时, 按照starttlsEnable开启状态时对待
this . sslEnable = true ;
}
}
// SSL
if ( null ! = this . sslEnable & & this . sslEnable ) {
p . put ( SSL_ENABLE , " true " ) ;
p . put ( SOCKET_FACTORY , socketFactoryClass ) ;
p . put ( SOCKET_FACTORY_FALLBACK , String . valueOf ( this . socketFactoryFallback ) ) ;
p . put ( SOCKET_FACTORY_PORT , String . valueOf ( this . socketFactoryPort ) ) ;
// issue#IZN95@Gitee, 在Linux下需自定义SSL协议版本
if ( StrUtil . isNotBlank ( this . sslProtocols ) ) {
p . put ( SSL_PROTOCOLS , this . sslProtocols ) ;
}
}
// 补充自定义属性,允许自定属性覆盖已经设置的值
p . putAll ( this . customProperty ) ;
return p ;
}
/**
* 如果某些值为null, 使用默认值
*
* @return this
*/
public MailAccount defaultIfEmpty ( ) {
// 去掉发件人的姓名部分
final String fromAddress = InternalMailUtil . parseFirstAddress ( this . from , this . charset ) . getAddress ( ) ;
if ( StrUtil . isBlank ( this . host ) ) {
// 如果SMTP地址为空, 默认使用smtp.<发件人邮箱后缀>
this . host = StrUtil . format ( " smtp.{} " , StrUtil . subSuf ( fromAddress , fromAddress . indexOf ( '@' ) + 1 ) ) ;
}
if ( StrUtil . isBlank ( user ) ) {
// 如果用户名为空, 默认为发件人( issue#I4FYVY@Gitee)
//this.user = StrUtil.subPre(fromAddress, fromAddress.indexOf('@'));
this . user = fromAddress ;
}
if ( null = = this . auth ) {
// 如果密码非空白,则使用认证模式
this . auth = ( false = = StrUtil . isBlank ( this . pass ) ) ;
}
if ( null = = this . port ) {
// 端口在SSL状态下默认与socketFactoryPort一致, 非SSL状态下默认为25
this . port = ( null ! = this . sslEnable & & this . sslEnable ) ? this . socketFactoryPort : 25 ;
}
if ( null = = this . charset ) {
// 默认UTF-8编码
this . charset = CharsetUtil . CHARSET_UTF_8 ;
}
return this ;
}
@Override
public String toString ( ) {
return " MailAccount [host= " + host + " , port= " + port + " , auth= " + auth + " , user= " + user + " , pass= " + ( StrUtil . isEmpty ( this . pass ) ? " " : " ****** " ) + " , from= " + from + " , startttlsEnable= "
+ starttlsEnable + " , socketFactoryClass= " + socketFactoryClass + " , socketFactoryFallback= " + socketFactoryFallback + " , socketFactoryPort= " + socketFactoryPort + " ] " ;
}
}