Loading... # 使用Spring Mail和FreeMarker发送HTML邮件 ## 引言 最近在写自己的博客项目,有收到新评论后发送邮件通知的功能,使用MQ通知服务,使用了没接触过的FreeMarker和JavaMail,记录一下实现过程,代码仓库:https://github.com/mashirot/MashiroBlog/tree/master/mail-service ## 实现 项目结构: ```text └─src └─main ├─kotlin │ └─ski │ └─mashiro │ │ MailServiceApplication.kt │ │ │ ├─annotation │ │ Slf4j.kt │ │ │ ├─config │ │ JacksonConfig.kt │ │ │ ├─constant │ │ RabbitMQConsts.kt │ │ │ ├─dto │ │ CommentMailDTO.kt │ │ │ ├─listener │ │ MailQueueListener.kt │ │ │ └─service │ │ MailService.kt │ │ │ └─impl │ MailServiceImpl.kt │ └─resources │ application.yml │ └─templates CommentAdvice.ftlh ``` ### 环境 `Springboot 3.1.2`,`JDK17`,`Kotlin 1.8.22` ### 依赖 ```kotlin dependencies { implementation("org.springframework.boot:spring-boot-starter-amqp") implementation("org.springframework.boot:spring-boot-starter-mail") implementation("org.springframework.boot:spring-boot-starter-freemarker") implementation("org.jetbrains.kotlin:kotlin-reflect") testImplementation("org.springframework.boot:spring-boot-starter-test") testImplementation("org.springframework.amqp:spring-rabbit-test") implementation("com.fasterxml.jackson.core:jackson-databind:2.15.2") implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.15.2") } ``` ### 代码 #### Jackson配置 ```kotlin /** * @author MashiroT */ @Configuration class JacksonConfig { @Bean fun objectMapper(): ObjectMapper { return ObjectMapper().registerModule(JavaTimeModule()) } } ``` #### @Slf4j注解 ```kotlin /** * @author MashiroT */ @Target(AnnotationTarget.CLASS) @Retention(AnnotationRetention.RUNTIME) annotation class Slf4j { companion object { val <reified T> T.log: Logger inline get() = LoggerFactory.getLogger(T::class.java) } } ``` #### MQ监听 ```kotlin /** * @author MashiroT */ @Component class MailQueueListener( val mailService: MailService ) { @RabbitListener(queues = [RabbitMQConsts.MAIL_QUEUE]) fun listenMailQueue(msg: String) { mailService.sendNewCommentAdvice2Owner(msg) } } ``` #### MailService ````kotlin /** * @author MashiroT */ @Service @Slf4j class MailServiceImpl( val objectMapper: ObjectMapper, val mailSender: JavaMailSender, val freeMakerConfiguration: Configuration, ) : MailService { @Value("\${blog.from}") private var from: String? = null @Value("\${blog.to}") private var to: String? = null override fun sendNewCommentAdvice2Owner(msg: String) { try { val commentMailDTO = objectMapper.readValue(msg, CommentMailDTO::class.java) // 使用MimeMessage发送复杂邮件,如无需求可使用MailSender配合SimpleMailMessage使用 val mimeMessage = mailSender.createMimeMessage() val mimeMessageHelper = MimeMessageHelper(mimeMessage, "utf-8") // 发送人邮箱 mimeMessageHelper.setFrom(from!!) // 收件人邮箱 mimeMessageHelper.setTo(to!!) val title = "你的帖子「${commentMailDTO.articleTitle}」有新回复" // 邮件主题 mimeMessageHelper.setSubject(title) val map = mapOf( "title" to title, "senderNickname" to commentMailDTO.senderNickname!!, "content" to if (commentMailDTO.content!!.length > 50) commentMailDTO.content.substring( 0, 50 ) else commentMailDTO.content ) // 获取Template模板,默认路径为classpath:/templates/ val template = freeMakerConfiguration.getTemplate("CommentAdvice.ftlh") // 传入参数并转为string val text = FreeMarkerTemplateUtils.processTemplateIntoString(template, map) // 邮件正文 mimeMessageHelper.setText(text, true) // 发送日期(不填默认当前) mimeMessageHelper.setSentDate(Date()) mailSender.send(mimeMessage) log.info("文章:${commentMailDTO.articleTitle} 收到新评论,已发送邮件通知") } catch (e: Exception) { e.printStackTrace() } } } ```` #### 配置 ```yaml mail: protocol: smtp host: smtp.office365.com port: 587 username: shiinamashiro@outlook.com password: sakurasou properties: mail: # debug: true smtp: starttls: enable: true # socks: # host: 127.0.0.1 # port: 7890 ``` ### 遇到的问题 #### SMTPSendFailedException: 501 5.1.7 Invalid address message的`from`属性设置错误,应为发送者邮箱 #### 451 5.7.3 STARTTLS is required to send mail Outlook的smtp使用starttls协议,在mail的配置中增加如下: ```yaml properties: mail: # debug: true smtp: starttls: enable: true ``` **参考文章** 1. [Java 发送邮件实现(JavaMail 和 Spring 实现)](https://blog.csdn.net/e_zxq/article/details/86525134) 2. [Spring Boot整合JavaMail实现邮件发送](https://zhuanlan.zhihu.com/p/343017891) 3. [Spring Boot + Freemarker 中的弯弯绕!](https://zhuanlan.zhihu.com/p/338940851) 4. [FreeMarker简单入门,这篇就够了](https://juejin.cn/post/7028216286576377893) 最后修改:2023 年 10 月 28 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 1 本作品采用 CC BY-NC-SA 4.0 International License 进行许可。