SpringCloud微服務(wù)實(shí)戰(zhàn)——搭建企業(yè)級(jí)開(kāi)發(fā)框架(四十三):多租戶可配置的電子郵件發(fā)送系統(tǒng)設(shè)計(jì)與實(shí)現(xiàn)

??在日常生活中,郵件已經(jīng)被聊天軟件、短信等更便捷的信息傳送方式代替固该。但在日常工作中,我們的重要的信息通知等非常有必要去歸檔追溯糖儡,那么郵件就是不可或缺的信息傳送渠道伐坏。對(duì)于我們工作中經(jīng)常用到的系統(tǒng),里面也基本都集成了郵件發(fā)送功能握联。
??SpringBoot提供了基于JavaMail的starter桦沉,我們只要按照官方的說(shuō)明配置郵件服務(wù)器信息,即可使我們的系統(tǒng)擁有發(fā)送電子郵件的功能金闽。但是纯露,在我們GitEgg開(kāi)發(fā)框架的實(shí)際業(yè)務(wù)開(kāi)發(fā)過(guò)程中,有兩個(gè)問(wèn)題需要解決:一個(gè)是SpringBoot郵箱服務(wù)器的配置是配置在配置文件中的代芜,不支持靈活的界面配置埠褪。另外一個(gè)是我們的開(kāi)發(fā)框架需要支持多租戶,那么此時(shí)需要對(duì)SpringBoot提供的郵件發(fā)送功能進(jìn)行擴(kuò)展挤庇,以滿足我們的需求钞速。

那么,基于以上需求和問(wèn)題嫡秕,我們對(duì)GitEgg框架進(jìn)行擴(kuò)展渴语,增加以下功能:

1、擴(kuò)展系統(tǒng)配置:將郵箱服務(wù)器的配置信息持久化到數(shù)據(jù)庫(kù)淘菩、Redis緩存遵班,和配置文件一起使用,制定讀取優(yōu)先級(jí)潮改。
2、擴(kuò)展多租戶配置:如果系統(tǒng)開(kāi)啟了多租戶功能腹暖,那么在郵件發(fā)送時(shí)汇在,首先讀取租戶的當(dāng)前配置,如果沒(méi)有配置脏答,那么在讀取系統(tǒng)配置糕殉。
3、自有選擇服務(wù)器:用戶可在系統(tǒng)界面上選擇指定的郵箱服務(wù)器進(jìn)行郵件發(fā)送。
4恳邀、提供郵件發(fā)送模板:用戶可選擇預(yù)先制定的郵件模板進(jìn)行發(fā)送特定郵件柬甥。
5、增加發(fā)送數(shù)量羡洁、頻率限制:增加配置玷过,限制模板郵件的發(fā)送數(shù)量和頻率。
6筑煮、保存郵件發(fā)送記錄:不一定把所有附件都保存辛蚊,只需保存郵件發(fā)送關(guān)鍵信息,如果需要保存所有附件等需要自己擴(kuò)展真仲。

??同一個(gè)租戶可以配置多個(gè)電子郵件服務(wù)器袋马,但只可以設(shè)置一個(gè)服務(wù)器為啟用狀態(tài)。默認(rèn)情況下秸应,系統(tǒng)通知類(lèi)的功能只使用啟用狀態(tài)的服務(wù)器進(jìn)行郵件發(fā)送虑凛。在有定制化需求的情況下,比如從頁(yè)面直接指定某個(gè)服務(wù)器進(jìn)行郵件發(fā)送软啼,那么提供可以選擇的接口桑谍,指定某個(gè)服務(wù)器進(jìn)行郵件發(fā)送。

一焰宣、集成spring-boot-starter-mail擴(kuò)展基礎(chǔ)郵件發(fā)送功能

1霉囚、在基礎(chǔ)框架gitegg-platform中新建gitegg-platform-mail子項(xiàng)目,引入郵件必需的相關(guān)依賴包匕积。
    <dependencies>
        <!-- gitegg Spring Boot自定義及擴(kuò)展 -->
        <dependency>
            <groupId>com.gitegg.platform</groupId>
            <artifactId>gitegg-platform-boot</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
            <!-- 去除springboot默認(rèn)的logback配置-->
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
2盈罐、擴(kuò)展郵件服務(wù)器配置類(lèi),增加租戶等信息闪唆,方便從緩存讀取到信息之后進(jìn)行配置轉(zhuǎn)換盅粪。
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class GitEggMailProperties extends MailProperties {

    /**
     * 配置id
     */
    private Long id;

    /**
     * 租戶id
     */
    private Long tenantId;

    /**
     * 渠道id
     */
    private String channelCode;

    /**
     * 狀態(tài)
     */
    private Integer channelStatus;

    /**
     * 配置的md5值
     */
    private String md5;
}
3、擴(kuò)展郵件發(fā)送實(shí)現(xiàn)類(lèi)JavaMailSenderImpl悄蕾,添加多租戶和郵箱服務(wù)器編碼票顾,便于多租戶和渠道選擇。
@Data
public class GitEggJavaMailSenderImpl extends JavaMailSenderImpl {

    /**
     * 配置id
     */
    private Long id;

    /**
     * 租戶id
     */
    private Long tenantId;

    /**
     * 渠道編碼
     */
    private String channelCode;

    /**
     * 配置的md5值
     */
    private String md5;

}
4帆调、新建郵件發(fā)送實(shí)例工廠類(lèi)JavaMailSenderFactory奠骄,在郵件發(fā)送時(shí),根據(jù)需求生產(chǎn)需要的郵件發(fā)送實(shí)例番刊。
@Slf4j
public class JavaMailSenderFactory {

    private RedisTemplate redisTemplate;

    private JavaMailSenderImpl javaMailSenderImpl;

    /**
     * 是否開(kāi)啟租戶模式
     */
    private Boolean enable;

    /**
     * JavaMailSender 緩存
     * 盡管存在多個(gè)微服務(wù)含鳞,但是只需要在每個(gè)微服務(wù)初始化一次即可
     */
    private final static Map<String, GitEggJavaMailSenderImpl> javaMailSenderMap = new ConcurrentHashMap<>();

    public JavaMailSenderFactory(RedisTemplate redisTemplate, JavaMailSenderImpl javaMailSenderImpl, Boolean enable) {
        this.redisTemplate = redisTemplate;
        this.javaMailSenderImpl = javaMailSenderImpl;
        this.enable = enable;
    }

    /**
     * 指定郵件發(fā)送渠道
     * @return
     */
    public JavaMailSenderImpl getMailSender(String... channelCode){
        if (null == channelCode || channelCode.length == GitEggConstant.COUNT_ZERO
                || null == channelCode[GitEggConstant.Number.ZERO])
        {
            return this.getDefaultMailSender();
        }
        // 首先判斷是否開(kāi)啟多租戶
        String mailConfigKey = JavaMailConstant.MAIL_TENANT_CONFIG_KEY;

        if (enable) {
            mailConfigKey += GitEggAuthUtils.getTenantId();
        } else {
            mailConfigKey = JavaMailConstant.MAIL_CONFIG_KEY;
        }

        // 從緩存獲取郵件配置信息
        // 根據(jù)channel code獲取配置,用channel code時(shí)芹务,不區(qū)分是否是默認(rèn)配置
        String propertiesStr = (String) redisTemplate.opsForHash().get(mailConfigKey, channelCode[GitEggConstant.Number.ZERO]);
        if (StringUtils.isEmpty(propertiesStr))
        {
            throw new BusinessException("未獲取到[" + channelCode[GitEggConstant.Number.ZERO] + "]的郵件配置信息");
        }
        GitEggMailProperties properties = null;
        try {
            properties = JsonUtils.jsonToPojo(propertiesStr, GitEggMailProperties.class);
        } catch (Exception e) {
            log.error("轉(zhuǎn)換郵件配置信息異常:{}", e);
            throw new BusinessException("轉(zhuǎn)換郵件配置信息異常:" + e);
        }
        return this.getMailSender(mailConfigKey, properties);
    }

    /**
     * 不指定郵件發(fā)送渠道蝉绷,取默認(rèn)配置
     * @return
     */
    public JavaMailSenderImpl getDefaultMailSender(){
        // 首先判斷是否開(kāi)啟多租戶
        String mailConfigKey = JavaMailConstant.MAIL_TENANT_CONFIG_KEY;

        if (enable) {
            mailConfigKey += GitEggAuthUtils.getTenantId();
        } else {
            mailConfigKey = JavaMailConstant.MAIL_CONFIG_KEY;
        }

        // 獲取所有郵件配置列表
        Map<Object, Object> propertiesMap = redisTemplate.opsForHash().entries(mailConfigKey);
        Iterator<Map.Entry<Object, Object>> entries = propertiesMap.entrySet().iterator();
        // 如果沒(méi)有設(shè)置取哪個(gè)配置鸭廷,那么獲取默認(rèn)的配置
        GitEggMailProperties properties = null;
        try {
            while (entries.hasNext()) {
                Map.Entry<Object, Object> entry = entries.next();
                // 轉(zhuǎn)為系統(tǒng)配置對(duì)象
                GitEggMailProperties propertiesEnable = JsonUtils.jsonToPojo((String) entry.getValue(), GitEggMailProperties.class);
                if (propertiesEnable.getChannelStatus().intValue() == GitEggConstant.ENABLE) {
                    properties = propertiesEnable;
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return this.getMailSender(mailConfigKey, properties);
    }

    private JavaMailSenderImpl getMailSender(String mailConfigKey, GitEggMailProperties properties) {
        // 根據(jù)最新配置信息判斷是否從本地獲取mailSender,在配置保存時(shí)熔吗,計(jì)算實(shí)體配置的md5值辆床,然后進(jìn)行比較,不要在每次對(duì)比的時(shí)候進(jìn)行md5計(jì)算
        if (null != properties && !StringUtils.isEmpty(properties.getMd5()))
        {
            GitEggJavaMailSenderImpl javaMailSender = javaMailSenderMap.get(mailConfigKey);
            if (null == javaMailSender || !properties.getMd5().equals(javaMailSender.getMd5()))
            {
                // 如果沒(méi)有配置信息桅狠,那么直接返回系統(tǒng)默認(rèn)配置的mailSender
                javaMailSender = new GitEggJavaMailSenderImpl();
                this.applyProperties(properties, javaMailSender);
                javaMailSender.setMd5(properties.getMd5());
                javaMailSender.setId(properties.getId());
                // 將MailSender放入緩存
                javaMailSenderMap.put(mailConfigKey, javaMailSender);
            }
            return javaMailSender;
        }
        else
        {
            return this.javaMailSenderImpl;
        }
    }

    private void applyProperties(MailProperties properties, JavaMailSenderImpl sender) {
        sender.setHost(properties.getHost());
        if (properties.getPort() != null) {
            sender.setPort(properties.getPort());
        }

        sender.setUsername(properties.getUsername());
        sender.setPassword(properties.getPassword());
        sender.setProtocol(properties.getProtocol());
        if (properties.getDefaultEncoding() != null) {
            sender.setDefaultEncoding(properties.getDefaultEncoding().name());
        }

        if (!properties.getProperties().isEmpty()) {
            sender.setJavaMailProperties(this.asProperties(properties.getProperties()));
        }

    }

    private Properties asProperties(Map<String, String> source) {
        Properties properties = new Properties();
        properties.putAll(source);
        return properties;
    }
}
5讼载、配置異步郵件發(fā)送的線程池,這里需注意異步線程池上下文變量共享問(wèn)題垂攘,有兩種方式解決维雇,一個(gè)是使用裝飾器TaskDecorator將父子線程變量進(jìn)行復(fù)制,還有一種方式是transmittable-thread-local來(lái)共享線程上下文晒他,這里不展開(kāi)描述吱型,后續(xù)會(huì)專(zhuān)門(mén)針對(duì)如何在微服務(wù)異步線程池中共享上線文進(jìn)行說(shuō)明。
@Configuration
public class MailThreadPoolConfig {

    @Value("${spring.mail-task.execution.pool.core-size}")
    private int corePoolSize;

    @Value("${spring.mail-task.execution.pool.max-size}")
    private int maxPoolSize;

    @Value("${spring.mail-task.execution.pool.queue-capacity}")
    private int queueCapacity;

    @Value("${spring.mail-task.execution.thread-name-prefix}")
    private String namePrefix;

    @Value("${spring.mail-task.execution.pool.keep-alive}")
    private int keepAliveSeconds;

    /**
     * 郵件發(fā)送的線程池
     * @return
     */
    @Bean("mailTaskExecutor")
    public Executor mailTaskExecutor(){

        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //最大線程數(shù)
        executor.setMaxPoolSize(maxPoolSize);
        //核心線程數(shù)
        executor.setCorePoolSize(corePoolSize);
        //任務(wù)隊(duì)列的大小
        executor.setQueueCapacity(queueCapacity);
        //線程前綴名
        executor.setThreadNamePrefix(namePrefix);
        //線程存活時(shí)間
        executor.setKeepAliveSeconds(keepAliveSeconds);

        // 設(shè)置裝飾器陨仅,父子線程共享request header變量
        executor.setTaskDecorator(new RequestHeaderTaskDecorator());

        /**
         * 拒絕處理策略
         * CallerRunsPolicy():交由調(diào)用方線程運(yùn)行津滞,比如 main 線程。
         * AbortPolicy():直接拋出異常灼伤。
         * DiscardPolicy():直接丟棄触徐。
         * DiscardOldestPolicy():丟棄隊(duì)列中最老的任務(wù)。
         */
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 線程初始化
        executor.initialize();
        return executor;
    }
}
6狐赡、增加郵件發(fā)送結(jié)果的枚舉類(lèi)MailResultCodeEnum
public enum MailResultCodeEnum {

    /**
     * 默認(rèn)
     */
    SUCCESS("success", "郵件發(fā)送成功"),

    /**
     * 自定義
     */
    ERROR("error", "郵件發(fā)送失敗");

    public String code;

    public String message;

    MailResultCodeEnum(String code, String message) {
        this.code = code;
        this.message = message;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

}
7撞鹉、增加郵箱服務(wù)器相關(guān)默認(rèn)配置的常量類(lèi)JavaMailConstant.java
public class JavaMailConstant {
    /**
     * Redis JavaMail配置config key
     */
    public static final String MAIL_CONFIG_KEY = "mail:config";

    /**
     * 當(dāng)開(kāi)啟多租戶模式時(shí),Redis JavaMail配置config key
     */
    public static final String MAIL_TENANT_CONFIG_KEY = "mail:tenant:config:";
}
8颖侄、增加GitEggJavaMail自動(dòng)裝配類(lèi)鸟雏,根據(jù)Nacos或者系統(tǒng)配置進(jìn)行裝配。
@Slf4j
@Configuration
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class GitEggJavaMailConfiguration {

    private final JavaMailSenderImpl javaMailSenderImpl;
    
    private final RedisTemplate redisTemplate;

    /**
     * 是否開(kāi)啟租戶模式
     */
    @Value("${tenant.enable}")
    private Boolean enable;
    
    @Bean
    public JavaMailSenderFactory gitEggAuthRequestFactory() {
        return new JavaMailSenderFactory(redisTemplate, javaMailSenderImpl, enable);
    }
}

二览祖、增加郵箱服務(wù)器配置界面

??郵箱服務(wù)器的配置孝鹊,實(shí)際就是不同郵箱渠道的配置,這里我們將表和字段設(shè)計(jì)好展蒂,然后使用GitEgg自帶代碼生成器又活,生成業(yè)務(wù)的CRUD代碼即可。

1锰悼、郵箱渠道配置表設(shè)計(jì)
CREATE TABLE `t_sys_mail_channel`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
  `tenant_id` bigint(20) NOT NULL DEFAULT 0 COMMENT '租戶id',
  `channel_code` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '渠道編碼',
  `channel_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '渠道名稱(chēng)',
  `host` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'SMTP服務(wù)器地址',
  `port` int(11) NULL DEFAULT NULL COMMENT 'SMTP服務(wù)器端口',
  `username` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '賬戶名',
  `password` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '密碼',
  `protocol` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'smtp' COMMENT '協(xié)議',
  `default_encoding` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '默認(rèn)編碼',
  `jndi_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '會(huì)話JNDI名稱(chēng)',
  `properties` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'JavaMail 配置',
  `channel_status` tinyint(2) NOT NULL DEFAULT 0 COMMENT '渠道狀態(tài) 1有效 0禁用',
  `md5` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'MD5',
  `comments` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '描述',
  `create_time` datetime(0) NULL DEFAULT NULL COMMENT '創(chuàng)建時(shí)間',
  `creator` bigint(20) NULL DEFAULT NULL COMMENT '創(chuàng)建者',
  `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新時(shí)間',
  `operator` bigint(20) NULL DEFAULT NULL COMMENT '更新者',
  `del_flag` tinyint(2) NULL DEFAULT 0 COMMENT '是否刪除',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '郵件渠道' ROW_FORMAT = DYNAMIC;

SET FOREIGN_KEY_CHECKS = 1;
2柳骄、根據(jù)表設(shè)計(jì),然后配置代碼生成界面箕般,生成前后端代碼夹界。
image.png
3、生成代碼后隘世,進(jìn)行相關(guān)權(quán)限配置可柿,前端界面展示:
image.png

三、以同樣的方式增加郵箱模板配置界面和郵件發(fā)送日志記錄

1丙者、郵箱模板和郵件發(fā)送日志數(shù)據(jù)庫(kù)表設(shè)計(jì)

郵件模板數(shù)據(jù)庫(kù)表設(shè)計(jì):

CREATE TABLE `t_sys_mail_template`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
  `tenant_id` bigint(20) NOT NULL DEFAULT 0 COMMENT '租戶id',
  `template_code` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '模板編碼',
  `template_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '模板名稱(chēng)',
  `sign_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '模板簽名',
  `template_status` tinyint(2) NOT NULL DEFAULT 1 COMMENT '模板狀態(tài)',
  `template_type` tinyint(2) NULL DEFAULT NULL COMMENT '模板類(lèi)型',
  `template_content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '模板內(nèi)容',
  `cache_code_key` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '緩存key',
  `cache_time_out` bigint(20) NULL DEFAULT 0 COMMENT '緩存有效期 值',
  `cache_time_out_unit` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '緩存有效期 單位',
  `send_times_limit` bigint(20) NULL DEFAULT 0 COMMENT '發(fā)送次數(shù)限制',
  `send_times_limit_period` bigint(20) NULL DEFAULT 0 COMMENT '限制時(shí)間間隔',
  `send_times_limit_period_unit` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '限制時(shí)間間隔 單位',
  `comments` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '描述',
  `create_time` datetime(0) NULL DEFAULT NULL COMMENT '創(chuàng)建時(shí)間',
  `creator` bigint(20) NULL DEFAULT NULL COMMENT '創(chuàng)建者',
  `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新時(shí)間',
  `operator` bigint(20) NULL DEFAULT NULL COMMENT '更新者',
  `del_flag` tinyint(2) NULL DEFAULT 0 COMMENT '是否刪除',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '郵件模板' ROW_FORMAT = DYNAMIC;

SET FOREIGN_KEY_CHECKS = 1;

郵件日志數(shù)據(jù)庫(kù)表設(shè)計(jì):

CREATE TABLE `t_sys_mail_log`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
  `tenant_id` bigint(20) NOT NULL DEFAULT 0 COMMENT '租戶id',
  `channel_id` bigint(20) NULL DEFAULT NULL COMMENT 'mail渠道id',
  `template_id` bigint(20) NULL DEFAULT NULL COMMENT 'mail模板id',
  `mail_subject` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '郵件主題',
  `mail_from` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '發(fā)送人',
  `mail_to` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '收件人',
  `mail_cc` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '抄送',
  `mail_bcc` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '密抄送',
  `mail_content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '郵件內(nèi)容',
  `attachment_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '0' COMMENT '附件名稱(chēng)',
  `attachment_size` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '0' COMMENT '附件大小',
  `send_time` datetime(0) NULL DEFAULT NULL COMMENT '發(fā)送時(shí)間',
  `send_result_code` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '1' COMMENT '發(fā)送結(jié)果碼',
  `send_result_msg` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '發(fā)送結(jié)果消息',
  `create_time` datetime(0) NULL DEFAULT NULL COMMENT '創(chuàng)建日期',
  `creator` bigint(20) NULL DEFAULT NULL COMMENT '創(chuàng)建者',
  `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新日期',
  `operator` bigint(20) NULL DEFAULT NULL COMMENT '更新者',
  `del_flag` tinyint(2) NOT NULL DEFAULT 0 COMMENT '是否刪除 1:刪除 0:不刪除',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '郵件記錄' ROW_FORMAT = DYNAMIC;

SET FOREIGN_KEY_CHECKS = 1;
2复斥、郵件模板和郵件發(fā)送日志界面
郵件模板管理界面
郵件渠道查詢界面

四、QQ郵箱配置和阿里云企業(yè)郵箱配置測(cè)試

??上面的基本功能開(kāi)發(fā)完成之后械媒,那么我們就需要進(jìn)行測(cè)試目锭,這里選擇兩種類(lèi)型的郵箱進(jìn)行測(cè)試,一種是QQ郵箱纷捞,還有一種是阿里云企業(yè)郵箱痢虹。

1、QQ郵箱配置

QQ郵箱在配置的時(shí)候不能使用QQ的登錄密碼主儡,需要單獨(dú)設(shè)置QQ郵箱的授權(quán)碼奖唯,下面是操作步驟:

  • 開(kāi)通qq郵箱的smtp功能
image.png

image.png

image.png
  • 經(jīng)過(guò)一系列的驗(yàn)證之后,會(huì)獲取到一個(gè)授權(quán)碼:


    image.png
  • 系統(tǒng)中配置QQ郵箱相關(guān)信息


    image.png
2糜值、 阿里云企業(yè)郵箱配置

阿里云企業(yè)郵箱的配置相比較而言就簡(jiǎn)單一些丰捷,配置的密碼就是企業(yè)郵箱登錄的密碼。

  • 賬戶設(shè)置寂汇,開(kāi)啟POP3/SMTP和IMAP/SMTP服務(wù)


    image.png
  • 系統(tǒng)中配置阿里云企業(yè)郵箱相關(guān)信息


    image.png
3病往、Nacos中配置默認(rèn)郵件服務(wù)器,同時(shí)增加郵件異步線程池配置
  mail:
    username: XXXXXXXXXXX
    password: XXXXXXXXXX
    default-encoding: UTF-8
    host: smtp.mxhichina.com
    port: 25
    protocol: smtp
    properties:
      mail:
        smtp:
          auth: true
          ssl:
            enable: false
  # 異步發(fā)送郵件骄瓣,核心線程池?cái)?shù)配置
  mail-task:
    execution:
      pool:
        core-size: 5
        max-size: 10
        queue-capacity: 5
        keep-alive: 60
      thread-name-prefix: mail-send-task-
4停巷、在郵件渠道配置界面進(jìn)行郵件發(fā)送測(cè)試,有兩種測(cè)試方式榕栏,一種是選擇指定渠道進(jìn)行發(fā)送畔勤,另外一種是選擇系統(tǒng)默認(rèn)渠道進(jìn)行郵件發(fā)送。發(fā)送完成后查看郵件日志模塊臼膏,檢查是否有郵件發(fā)送成功的記錄硼被。
  • 選擇需要測(cè)試的郵箱服務(wù)器
image.png
  • 填寫(xiě)測(cè)試郵箱發(fā)送內(nèi)容
image.png
  • 查看郵箱發(fā)送日志
image.png
GitEgg-Cloud是一款基于SpringCloud整合搭建的企業(yè)級(jí)微服務(wù)應(yīng)用開(kāi)發(fā)框架,開(kāi)源項(xiàng)目地址:

Gitee: https://gitee.com/wmz1930/GitEgg
GitHub: https://github.com/wmz1930/GitEgg

歡迎感興趣的小伙伴Star支持一下渗磅。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末嚷硫,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子始鱼,更是在濱河造成了極大的恐慌仔掸,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件医清,死亡現(xiàn)場(chǎng)離奇詭異起暮,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)会烙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)负懦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)筒捺,“玉大人,你說(shuō)我怎么就攤上這事纸厉∠悼裕” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵颗品,是天一觀的道長(zhǎng)肯尺。 經(jīng)常有香客問(wèn)我,道長(zhǎng)躯枢,這世上最難降的妖魔是什么则吟? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮锄蹂,結(jié)果婚禮上氓仲,老公的妹妹穿的比我還像新娘。我一直安慰自己败匹,他們只是感情好寨昙,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著掀亩,像睡著了一般舔哪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上槽棍,一...
    開(kāi)封第一講書(shū)人閱讀 51,631評(píng)論 1 305
  • 那天捉蚤,我揣著相機(jī)與錄音,去河邊找鬼炼七。 笑死缆巧,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的豌拙。 我是一名探鬼主播陕悬,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼按傅!你這毒婦竟也來(lái)了捉超?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤唯绍,失蹤者是張志新(化名)和其女友劉穎拼岳,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體况芒,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡惜纸,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片耐版。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡祠够,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出椭更,到底是詐尸還是另有隱情哪审,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布虑瀑,位于F島的核電站,受9級(jí)特大地震影響滴须,放射性物質(zhì)發(fā)生泄漏舌狗。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一扔水、第九天 我趴在偏房一處隱蔽的房頂上張望痛侍。 院中可真熱鬧,春花似錦魔市、人聲如沸主届。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)君丁。三九已至,卻和暖如春将宪,著一層夾襖步出監(jiān)牢的瞬間绘闷,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工较坛, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留印蔗,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓丑勤,卻偏偏與公主長(zhǎng)得像华嘹,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子法竞,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容