重学Springboot系列之邮件发送的整合与使用

重学Springboot系列之邮件发送的整合与使用


基础协议及邮件配置整合

名词概念解释

  • 什么是POP3、SMTP和IMAP?

简单的说:POP3和IMAP是用来从服务器上下载邮件的。SMTP适用于发送或中转信件时找到下一个目的地。所以我们发送邮件应该使用SMTP协议。

  • 什么是免费邮箱客户端授权码功能?

邮箱客户端授权码是为了避免您的邮箱密码被盗后,盗号者通过客户端登录邮箱而独特设计的安防功能。可以理解为客户端授权码为邮件发送的二次密码。


整合邮件发送功能

引入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>

邮箱配置

QQ系邮箱配置

官方配置说明:参考官方帮助中心

获取客户端授权码:参考官方帮助中心

详细的配置如下:

spring:
  mail:
    host: smtp.qq.com #发送邮件服务器
    username: xx@qq.com #QQ邮箱
    password: xxxxxxxxxxx #客户端授权码
    protocol: smtp #发送邮件协议
    properties.mail.smtp.auth: true
    properties.mail.smtp.port: 465 #端口号465或587
    properties.mail.display.sendmail: Javen #可以任意
    properties.mail.display.sendname: Spring Boot Guide Email #可以任意
    properties.mail.smtp.starttls.enable: true
    properties.mail.smtp.starttls.required: true
    properties.mail.smtp.ssl.enable: true
    default-encoding: utf-8

说明:开启SSL时使用587端口时无法连接QQ邮件服务器


网易系(126/163/yeah)邮箱配置

网易邮箱客户端授码:参考官方帮助中心

客户端端口配置说明:参考官方帮助中心

详细的配置如下:

spring:
  mail:
    host: smtp.126.com
    username: xx@126.com
    password: xxxxxxxx
    protocol: smtp
    properties.mail.smtp.auth: true
    properties.mail.smtp.port: 994 #465或者994
    properties.mail.display.sendmail: Javen
    properties.mail.display.sendname: Spring Boot Guide Email
    properties.mail.smtp.starttls.enable: true
    properties.mail.smtp.starttls.required: true
    properties.mail.smtp.ssl.enable: true
    default-encoding: utf-8
    from: xx@126.com

特别说明:

  • 126邮箱SMTP服务器地址:smtp.126.com,端口号:465或者994
  • 163邮箱SMTP服务器地址:smtp.163.com,端口号:465或者994
  • yeah邮箱SMTP服务器地址:smtp.yeah.net,端口号:465或者994

有的邮件服务器接受使用客户端授权码发邮件,有的邮件服务器接受使用邮箱密码来发送邮件,所以password的配置不能一概而论。客户端授权码不行,就试试用邮箱密码;邮箱密码不行,就试试客户端授权码。


发送简单邮件

这里的简单邮件就是指邮件的内容只是普通文字的这种邮件。

@Service
public class MailService {
    @Resource
    private JavaMailSender mailSender;

    @Value("${spring.mail.username}")
    private String fromEmail;

    /**
     * 发送文本邮件
     */
    public void sendSimpleMail(String to, String subject, String content) {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setFrom(fromEmail);
        message.setTo(to);
        message.setSubject(subject);
        message.setText(content);
        mailSender.send(message);
    }

}

sendSimpleMail的三个参数依次是:邮件的发送目标,邮件的标题,邮件的内容。

测试代码:

//用配置文件的指定端口DEFINED_PORT作为启动端口运行测试用例
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
public class MailServiceTest {

    @Resource
    MailService mailService;

    @Test
    public void sendSimpleMail() {
        mailService.sendSimpleMail("431899405@qq.com",
                "普通文本邮件",
                "普通文本邮件内容测试");
    }
}

测试结果
重学Springboot系列之邮件发送的整合与使用


附录:QQ邮箱发邮件设置

1.开启SMTP服务

重学Springboot系列之邮件发送的整合与使用
2.在配置开启SMTP之后,会返回给我们一个客户端授权码。这个授权码就是上文中用来发邮件的password,所以记下来。

重学Springboot系列之邮件发送的整合与使用


发送html和基于模板的邮件

发送html邮件服务

sendHtmlMail函数的第一个参数是发送目标邮箱,第二个参数是邮件标题,第三个参数是邮件的正文(html)。

  • 上一节中发送普通的文本文件邮件,使用的是SimpleMailMessage
  • 下文代码中发送的正文是HTML的邮件,使用的是MimeMessage
/**
 * 发送html邮件
 */
public void sendHtmlMail(String to, String subject, String content) throws MessagingException {
    //注意这里使用的是MimeMessage
    MimeMessage message = mailSender.createMimeMessage();
    MimeMessageHelper helper = new MimeMessageHelper(message, true);
    helper.setFrom(fromEmail);
    helper.setTo(to);
    helper.setSubject(subject);
    //第二个参数是否是html,true表示发送的邮件正文是html文本
    helper.setText(content, true);

    mailSender.send(message);
}

测试用例,大家看到使用这种方式发送html邮件,我们将HTML以字符串拼接的方式写在Java代码里面,这样对于开发者而言非常的不友好。后文中我们会向大家介绍使用Java模板引擎来发送HTML邮件的方法,HTML书写更加友好。

@Test
public void sendHtmlMail() throws MessagingException {
    mailService.sendHtmlMail("431899405@qq.com","一封html测试邮件","<body style=\"text-align: center;margin-left: auto;margin-right: auto;\">\n"
            + " <div id=\"welcome\" style=\"text-align: center;position: absolute;\" >\n"
            +"      <h3>\"一封html测试邮件\"</h3>\n"
            +"      <span>http://www.zimug.com</span>"
            + "     <div style=\"text-align: center; padding: 10px\"><a style=\"text-decoration: none;\" href=\"https://zimug.com\" target=\"_bank\" >"
            + "           <strong>我很用心,希望你有所收获</strong></a></div>\n"
            + " </div>\n" + "</body>");
}

邮件发送成功截图
重学Springboot系列之邮件发送的整合与使用


基于freemarker模板的邮件

使用下面的方法发送邮件的前提是,你的项目里面已经正确的集成了freemarker模板引擎

重学Springboot系列之邮件发送的整合与使用

基于freemarker模板邮件本质上,还是发送html邮件,只不过是有一个把模板转换成html字符串的过程。

@Autowired
private FreeMarkerConfigurer freeMarkerConfigurer;

@Test
public void sendTemplateMail() throws IOException, TemplateException, MessagingException {
    //添加动态数据,替换模板里面的占位符
    List<ArticleVO> articles = new ArrayList<>();
    articles.add(new ArticleVO(1L,"dhy","spring boot1","内容一",new Date(),null));
    articles.add(new ArticleVO(2L,"xpy","spring boot2","内容二",new Date(),null));
    Template template = freeMarkerConfigurer.getConfiguration().getTemplate("freemarker-temp.html");
    //将模板文件及数据渲染完成之后,转换为html字符串
    Map<String,Object> model = new HashMap<>();
    model.put("articles",articles);
    String templateHtml = FreeMarkerTemplateUtils.processTemplateIntoString(template,model);

    //发送邮件
    mailService.sendHtmlMail("123456@qq.com","一封freemarker模板的html测试邮件",templateHtml);
}

模板文件freemarker-temp.html,使用freemarker语法编写,可以实现动态赋值。

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8" />
    <title>freemarker简单示例</title>
</head>
<body>
<h1>Hello Freemarker</h1>

<table class="">
    <tr>
        <td>作者</td>
        <td>教程名称</td>
        <td>内容</td>
    </tr>

<#list articles as article>
    <tr>
        <td>${article.author}</td>
        <td>${article.title}</td>
        <td>${article.content}</td>
    </tr>
</#list>

</table>
</body>
</html>

ArticleVO

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class ArticleVO {

    private Long id;
    private String author;
    private String title;
    private String content;
    private Date createTime;
    private List<Reader> reader;

}

thymeleaf也可以实现,不妨试一试。


发送带附件和内联附件邮件

发送带附件的邮件

/**
 * 发送带附件的邮件
 */
public void sendAttachmentsMail(String to, String subject, String content, String filePath) throws MessagingException {
    MimeMessage message = mailSender.createMimeMessage();
    //带附件第二个参数true
    MimeMessageHelper helper = new MimeMessageHelper(message, true);
    helper.setFrom(fromEmail);
    helper.setTo(to);
    helper.setSubject(subject);
    helper.setText(content, true);
    //添加附件资源
    FileSystemResource file = new FileSystemResource(new File(filePath));
    String fileName = filePath.substring(filePath.lastIndexOf(File.separator));
    helper.addAttachment(fileName, file);
    //发送邮件
    mailSender.send(message);
}

sendAttachmentsMail的第一个参数是发送目标邮箱,第二个参数是邮件的内容,第三个参数是邮件的附件。

运行如下的测试用例进行测试:

@Test
public void sendAttachmentsMailTest() throws MessagingException {
    String filePath = "D:\\courseview\\springboot\\template.png";
    mailService.sendAttachmentsMail("431899405@qq.com", 
                    "这是一封带附件的邮件", "邮件中有附件,请注意查收!", 
                    filePath);
}

邮件结果展示

重学Springboot系列之邮件发送的整合与使用


发送内联附件的邮件

所谓的内联附件就是附件文件在邮件正文内显示,通常是一图片资源。

重学Springboot系列之邮件发送的整合与使用

/**
 * 发送正文中有静态资源的邮件
 */
public void sendResourceMail(String to, String subject, String content, String rscPath, String rscId) throws MessagingException {
    MimeMessage message = mailSender.createMimeMessage();

    MimeMessageHelper helper = new MimeMessageHelper(message, true);
    helper.setFrom(fromEmail);
    helper.setTo(to);
    helper.setSubject(subject);
    helper.setText(content, true);
    //添加内联附件,指定一个资源id:rscId
    FileSystemResource res = new FileSystemResource(new File(rscPath));
    helper.addInline(rscId, res);

    mailSender.send(message);
}

sendResourceMail方法的参数说明:

[ ] 参数一:发送邮件的目标邮箱
[ ] 参数二:文件的标题
[ ] 参数三:邮件的正文:html(含图片资源id:rscId)
[ ] 参数四:图片资源文件本地磁盘路径res
[ ] 参数五:图片资源文件的资源Id:rscId

参数三HTML文本发现正文中包含<img src=cid: rscId>,就会根据参数五helper.addInline(rscId, res);,找到参数四对应的资源文件res,并渲染到HTML里面。

下面的代码是测试用例,执行之后看结果

@Test
public void sendResourceMail() throws MessagingException {
    String rscId = "dhy";
    String content = "<html><body>这是有图片的邮件<br/><img src=\'cid:" + rscId + "\' ></body></html>";
    String imgPath = "D:\\courseview\\springboot\\template.png";
    mailService.sendResourceMail("431899405@qq.com", 
                            "这邮件中含有图片", 
                            content,
                            imgPath, 
                            rscId);

}

邮件结果展示:

重学Springboot系列之邮件发送的整合与使用


可参考文章

Java邮件发送基于springboot实现

【SpringBoot总结】7. SpringBoot整合JavaMailSender实现邮件发送

手把手教你通过SpringBoot实现邮箱注册码验证


重学Springboot系列之邮件发送的整合与使用
注意连接超时的问题: 对应的邮箱不存在…

上一篇:狂神-邮件发送笔记


下一篇:使用python邮件加密:SSL加密: 端口号是465,通信过程加密,邮件数据安全02