文章目录

  • 简介
  • 依赖导入
  • 配置
  • 核心类介绍
  • 申请邮箱授权码
  • 发送邮件示例
  • 发送简单文本邮件
  • 发送Html格式邮件
  • 发送带附件的邮件
  • 发送带静态资源的邮件
  • 发送模板邮件
  • 扩展
  • 自定义发件人名称
  • 发送多人、抄送、密送
  • 常见的错误返回码
  • 发送频率和次数限制
  • 企业邮箱发送邮件
  • 连接smtp.qq.com 25异常问题


简介

信息通知类功能,目前的实现有短信、邮件、钉钉等较为普遍,其中邮件功能成本最为低廉,消息存储溯源性高,常用于注册验证,忘记密码或者是给用户发送信息。

依赖导入

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

配置

对应类为:MailProperties.java

spring:
  #邮箱配置
  mail:
    host: smtp.qq.com
    username: xxxxxx@qq.com
    #QQ邮箱的授权码
    password: 
    #默认UTF-8
    #default-encoding: UTF-8
    properties:
      mail:
        smtp:
          auth: true
          starttls:
            enable: true
            required: true

也可以使用Java配置

@Bean
public JavaMailSender getJavaMailSender() {
    JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
    mailSender.setHost("smtp.gmail.com");
    mailSender.setPort(587);
    mailSender.setUsername("my.gmail@gmail.com");
    mailSender.setPassword("password");
    Properties props = mailSender.getJavaMailProperties();
    props.put("mail.transport.protocol", "smtp");
    props.put("mail.smtp.auth", "true");
    props.put("mail.smtp.starttls.enable", "true");
    props.put("mail.debug", "true");
    return mailSender;
}

配置文件的配置会覆盖Java配置

核心类介绍

  • MailSender:提供发送简单电子邮件的基本功能的顶级接口
  • JavaMailSender接口:上述MailSender的子接口。它支持 MIME 消息,并且主要与MimeMessageHelper类结合使用以创建MimeMessage。建议在此接口中使用MimeMessagePreparator机制。
  • JavaMailSenderImpl类: 提供了JavaMailSender接口的实现。它支持MimeMessageSimpleMailMessage
  • SimpleMailMessage类:用于创建简单的邮件消息,包括发件人、收件人、抄送、主题和文本字段
  • MimeMessagePreparator接口:提供了一个回调接口,用于准备 MIME 消息。
  • MimeMessageHelper类:用于创建 MIME 消息的帮助器类。它支持 HTML 布局中的图像、典型邮件附件和文本内容。

申请邮箱授权码

以QQ邮箱为例,申请流程如下:

QQ邮箱->设置->账户->POP3/SMTP服务:开启服务后会获得QQ的授权码

springboot搭建flink springboot搭建邮件服务器_springboot搭建flink

发送邮件示例

发送简单文本邮件

@Autowired
    JavaMailSender javaMailSender;

	public void sendSimpleMail() {
        try {
            SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
            simpleMailMessage .setFrom("发送方邮箱");
            simpleMailMessage .setTo("接收方");
            simpleMailMessage.setSubject("主题");
            simpleMailMessage.setText("内容");
            javaMailSender.send(simpleMailMessage);//发送
        } catch (Exception e) {
            logger.error("邮件发送失败", e.getMessage());
        }
    }

springboot搭建flink springboot搭建邮件服务器_html_02

发送Html格式邮件

public void sendHtmlMail() {
    try {
        MimeMessage mimeMailMessage = javaMailSender.createMimeMessage();
        //true表示需要创建一个multipart message
        MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMailMessage, true);
        mimeMessageHelper.setFrom("发送者邮箱");
        mimeMessageHelper.setTo("接收者邮箱");
        mimeMessageHelper.setSubject("主题");
        mimeMessageHelper.setText("<h1>hello</h1>", true);
        javaMailSender.send(mimeMailMessage);
        logger.info("html邮件发送成功");
    } catch (MessagingException e) {
        logger.error("发送html邮件时发生异常!", e);
    }
}

springboot搭建flink springboot搭建邮件服务器_springboot搭建flink_03

发送带附件的邮件

public void sendAttachmentMail() {
        try {
        	MimeMessage mimeMailMessage = javaMailSender.createMimeMessage();
        	MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMailMessage, true);
        	mimeMessageHelper.setFrom("发送者邮箱");
        	mimeMessageHelper.setTo("接收者邮箱");
        	mimeMessageHelper.setSubject("主题");
        	mimeMessageHelper.setText("<h1>hello</h1>", true);
        	//文件路径  spring的FileSystemResource,使用绝对路径访问文件资源
        	FileSystemResource file = new FileSystemResource(new File("src/main/resources/static/image/i.jpg"));
        	mimeMessageHelper.addAttachment("i.jpg", file);
        	javaMailSender.send(mimeMailMessage);
        } catch (Exception e) {
            logger.error("邮件发送失败", e.getMessage());
        }
    }

springboot搭建flink springboot搭建邮件服务器_springboot搭建flink_04

发送带静态资源的邮件

public void sendInlineMail() {
        try {
        	MimeMessage mimeMailMessage = javaMailSender.createMimeMessage();
        	MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMailMessage, true);
        	mimeMessageHelper.setFrom("发送者邮箱");
        	mimeMessageHelper.setTo("接收者邮箱");
        	mimeMessageHelper.setSubject("主题");
        	mimeMessageHelper.setText("<html><body>带静态资源的邮件内容,这个一张照片:<img src='cid:picture' /></body></html>", true);
       
        	//文件路径
        	FileSystemResource file = new FileSystemResource(new File("src/main/resources/static/image/i.jpg"));
        	mimeMessageHelper.addInline("picture", file);
        	javaMailSender.send(mimeMailMessage);
        } catch (Exception e) {
            logger.error("邮件发送失败", e.getMessage());
        }
    }

springboot搭建flink springboot搭建邮件服务器_spring boot_05

发送模板邮件

第一步:引入依赖

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

第二步:创建模板,在resources/templates下新建xxx.ftl

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <title>Title</title>
</head>
<body>
<div>
    <h2>邮件消息通知</h2>
    <table border="1">
        <tr>
            <th>工号</th>
            <th>工龄</th>
            <th>薪资</th>
        </tr>
        <tr>
            <td>${(jobNo)!""}</td>
            <td>${(jobAge)!""}</td>
            <td>${(salary)!""}</td>
        </tr>
    </table>
</div>
</body>
</html>

第三步:解析模板发送邮件

@Autowired
    JavaMailSender javaMailSender;
    @Autowired
    private FreeMarkerConfigurer freeMarkerConfigurer;
    @Value("${spring.mail.username}")
    String from;
    @Test
    public void sendTemplateMail() {
        try {
            MimeMessage mimeMailMessage = javaMailSender.createMimeMessage();
            String nick = "";
            try {
                nick = javax.mail.internet.MimeUtility.encodeText("laker测试");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            // 设置发件人
            MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMailMessage, true);
            mimeMessageHelper.setFrom(String.valueOf(new InternetAddress(from, nick)));
            mimeMessageHelper.setTo("xxxx@qq.com");
            mimeMessageHelper.setSubject("主题");
            Map<String, Object> model = new HashMap<>();
            model.put("jobNo", "30982");
            model.put("jobAge", "30");
            model.put("salary", "43800");
            Template template = freeMarkerConfigurer.getConfiguration().getTemplate("xxx.ftl");
            String text = FreeMarkerTemplateUtils.processTemplateIntoString(template, model);
            mimeMessageHelper.setText(text, true);
            javaMailSender.send(mimeMailMessage);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

springboot搭建flink springboot搭建邮件服务器_java_06

扩展

自定义发件人名称

String nick = "";
        try {
            nick = javax.mail.internet.MimeUtility.encodeText("张三");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        // 设置发件人
        simpleMailMessage.setFrom(String.valueOf(new InternetAddress("xxxxx@qq.com", nick)));

发送多人、抄送、密送

// 构建一个邮件对象
        SimpleMailMessage message = new SimpleMailMessage();
        // 设置邮件主题
        message.setSubject("这是一封测试邮件");
        // 设置邮件发送者,这个跟application.yml中设置的要一致
        message.setFrom("7*****9@qq.com");
        // 设置邮件接收者,可以有多个接收者,中间用逗号隔开,以下类似
      	// message.setTo("10*****16@qq.com","12****32*qq.com");
        message.setTo("10*****16@qq.com");
        // 设置邮件抄送人,可以有多个抄送人
        message.setCc("12****32*qq.com");
        // 设置隐秘抄送人,可以有多个
        message.setBcc("7******9@qq.com");
        // 设置邮件发送日期
        message.setSentDate(new Date());

常见的错误返回码

  • 421 HL:ICC 该IP同时并发连接数过大,超过了网易的限制,被临时禁止连接。
  • 451 Requested mail action not taken: too much fail authentication 登录失败次数过多,被临时禁止登录。请检查密码与帐号验证设置
  • 553 authentication is required,密码配置不正确
  • 554 DT:SPM 发送的邮件内容包含了未被许可的信息,或被系统识别为垃圾邮件。请检查是否有用户发送病毒或者垃圾邮件;
  • 550 Invalid User 请求的用户不存在
  • 554 MI:STC 发件人当天内累计邮件数量超过限制,当天不再接受该发件人的投信。如果使用一个邮箱频繁发送相同内容邮件,也会被认定为垃圾邮件,报 554 DT:SPM 错误
  • 501 Mail from address must be same as authorization user.发送者必须要和SMTP中的账号一致

message.setFrom(new InternetAddress(“xxx@qq.com”));
要与connect保持一致,connect中是xxx@qq.com,那么from中也必须是xxx@qq.com
connect(sender, password);// 密码为QQ邮箱开通的SMTP服务后得到的客户端授权码

发送频率和次数限制

注意发送过快过多会报535错误,建议每10秒发送一次或者没分钟一次

也可以改用企业邮箱,会好很多

企业邮箱发送邮件

mail:
  # 这个地方不一样
    host: smtp.exmail.qq.com
    username: xxxxx@qq.com
    # 企业邮箱这里是邮箱的登录密码,没有授权码了
    password: xxxx

连接smtp.qq.com 25异常问题

Caused by: com.sun.mail.util.MailConnectException: Couldn't connect to host, port: smtp.qq.com, 25; timeout -1
	at com.sun.mail.smtp.SMTPTransport.openServer(SMTPTransport.java:2210)
	at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:722)
	at javax.mail.Service.connect(Service.java:342)
	at org.springframework.mail.javamail.JavaMailSenderImpl.connectTransport(JavaMailSenderImpl.java:518)
	at org.springframework.mail.javamail.JavaMailSenderImpl.doSend(JavaMailSenderImpl.java:437)
	... 8 common frames omitted
Caused by: java.net.ConnectException: Connection timed out (Connection timed out)

在自己本地和公司服务器部署没问题,上到阿里云和腾讯云出现上面错误,有经过排查得知是:

  • 阿里云出于安全考虑默认禁用25端口导致发邮件失败

springboot搭建flink springboot搭建邮件服务器_html_07


解决方案

更改端口465ssl方式发送

spring:
  mail:
    host: smtp.qq.com
    port: 465
    username: 792750228@qq.com
    #QQ邮箱的授权码
    password: nybgwcppvgekbdjg
    #默认协议smtp
    #protocol: smtp
    #默认UTF-8
    #default-encoding: UTF-8
    properties:
      mail:
        smtp:
          socketFactory:
            port: 465
            class: javax.net.ssl.SSLSocketFactory
            fallback: false
          auth: true
          starttls:
            enable: true
            required: true