Spring Cloud--多租户电子邮件发送系统设计与实现

SpringBoot提供了基于JavaMail的starter,我们只要按照官方的说明配置邮件服务器
首页 新闻资讯 行业资讯 Spring Cloud--多租户电子邮件发送系统设计与实现

a638cf7220db2d6a905286dd977bb9357227a9.png

在日常生活中,邮件已经被聊天软件、短信等更便捷的信息传送方式代替。但在日常工作中,我们的重要的信息通知等非常有必要去归档追溯,那么邮件就是不可或缺的信息传送渠道。对于我们工作中经常用到的系统,里面也基本都集成了邮件发送功能。SpringBoot提供了基于JavaMail的starter,我们只要按照官方的说明配置邮件服务器信息,即可使我们的系统拥有发送电子邮件的功能。但是,在我们GitEgg开发框架的实际业务开发过程中,有两个问题需要解决:一个是SpringBoot邮箱服务器的配置是配置在配置文件中的,不支持灵活的界面配置。另外一个是我们的开发框架需要支持多租户,那么此时需要对SpringBoot提供的邮件发送功能进行扩展,以满足我们的需求。

那么,基于以上需求和问题,我们对GitEgg框架进行扩展,增加以下功能:

  1. 扩展系统配置:将邮箱服务器的配置信息持久化到数据库、Redis缓存,和配置文件一起使用,制定读取优先级。

  2. 扩展多租户配置:如果系统开启了多租户功能,那么在邮件发送时,首先读取租户的当前配置,如果没有配置,那么在读取系统配置。

  3. 自有选择服务器:用户可在系统界面上选择指定的邮箱服务器进行邮件发送。

  4. 提供邮件发送模板:用户可选择预先制定的邮件模板进行发送特定邮件。

  5. 增加发送数量、频率限制:增加配置,限制模板邮件的发送数量和频率。

  6. 保存邮件发送记录:不一定把所有附件都保存,只需保存邮件发送关键信息,如果需要保存所有附件等需要自己扩展。

同一个租户可以配置多个电子邮件服务器,但只可以设置一个服务器为启用状态。默认情况下,系统通知类的功能只使用启用状态的服务器进行邮件发送。在有定制化需求的情况下,比如从页面直接指定某个服务器进行邮件发送,那么提供可以选择的接口,指定某个服务器进行邮件发送。

一、集成spring-boot-starter-mail扩展基础邮件发送功能

1、在基础框架gitegg-platform中新建gitegg-platform-mail子项目,引入邮件必需的相关依赖包。

复制

<dependencies><!-- gitegg Spring Boot自定义及扩展 --><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默认的logback配置--><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-logging</artifactId></exclusion></exclusions></dependency></dependencies>
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

  • 15.

  • 16.

  • 17.

  • 18.

  • 19.

  • 20.

  • 21.

  • 22.

  • 23.

2、扩展邮件服务器配置类,增加租户等信息,方便从缓存读取到信息之后进行配置转换。

复制

@Data@JsonIgnoreProperties(ignoreUnknown = true)public class GitEggMailProperties extends MailProperties {/** * 配置id */private Long id;/** * 租户id */private Long tenantId;/** * 渠道id */private String channelCode;/** * 状态 */private Integer channelStatus;/** * 配置的md5值 */private String md5;
}
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

  • 15.

  • 16.

  • 17.

  • 18.

  • 19.

  • 20.

  • 21.

  • 22.

  • 23.

  • 24.

3、扩展邮件发送实现类JavaMailSenderImpl,添加多租户和邮箱服务器编码,便于多租户和渠道选择。

复制

@Datapublic class GitEggJavaMailSenderImpl extends JavaMailSenderImpl {/** * 配置id */private Long id;/** * 租户id */private Long tenantId;/** * 渠道编码 */private String channelCode;/** * 配置的md5值 */private String md5;
}
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

  • 15.

  • 16.

  • 17.

  • 18.

  • 19.

4、新建邮件发送实例工厂类JavaMailSenderFactory,在邮件发送时,根据需求生产需要的邮件发送实例。

复制

@Slf4jpublic class JavaMailSenderFactory {private RedisTemplate redisTemplate;private JavaMailSenderImpl javaMailSenderImpl;/** * 是否开启租户模式 */private Boolean enable;/** * JavaMailSender 缓存 * 尽管存在多个微服务,但是只需要在每个微服务初始化一次即可 */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;
    }/** * 指定邮件发送渠道 * @return */public JavaMailSenderImpl getMailSender(String... channelCode){if (null == channelCode || channelCode.length == GitEggConstant.COUNT_ZERO|| null == channelCode[GitEggConstant.Number.ZERO])
        {return this.getDefaultMailSender();
        }// 首先判断是否开启多租户String mailConfigKey = JavaMailConstant.MAIL_TENANT_CONFIG_KEY;if (enable) {mailConfigKey += GitEggAuthUtils.getTenantId();
        } else {mailConfigKey = JavaMailConstant.MAIL_CONFIG_KEY;
        }// 从缓存获取邮件配置信息// 根据channel code获取配置,用channel code时,不区分是否是默认配置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("转换邮件配置信息异常:{}", e);throw new BusinessException("转换邮件配置信息异常:" + e);
        }return this.getMailSender(mailConfigKey, properties);
    }/** * 不指定邮件发送渠道,取默认配置 * @return */public JavaMailSenderImpl getDefaultMailSender(){// 首先判断是否开启多租户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();// 如果没有设置取哪个配置,那么获取默认的配置GitEggMailProperties properties = null;try {while (entries.hasNext()) {Map.Entry<Object, Object> entry = entries.next();// 转为系统配置对象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) {// 根据最新配置信息判断是否从本地获取mailSender,在配置保存时,计算实体配置的md5值,然后进行比较,不要在每次对比的时候进行md5计算if (null != properties && !StringUtils.isEmpty(properties.getMd5()))
        {GitEggJavaMailSenderImpl javaMailSender = javaMailSenderMap.get(mailConfigKey);if (null == javaMailSender || !properties.getMd5().equals(javaMailSender.getMd5()))
            {// 如果没有配置信息,那么直接返回系统默认配置的mailSenderjavaMailSender = 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;
    }
}
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

  • 15.

  • 16.

  • 17.

  • 18.

  • 19.

  • 20.

  • 21.

  • 22.

  • 23.

  • 24.

  • 25.

  • 26.

  • 27.

  • 28.

  • 29.

  • 30.

  • 31.

  • 32.

  • 33.

  • 34.

  • 35.

  • 36.

  • 37.

  • 38.

  • 39.

  • 40.

  • 41.

  • 42.

  • 43.

  • 44.

  • 45.

  • 46.

  • 47.

  • 48.

  • 49.

  • 50.

  • 51.

  • 52.

  • 53.

  • 54.

  • 55.

  • 56.

  • 57.

  • 58.

  • 59.

  • 60.

  • 61.

  • 62.

  • 63.

  • 64.

  • 65.

  • 66.

  • 67.

  • 68.

  • 69.

  • 70.

  • 71.

  • 72.

  • 73.

  • 74.

  • 75.

  • 76.

  • 77.

  • 78.

  • 79.

  • 80.

  • 81.

  • 82.

  • 83.

  • 84.

  • 85.

  • 86.

  • 87.

  • 88.

  • 89.

  • 90.

  • 91.

  • 92.

  • 93.

  • 94.

  • 95.

  • 96.

  • 97.

  • 98.

  • 99.

  • 100.

  • 101.

  • 102.

  • 103.

  • 104.

  • 105.

  • 106.

  • 107.

  • 108.

  • 109.

  • 110.

  • 111.

  • 112.

  • 113.

  • 114.

  • 115.

  • 116.

  • 117.

  • 118.

  • 119.

  • 120.

  • 121.

  • 122.

  • 123.

  • 124.

  • 125.

  • 126.

  • 127.

  • 128.

  • 129.

  • 130.

5、配置异步邮件发送的线程池,这里需注意异步线程池上下文变量共享问题,有两种方式解决,一个是使用装饰器TaskDecorator将父子线程变量进行复制,还有一种方式是transmittable-thread-local来共享线程上下文,这里不展开描述,后续会专门针对如何在微服务异步线程池中共享上线文进行说明。

复制

@Configurationpublic 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;/** * 邮件发送的线程池 * @return */@Bean("mailTaskExecutor")public Executor mailTaskExecutor(){ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();//最大线程数executor.setMaxPoolSize(maxPoolSize);//核心线程数executor.setCorePoolSize(corePoolSize);//任务队列的大小executor.setQueueCapacity(queueCapacity);//线程前缀名executor.setThreadNamePrefix(namePrefix);//线程存活时间executor.setKeepAliveSeconds(keepAliveSeconds);// 设置装饰器,父子线程共享request header变量executor.setTaskDecorator(new RequestHeaderTaskDecorator());/** * 拒绝处理策略 * CallerRunsPolicy():交由调用方线程运行,比如 main 线程。 * AbortPolicy():直接抛出异常。 * DiscardPolicy():直接丢弃。 * DiscardOldestPolicy():丢弃队列中最老的任务。 */executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());// 线程初始化executor.initialize();return executor;
    }
}
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

  • 15.

  • 16.

  • 17.

  • 18.

  • 19.

  • 20.

  • 21.

  • 22.

  • 23.

  • 24.

  • 25.

  • 26.

  • 27.

  • 28.

  • 29.

  • 30.

  • 31.

  • 32.

  • 33.

  • 34.

  • 35.

  • 36.

  • 37.

  • 38.

  • 39.

  • 40.

  • 41.

  • 42.

  • 43.

  • 44.

6、增加邮件发送结果的枚举类MailResultCodeEnum

复制

public enum MailResultCodeEnum {/** * 默认 */SUCCESS("success", "邮件发送成功"),/** * 自定义 */ERROR("error", "邮件发送失败");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;
    }
}
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

  • 15.

  • 16.

  • 17.

  • 18.

  • 19.

  • 20.

  • 21.

  • 22.

  • 23.

  • 24.

  • 25.

  • 26.

  • 27.

  • 28.

7、增加邮箱服务器相关默认配置的常量类JavaMailConstant.java

复制

public class JavaMailConstant {/** * Redis JavaMail配置config key */public static final String MAIL_CONFIG_KEY = "mail:config";/** * 当开启多租户模式时,Redis JavaMail配置config key */public static final String MAIL_TENANT_CONFIG_KEY = "mail:tenant:config:";
}
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

8、增加GitEggJavaMail自动装配类,根据Nacos或者系统配置进行装配。

复制

@Slf4j@Configuration@RequiredArgsConstructor(onConstructor_ = @Autowired)public class GitEggJavaMailConfiguration {private final JavaMailSenderImpl javaMailSenderImpl;    private final RedisTemplate redisTemplate;/** * 是否开启租户模式 */@Value("${tenant.enable}")private Boolean enable;   @Beanpublic JavaMailSenderFactory gitEggAuthRequestFactory() {return new JavaMailSenderFactory(redisTemplate, javaMailSenderImpl, enable);
    }
}
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

  • 15.

  • 16.

二、增加邮箱服务器配置界面

邮箱服务器的配置,实际就是不同邮箱渠道的配置,这里我们将表和字段设计好,然后使用GitEgg自带代码生成器,生成业务的CRUD代码即可。

1、邮箱渠道配置表设计

复制

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 '渠道名称',  `host` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'SMTP服务器地址',  `port` int(11) NULL DEFAULT NULL COMMENT 'SMTP服务器端口',  `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 '协议',  `default_encoding` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '默认编码',  `jndi_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '会话JNDI名称',  `properties` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'JavaMail 配置',  `channel_status` tinyint(2) NOT NULL DEFAULT 0 COMMENT '渠道状态 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 '创建时间',  `creator` bigint(20) NULL DEFAULT NULL COMMENT '创建者',  `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',  `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;
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

  • 15.

  • 16.

  • 17.

  • 18.

  • 19.

  • 20.

  • 21.

  • 22.

  • 23.

  • 24.

  • 25.

2、根据表设计,然后配置代码生成界面,生成前后端代码。

「SpringCloud」(四十三)多租户电子邮件发送系统设计与实现

3、生成代码后,进行相关权限配置,前端界面展示:

「SpringCloud」(四十三)多租户电子邮件发送系统设计与实现

三、以同样的方式增加邮箱模板配置界面和邮件发送日志记录

1、邮箱模板和邮件发送日志数据库表设计

邮件模板数据库表设计:

复制

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 '模板名称',  `sign_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '模板签名',  `template_status` tinyint(2) NOT NULL DEFAULT 1 COMMENT '模板状态',  `template_type` tinyint(2) NULL DEFAULT NULL COMMENT '模板类型',  `template_content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '模板内容',  `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 '发送次数限制',  `send_times_limit_period` bigint(20) NULL DEFAULT 0 COMMENT '限制时间间隔',  `send_times_limit_period_unit` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '限制时间间隔 单位',  `comments` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '描述',  `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',  `creator` bigint(20) NULL DEFAULT NULL COMMENT '创建者',  `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',  `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;
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

  • 15.

  • 16.

  • 17.

  • 18.

  • 19.

  • 20.

  • 21.

  • 22.

  • 23.

  • 24.

  • 25.

邮件日志数据库表设计:

复制

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 '发送人',  `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 '邮件内容',  `attachment_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '0' COMMENT '附件名称',  `attachment_size` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '0' COMMENT '附件大小',  `send_time` datetime(0) NULL DEFAULT NULL COMMENT '发送时间',  `send_result_code` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '1' COMMENT '发送结果码',  `send_result_msg` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '发送结果消息',  `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建日期',  `creator` bigint(20) NULL DEFAULT NULL COMMENT '创建者',  `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;
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

  • 15.

  • 16.

  • 17.

  • 18.

  • 19.

  • 20.

  • 21.

  • 22.

  • 23.

  • 24.

  • 25.

2、邮件模板和邮件发送日志界面

「SpringCloud」(四十三)多租户电子邮件发送系统设计与实现

「SpringCloud」(四十三)多租户电子邮件发送系统设计与实现

四、QQ邮箱配置和阿里云企业邮箱配置测试

上面的基本功能开发完成之后,那么我们就需要进行测试,这里选择两种类型的邮箱进行测试,一种是QQ邮箱,还有一种是阿里云企业邮箱。

1、QQ邮箱配置

QQ邮箱在配置的时候不能使用QQ的登录密码,需要单独设置QQ邮箱的授权码,下面是操作步骤:

  • 开通qq邮箱的smtp功能

「SpringCloud」(四十三)多租户电子邮件发送系统设计与实现

「SpringCloud」(四十三)多租户电子邮件发送系统设计与实现

「SpringCloud」(四十三)多租户电子邮件发送系统设计与实现

  • 经过一系列的验证之后,会获取到一个授权码:

  • 系统中配置QQ邮箱相关信息。

2、 阿里云企业邮箱配置

阿里云企业邮箱的配置相比较而言就简单一些,配置的密码就是企业邮箱登录的密码。

  • 账户设置,开启POP3/SMTP和IMAP/SMTP服务。

  • 系统中配置阿里云企业邮箱相关信息。

3、Nacos中配置默认邮件服务器,同时增加邮件异步线程池配置

复制

mail:username: XXXXXXXXXXXpassword: XXXXXXXXXXdefault-encoding: UTF-8host: smtp.mxhichina.comport: 25protocol: smtpproperties:      mail:smtp:          auth: true  ssl:enable: false
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

复制

# 异步发送邮件,核心线程池数配置
  mail-task:execution:      pool:core-size: 5max-size: 10queue-capacity: 5keep-alive: 60  thread-name-prefix: mail-send-task-
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

4、在邮件渠道配置界面进行邮件发送测试,有两种测试方式,一种是选择指定渠道进行发送,另外一种是选择系统默认渠道进行邮件发送。发送完成后查看邮件日志模块,检查是否有邮件发送成功的记录。

  • 选择需要测试的邮箱服务器

「SpringCloud」(四十三)多租户电子邮件发送系统设计与实现

  • 填写测试邮箱发送的内容

「SpringCloud」(四十三)多租户电子邮件发送系统设计与实现

  • 查看邮箱发送日志

「SpringCloud」(四十三)多租户电子邮件发送系统设计与实现

36    2022-07-08 08:07:14    Spring JavaMail