Spring Boot 整合邮件发送实战:spring-boot-demo-email 模块全解析(文本 / HTML 模板 / 附件 / 静态资源四种邮件)

发布时间:2026/9/19 14:22:53
Spring Boot 整合邮件发送实战:spring-boot-demo-email 模块全解析(文本 / HTML 模板 / 附件 / 静态资源四种邮件) Spring Boot 整合邮件发送实战spring-boot-demo-email 模块全解析文本 / HTML 模板 / 附件 / 静态资源四种邮件【免费下载链接】spring-boot-demo一个用来深入学习并实战 Spring Boot 的项目。项目地址: https://gitcode.com/gh_mirrors/sp/spring-boot-demo本篇文章以 spring-boot-demo 仓库中的 demo-email 模块为主线完整讲解 Spring Boot 如何整合 JavaMail 发送邮件。该模块覆盖了生产环境中最常见的四种邮件形态简单文本邮件、HTML 邮件含 Thymeleaf 模板渲染与自定义模板目录、带附件邮件、正文内嵌静态资源图片邮件并引入 jasypt 对邮箱密码进行加密存储。阅读本文后你将掌握 Spring Boot 邮件发送的完整配置、JavaMailSender底层 API 的使用方法以及一套可直接复制到业务项目中的邮件服务封装方案。一、模块定位与整体架构demo-email是 spring-boot-demo 系列实战项目中的一个独立 Maven 模块其核心目标是演示Spring Boot 与 JavaMailSMTP的整合。模块结构非常清晰遵循接口 实现 测试的经典分层demo-email/ ├── pom.xml # 依赖管理 └── src/ ├── main/ │ ├── java/com/xkcoding/email/ │ │ ├── SpringBootDemoEmailApplication.java # 启动类 │ │ └── service/ │ │ ├── MailService.java # 邮件服务接口 │ │ └── impl/MailServiceImpl.java # 邮件服务实现 │ └── resources/ │ ├── application.yml # 邮件与 jasypt 配置 │ ├── templates/welcome.html # Thymeleaf 邮件模板默认目录 │ ├── email/test.html # 自定义目录下的邮件模板 │ └── static/xkcoding.png # 附件/静态资源测试图片 └── test/java/com/xkcoding/email/ ├── SpringBootDemoEmailApplicationTests.java # 上下文加载测试基类 ├── PasswordTest.java # jasypt 密码加解密测试 └── service/MailServiceTest.java # 四种邮件发送测试从整体调用链看业务方调用 MailService 接口由 MailServiceImpl 内部注入 Spring Boot 自动配置好的JavaMailSender完成实际发送邮件模板则由 Thymeleaf 的TemplateEngine渲染为 HTML 字符串后传入。启动类 SpringBootDemoEmailApplication 是一个标准的SpringBootApplication通过SpringApplication.run启动邮件相关 Bean 均由 Spring Boot 的自动配置机制装配。二、环境准备pom.xml 依赖解析模块的依赖声明位于 demo-email/pom.xml父工程为spring-boot-democom.xkcoding组织Java 版本 1.8。核心依赖及其作用如下依赖说明spring-boot-starter-mailSpring Boot 邮件官方 Starter内含 Spring 的spring-context-support与 JavaMail API自动配置JavaMailSender/JavaMailSenderImpljasypt-spring-boot-starter2.1.1配置文件加密组件用于对spring.mail.password进行ENC(...)加密存储与运行时解密spring-boot-starter-thymeleaf模板引擎用于渲染 HTML 邮件正文配合templateEngine.process(模板名, context)使用spring-boot-starter-testscopetest提供 JUnit、Spring Test 等测试基础设施hutool-all工具类库此处主要使用ArrayUtil.isNotEmpty判断抄送数组、ResourceUtil.getResource获取 classpath 资源dependencies !-- Spring Boot 邮件依赖 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-mail/artifactId /dependency !--jasypt配置文件加解密-- dependency groupIdcom.github.ulisesbocchio/groupId artifactIdjasypt-spring-boot-starter/artifactId version${jasypt.version}/version /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-test/artifactId scopetest/scope /dependency dependency groupIdcn.hutool/groupId artifactIdhutool-all/artifactId /dependency !-- Spring Boot 模板依赖 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-thymeleaf/artifactId /dependency /dependencies构建配置中设置了finalName为spring-boot-demo-email并引入spring-boot-maven-plugin用于打包可执行 Jar。三、核心配置application.yml 全参数解析邮件相关的全部配置集中在 demo-email/src/main/resources/application.ymlspring: mail: host: smtp.mxhichina.com port: 465 username: spring-boot-demoxkcoding.com # 使用 jasypt 加密密码使用com.xkcoding.email.PasswordTest.testGeneratePassword 生成加密密码替换 ENC(加密密码) password: ENC(OT0qGOpXrr1Iog1WfjOiIDCJdBjHyhy) protocol: smtp test-connection: true default-encoding: UTF-8 properties: mail.smtp.auth: true mail.smtp.starttls.enable: true mail.smtp.starttls.required: true mail.smtp.ssl.enable: true mail.display.sendmail: spring-boot-demo # 为 jasypt 配置解密秘钥 jasypt: encryptor: password: spring-boot-demo3.1 核心参数说明配置项示例值作用与注意点spring.mail.hostsmtp.mxhichina.comSMTP 服务器地址需根据邮件服务商替换如 QQ 邮箱smtp.qq.com、163 邮箱smtp.163.comspring.mail.port465SMTP 端口。465 对应 SSL 加密端口若走 STARTTLS 通常使用 587普通 25 端口常被云厂商封禁生产建议 465/587spring.mail.username邮箱账号发送方邮箱地址同时会被MailServiceImpl通过Value(${spring.mail.username})注入作为from发件人spring.mail.passwordENC(...)邮箱授权码或密码此处以 jasypt 加密密文形式给出运行时解密后再用于 SMTP 认证spring.mail.protocolsmtp邮件传输协议默认即 smtpspring.mail.test-connectiontrue是否在应用启动时调用JavaMailSenderImpl.testConnection()校验 SMTP 连接可用性。为true时若连接失败会直接导致启动失败便于尽早发现配置错误spring.mail.default-encodingUTF-8邮件内容的默认字符编码避免中文乱码3.2 properties 中的 SMTP 细节参数spring.mail.properties下的mail.smtp.*会被透传给 JavaMail 的Session属性直接影响与 SMTP 服务器的握手行为mail.smtp.auth: true开启 SMTP 认证发送前必须先登录绝大多数服务商强制要求mail.smtp.starttls.enable: true启用 STARTTLS允许在明文连接上升级为 TLS 加密通道mail.smtp.starttls.required: true强制要求服务器支持 STARTTLS否则拒绝连接mail.smtp.ssl.enable: true直接以 SSL 加密方式建立连接配合 465 端口使用。本示例同时开启了 SSL 与 STARTTLS 配置在实际使用时建议与端口匹配465 端口配ssl.enabletrue587 端口配starttls.enabletrue避免重复协商mail.display.sendmail: spring-boot-demo邮件头的显示名称X-Mailer等信息部分服务商用于标识发信应用。3.3 jasypt 解密密钥jasypt: encryptor: password: spring-boot-demojasypt-spring-boot-starter会在应用启动时读取jasypt.encryptor.password作为加解密密钥凡是配置文件中形如ENC(密文)的值都会被自动解密为明文后再注入到 Spring 环境中。注意该密钥属于安全敏感信息本示例为演示写在 yml 中生产环境建议通过环境变量、启动参数等方式注入避免明文入库。四、服务接口设计MailServiceMailService 定义了四种发送能力的统一接口所有方法都支持可变参数cc抄送地址可传多个或省略public interface MailService { /** * 发送文本邮件 * * param to 收件人地址 * param subject 邮件主题 * param content 邮件内容 * param cc 抄送地址 */ void sendSimpleMail(String to, String subject, String content, String... cc); /** * 发送HTML邮件 * * param to 收件人地址 * param subject 邮件主题 * param content 邮件内容 * param cc 抄送地址 * throws MessagingException 邮件发送异常 */ void sendHtmlMail(String to, String subject, String content, String... cc) throws MessagingException; /** * 发送带附件的邮件 * * param to 收件人地址 * param subject 邮件主题 * param content 邮件内容 * param filePath 附件地址 * param cc 抄送地址 * throws MessagingException 邮件发送异常 */ void sendAttachmentsMail(String to, String subject, String content, String filePath, String... cc) throws MessagingException; /** * 发送正文中有静态资源的邮件 * * param to 收件人地址 * param subject 邮件主题 * param content 邮件内容 * param rscPath 静态资源地址 * param rscId 静态资源id * param cc 抄送地址 * throws MessagingException 邮件发送异常 */ void sendResourceMail(String to, String subject, String content, String rscPath, String rscId, String... cc) throws MessagingException; }这种接口 实现的封装方式便于在业务中解耦上层只依赖MailService后续若更换邮件服务商或引入队列异步发送只需替换实现类。五、实现剖析MailServiceImpl 与 JavaMailSender 底层原理MailServiceImpl 是整个模块的核心它通过Autowired注入JavaMailSender并用Value(${spring.mail.username})注入发件人地址Service public class MailServiceImpl implements MailService { Autowired private JavaMailSender mailSender; Value(${spring.mail.username}) private String from; // ... 四种发送方法实现 }5.1 简单文本邮件SimpleMailMessageOverride public void sendSimpleMail(String to, String subject, String content, String... cc) { SimpleMailMessage message new SimpleMailMessage(); message.setFrom(from); message.setTo(to); message.setSubject(subject); message.setText(content); if (ArrayUtil.isNotEmpty(cc)) { message.setCc(cc); } mailSender.send(message); }SimpleMailMessage是 Spring 对纯文本邮件的轻量封装直接设置发件人、收件人、主题、正文后交由mailSender.send()发送。当cc非空时通过setCc(cc)批量设置抄送人可变参数天然支持多个抄送地址。5.2 HTML 邮件MimeMessage MimeMessageHelperOverride public void sendHtmlMail(String to, String subject, String content, String... cc) throws MessagingException { MimeMessage message mailSender.createMimeMessage(); MimeMessageHelper helper new MimeMessageHelper(message, true); helper.setFrom(from); helper.setTo(to); helper.setSubject(subject); helper.setText(content, true); if (ArrayUtil.isNotEmpty(cc)) { helper.setCc(cc); } mailSender.send(message); }HTML 邮件必须走 MIME 协议先通过mailSender.createMimeMessage()创建MimeMessage再以new MimeMessageHelper(message, true)包装——第二个参数true表示启用 multipart 模式这是后续支持 HTML 正文、附件和内嵌资源的前提。关键点是helper.setText(content, true)的第二个布尔参数true代表将正文按 HTML 解析渲染若传false则 HTML 标签会原样显示为文本。5.3 附件邮件addAttachmentOverride public void sendAttachmentsMail(String to, String subject, String content, String filePath, String... cc) throws MessagingException { MimeMessage message mailSender.createMimeMessage(); MimeMessageHelper helper new MimeMessageHelper(message, true); helper.setFrom(from); helper.setTo(to); helper.setSubject(subject); helper.setText(content, true); if (ArrayUtil.isNotEmpty(cc)) { helper.setCc(cc); } FileSystemResource file new FileSystemResource(new File(filePath)); String fileName filePath.substring(filePath.lastIndexOf(File.separator)); helper.addAttachment(fileName, file); mailSender.send(message); }附件通过helper.addAttachment(fileName, file)挂载。实现中有两个值得注意的细节FileSystemResource将本地文件路径包装为 Spring 的Resource抽象供邮件组件读取二进制流文件名取自filePath.substring(filePath.lastIndexOf(File.separator))即从路径最后一个/Linux或\Windows之后截取避免附件名带完整路径。这里的File.separator保证了跨平台兼容性。5.4 内嵌静态资源邮件addInline 与 cid 协议Override public void sendResourceMail(String to, String subject, String content, String rscPath, String rscId, String... cc) throws MessagingException { MimeMessage message mailSender.createMimeMessage(); MimeMessageHelper helper new MimeMessageHelper(message, true); helper.setFrom(from); helper.setTo(to); helper.setSubject(subject); helper.setText(content, true); if (ArrayUtil.isNotEmpty(cc)) { helper.setCc(cc); } FileSystemResource res new FileSystemResource(new File(rscPath)); helper.addInline(rscId, res); mailSender.send(message); }静态资源典型场景是邮件中的 logo、产品图通过helper.addInline(rscId, res)作为inline 附件嵌入 MIME 结构正文中通过cid:rscId引用img srccid:xkcoding /这种content-id 引用方式让图片随邮件一起发送收件人无需外网也能看到避免了引用外部 URL 时被邮件客户端拦截或图片失效的问题。测试用例sendResourceMail中的正文即为此用法见 MailServiceTest。六、密码安全jasypt 加解密实战邮件密码属于敏感凭据直接明文写在application.yml中有泄露风险。本模块通过 jasypt 将密码加密为ENC(...)密文。加密密码的生成方式见 PasswordTestpublic class PasswordTest extends SpringBootDemoEmailApplicationTests { Autowired private StringEncryptor encryptor; /** * 生成加密密码 */ Test public void testGeneratePassword() { // 你的邮箱密码 String password Just4Test!; // 加密后的密码(注意配置上去的时候需要加 ENC(加密密码)) String encryptPassword encryptor.encrypt(password); String decryptPassword encryptor.decrypt(encryptPassword); System.out.println(password password); System.out.println(encryptPassword encryptPassword); System.out.println(decryptPassword decryptPassword); } }运行该测试控制台会同时打印明文、encrypt()加密结果和decrypt()解密结果。将加密结果按ENC(加密密码)的格式替换到application.yml的spring.mail.password中即可。运行时 jasypt 依据jasypt.encryptor.password解密出真实密码再交给 JavaMail 做 SMTP 认证。加密算法默认使用 PBEWithMD5AndDES 等 jasypt 内置算法具体由jasypt-spring-boot-starter版本决定本项目固定版本为 2.1.1见 demo-email/pom.xml 中jasypt.version2.1.1/jasypt.version。七、模板化 HTML 邮件Thymeleaf 渲染7.1 默认模板目录templates/welcome.htmlspring-boot-starter-thymeleaf默认将classpath:/templates/作为模板根目录、.html作为后缀。邮件模板 welcome.html 位于该目录通过th:text绑定变量、th:href绑定链接div idwelcome h3欢迎使用 span th:text${project}/span - Powered By span th:text ${author}/span/h3 span th:text${url}/span div styletext-align: center; padding: 10px a styletext-decoration: none; href# th:href{${url}} target_bank strongspring-boot-demo入门Spring Boot的首选Demo:)/strong /a /div ... /div配合测试方法sendHtmlMail先用TemplateEngine渲染模板再发送Test public void sendHtmlMail() throws MessagingException { Context context new Context(); context.setVariable(project, Spring Boot Demo); context.setVariable(author, Yangkai.Shen); context.setVariable(url, https://github.com/xkcoding/spring-boot-demo); String emailTemplate templateEngine.process(welcome, context); mailService.sendHtmlMail(237497819qq.com, 这是一封模板HTML邮件, emailTemplate); }流程为创建 Thymeleaf 的Context→setVariable注入模板变量 →templateEngine.process(welcome, context)渲染出 HTML 字符串 → 交给sendHtmlMail发送。这样邮件正文与 Java 代码完全分离业务上修改活动邮件样式无需改动代码。7.2 自定义模板目录SpringResourceTemplateResolver当邮件模板不想放在默认的templates/目录时可通过SpringResourceTemplateResolver自定义前缀/后缀。测试方法sendHtmlMail2演示了这一点它指向classpath:/email/目录下的 test.htmlTest public void sendHtmlMail2() throws MessagingException { SpringResourceTemplateResolver templateResolver new SpringResourceTemplateResolver(); templateResolver.setApplicationContext(context); templateResolver.setCacheable(false); templateResolver.setPrefix(classpath:/email/); templateResolver.setSuffix(.html); templateEngine.setTemplateResolver(templateResolver); Context context new Context(); context.setVariable(project, Spring Boot Demo); context.setVariable(author, Yangkai.Shen); context.setVariable(url, https://github.com/xkcoding/spring-boot-demo); String emailTemplate templateEngine.process(test, context); mailService.sendHtmlMail(237497819qq.com, 这是一封模板HTML邮件, emailTemplate); }三个关键设置setApplicationContext(context)把 Spring 的ApplicationContext交给解析器使其能解析classpath:前缀资源setPrefix(classpath:/email/)与setSuffix(.html)将模板目录重定向到classpath:/email/此时process(test, context)实际渲染classpath:/email/test.htmlsetCacheable(false)关闭模板缓存便于开发期修改模板即时生效生产环境建议开启缓存提升性能。该目录下的 test.html 与welcome.html内容结构一致同样通过th:text渲染project、author、url三个变量。八、端到端验证测试用例总览测试基类 SpringBootDemoEmailApplicationTests 使用RunWith(SpringRunner.class) SpringBootTest加载完整 Spring 上下文。在其之上MailServiceTest 注入了MailService、Thymeleaf 的TemplateEngine以及ApplicationContext包含 5 个测试方法测试方法验证内容关键点sendSimpleMail简单文本邮件纯文本正文直接发送sendHtmlMail模板 HTML 邮件templateEngine.process(welcome, context)渲染默认目录模板sendHtmlMail2自定义模板目录SpringResourceTemplateResolver重定向到classpath:/email/sendAttachmentsMail附件邮件ResourceUtil.getResource(static/xkcoding.png)获取 classpath 内图片作为附件sendResourceMail静态资源邮件正文img srccid:xkcodinghelper.addInline(xkcoding, res)附件与静态资源测试均使用模块自带的 static/xkcoding.png100x100 像素作为测试素材通过 hutool 的ResourceUtil.getResource(static/xkcoding.png)从 classpath 定位文件绝对路径再传入发送方法。九、运行与使用流程克隆并进入模块在仓库根目录执行git clone后进入demo-email目录或直接在父工程spring-boot-demo下构建该模块修改配置编辑 application.yml将spring.mail.host、spring.mail.port、spring.mail.username替换为你自己的邮箱服务商参数生成加密密码运行PasswordTest.testGeneratePassword将输出结果按ENC(密文)格式写入spring.mail.password修改收件人将MailServiceTest各测试方法中的收件人地址237497819qq.com替换为实际测试邮箱执行测试运行mvn test或直接运行各Test方法即可收到对应的文本、HTML、附件与内嵌图片邮件。注意spring.mail.test-connection: true会在应用启动时校验 SMTP 连接若账号密码或端口配置有误启动阶段即会抛出MailAuthenticationException或连接异常可据此快速定位问题。十、技术要点回顾四种邮件形态的本质区别文本邮件用SimpleMailMessageHTML / 附件 / 内嵌资源都必须使用MimeMessage MimeMessageHelper(message, true)的 multipart 模式分别依赖setText(content, true)、addAttachment、addInline(rscId, res)内嵌图片用cid:协议helper.addInline(rscId, res)与正文img srccid:rscId一一对应实现图片随信发送密码安全jasypt 的ENC()密文 独立密钥避免明文凭据进仓库密钥本身在生成环境需独立保管模板与代码解耦Thymeleaf 支持默认templates/目录也支持通过SpringResourceTemplateResolver自由定制模板目录与缓存策略抄送批量支持四个接口方法的String... cc可变参数统一支持多抄送场景。如需深入阅读源码可从 MailService 与 MailServiceImpl 入手配合 MailServiceTest 五组测试用例对照学习本模块同时是 spring-boot-demo 仓库中邮件 模板引擎 配置加密组合使用的代表性示例。【免费下载链接】spring-boot-demo一个用来深入学习并实战 Spring Boot 的项目。项目地址: https://gitcode.com/gh_mirrors/sp/spring-boot-demo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考