1. SpringBoot邮件发送功能入门指南每次看到验证码邮件或者电商促销信息你有没有好奇过这些邮件是怎么自动发送的作为开发者我们经常需要实现邮件发送功能比如用户注册验证、订单通知、系统告警等场景。SpringBoot让这个原本复杂的任务变得异常简单今天我就带你从零开始手把手实现各种类型的邮件发送功能。先说说为什么选择SpringBoot来做邮件发送。传统的JavaMail API配置繁琐需要处理各种Session和Transport对象。而SpringBoot的starter-mail模块把这些复杂性都封装好了我们只需要关注核心业务逻辑。就像用微波炉热饭比用柴火灶方便多了SpringBoot让邮件发送变得一键式操作。我去年给公司电商系统改造邮件通知功能时原本用原生JavaMail API写了300多行代码换成SpringBoot后核心代码不到50行而且运行更稳定。这就像从手动挡汽车换成了自动驾驶省心又高效。2. 环境准备与基础配置2.1 项目依赖配置创建SpringBoot项目时记得勾选Spring Mail依赖。如果已经创建了项目也没关系手动添加以下依赖到pom.xmldependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-mail/artifactId /dependency我建议同时引入web和lombok依赖方便测试和简化代码dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency2.2 邮箱服务配置国内常用的是163和QQ邮箱我这里以163邮箱为例。首先需要开启SMTP服务并获取授权码登录163邮箱点击设置→POP3/SMTP/IMAP开启IMAP/SMTP服务按照提示发送短信验证后会获得一个16位的授权码不是邮箱密码在application.yml中配置spring: mail: host: smtp.163.com username: your_email163.com password: your_authorization_code default-encoding: UTF-8 properties: mail: smtp: auth: true starttls: enable: true required: true这里有个坑我踩过password要填授权码而不是邮箱密码我第一次配置时用了邮箱密码调试了半天才发现问题。3. 基础邮件发送实现3.1 文本邮件发送先实现最简单的纯文本邮件。创建一个EmailService类Service public class EmailService { Autowired private JavaMailSender mailSender; Value(${spring.mail.username}) private String from; public void sendSimpleEmail(String to, String subject, String text) { SimpleMailMessage message new SimpleMailMessage(); message.setFrom(from); message.setTo(to); message.setSubject(subject); message.setText(text); mailSender.send(message); } }调用方式emailService.sendSimpleEmail( recipientexample.com, 测试邮件主题, 这是一封简单的测试邮件内容 );我在实际项目中发现当收件人较多时比如群发通知使用setTo(String... to)方法比循环发送效率高很多。SpringBoot会智能地批量处理。3.2 HTML邮件发送想让邮件更美观试试HTML格式public void sendHtmlEmail(String to, String subject, String htmlContent) throws MessagingException { MimeMessage message mailSender.createMimeMessage(); MimeMessageHelper helper new MimeMessageHelper(message, true); helper.setFrom(from); helper.setTo(to); helper.setSubject(subject); helper.setText(htmlContent, true); // 关键第二个参数设为true mailSender.send(message); }HTML内容示例String html htmlbody h1 stylecolor:red促销通知/h1 p尊敬的客户您购买的商品正在特价/p ulli商品A - 5折/lili商品B - 7折/li/ul /body/html;注意HTML邮件容易被标记为垃圾邮件。建议遵循以下规则避免使用过多的红色字体图片与文字比例要平衡包含明确的退订链接4. 高级邮件功能实现4.1 带附件的邮件实现附件功能只需要在HTML邮件基础上增加几行代码public void sendEmailWithAttachment(String to, String subject, String text, MultipartFile attachment) throws MessagingException, IOException { MimeMessage message mailSender.createMimeMessage(); MimeMessageHelper helper new MimeMessageHelper(message, true); helper.setFrom(from); helper.setTo(to); helper.setSubject(subject); helper.setText(text); // 添加附件 helper.addAttachment( attachment.getOriginalFilename(), new ByteArrayResource(attachment.getBytes()) ); mailSender.send(message); }实际项目中我建议对附件大小做限制。曾经有同事试图发送100MB的附件导致邮件服务器崩溃。可以在方法开始处添加if(attachment.getSize() 10 * 1024 * 1024) { throw new IllegalArgumentException(附件大小不能超过10MB); }4.2 内嵌资源的邮件有些邮件需要在正文中显示图片这些图片不是作为附件而是直接显示在内容中public void sendEmailWithInlineImage(String to, String subject, String htmlContent, MultipartFile image) throws MessagingException, IOException { MimeMessage message mailSender.createMimeMessage(); MimeMessageHelper helper new MimeMessageHelper(message, true); helper.setFrom(from); helper.setTo(to); helper.setSubject(subject); // 替换HTML中的cid占位符 String finalHtml htmlContent.replace(${imageCid}, logo); helper.setText(finalHtml, true); // 添加内联图片 helper.addInline(logo, new ByteArrayResource(image.getBytes())); mailSender.send(message); }HTML模板示例html body h1欢迎加入我们/h1 img srccid:logo width200/ p感谢您注册我们的服务/p /body /html5. 生产环境最佳实践5.1 邮件发送的异常处理邮件发送可能会遇到各种异常网络问题、认证失败、被对方服务器拒绝等。完善的异常处理很重要public void sendEmailSafely(String to, String subject, String content) { try { sendSimpleEmail(to, subject, content); } catch (MailAuthenticationException e) { log.error(邮件认证失败请检查配置, e); // 可以触发告警通知管理员 } catch (MailSendException e) { log.error(邮件发送失败收件人{}, to, e); // 可以加入重试逻辑 } catch (MailException e) { log.error(邮件发送异常, e); } }我建议对重要邮件如验证码实现重试机制但要注意限制最大重试次数通常3次足够每次重试间隔逐渐增加指数退避记录失败原因便于排查5.2 性能优化建议当需要发送大量邮件时直接同步发送会导致性能问题。几种优化方案使用异步发送Async public void sendEmailAsync(String to, String subject, String content) { sendSimpleEmail(to, subject, content); }批量发送public void sendBatchEmails(ListString toList, String subject, String content) { SimpleMailMessage[] messages toList.stream() .map(to - { SimpleMailMessage message new SimpleMailMessage(); message.setTo(to); message.setSubject(subject); message.setText(content); return message; }) .toArray(SimpleMailMessage[]::new); mailSender.send(messages); }使用连接池在application.yml中配置spring: mail: properties: mail: smtp: connectiontimeout: 5000 timeout: 3000 writetimeout: 5000 pool: size: 5 wait: true6. 邮件模板与个性化6.1 使用Thymeleaf模板硬编码HTML在邮件内容中很难维护推荐使用模板引擎Autowired private TemplateEngine templateEngine; public void sendTemplateEmail(String to, String subject, MapString, Object model) throws MessagingException { MimeMessage message mailSender.createMimeMessage(); MimeMessageHelper helper new MimeMessageHelper(message, true); Context context new Context(); context.setVariables(model); String html templateEngine.process(email-template, context); helper.setFrom(from); helper.setTo(to); helper.setSubject(subject); helper.setText(html, true); mailSender.send(message); }模板文件resources/templates/email-template.html!DOCTYPE html html xmlns:thhttp://www.thymeleaf.org body h1 th:text${title}默认标题/h1 p亲爱的 span th:text${username}用户/span您好/p p th:text${content}默认内容/p /body /html6.2 个性化邮件内容通过模板变量实现个性化MapString, Object model new HashMap(); model.put(title, 专属优惠通知); model.put(username, 张先生); model.put(content, 您专属的优惠码是VIP2023); sendTemplateEmail(customerexample.com, 您的专属优惠, model);我在电商项目中统计发现个性化邮件的打开率比普通邮件高40%点击率高25%。但要注意隐私保护不要在邮件中泄露敏感信息。7. 邮件发送的监控与日志7.1 日志记录策略建议记录以下信息邮件发送时间发件人和收件人注意隐私可以只记录域名部分邮件主题发送状态成功/失败邮件大小和附件信息Slf4j Service public class EmailService { public void sendEmailWithLogging(String to, String subject, String content) { long startTime System.currentTimeMillis(); try { sendSimpleEmail(to, subject, content); long duration System.currentTimeMillis() - startTime; log.info(邮件发送成功 | 收件人: {} | 主题: {} | 耗时: {}ms, maskEmail(to), subject, duration); } catch (Exception e) { log.error(邮件发送失败 | 收件人: {} | 主题: {}, maskEmail(to), subject, e); } } private String maskEmail(String email) { // 只显示前面的前2个字符和域名保护隐私 int atIndex email.indexOf(); if(atIndex 2) { return email.substring(0, 2) *** email.substring(atIndex); } return *** email.substring(atIndex); } }7.2 监控指标重要的监控指标包括发送成功率平均发送耗时失败类型分布各时段发送量可以使用Spring Boot Actuator暴露这些指标或者集成监控系统如Prometheus。我在项目中配置的告警规则包括连续5分钟发送成功率低于90%平均发送耗时超过3秒同一IP被拒次数突然增加8. 安全注意事项8.1 防止邮件注入攻击直接拼接用户输入到邮件内容中存在安全风险。必须进行转义处理import org.springframework.web.util.HtmlUtils; public void sendSafeEmail(String to, String subject, String rawContent) { String safeContent HtmlUtils.htmlEscape(rawContent); sendSimpleEmail(to, subject, safeContent); }特别要注意转义HTML特殊字符验证邮件地址格式限制邮件主题长度8.2 敏感信息保护邮件传输不是完全安全的要注意不要在邮件正文中明文发送密码敏感附件应该加密使用TLS加密传输配置强制TLSspring: mail: properties: mail: smtp: starttls: enable: true required: true我在金融项目中还实现了邮件内容的自动脱敏处理比如识别并隐藏银行卡号、身份证号等敏感信息。