整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

SpringBoot系列-mail

SpringBoot系列-mail

 前言

  邮件是许多项目里都需要用到的功能,之前一直都是用JavaMail来发,现在Spring框架为使用JavaMailSender接口发送电子邮件提供了一个简单的抽象,Spring Boot为它提供了自动配置以及启动模块。springboot参考手册介绍:https://docs.spring.io/spring-boot/docs/2.1.0.RELEASE/reference/htmlsingle/#boot-features-email

  作为发送方,首先需要开启POP3/SMTP服务,登录邮箱后前往设置进行开启,开启后取得授权码。

  POP3 :
  POP3是Post Office Protocol 3的简称,即邮局协议的第3个版本,规定怎样将个人计算机连接到Internet的邮件服务器和下载电子邮件的电子协议。是因特网电子邮件的第一个离线协议标准,POP3允许用户从服务器上把邮件存储到本地主机(即自己的计算机)上,同时删除保存在邮件服务器上的邮件,而POP3服务器则是遵循POP3协议的接收邮件服务器,用来接收电子邮件的。
  

  SMTP:
  SMTP 的全称是“Simple Mail Transfer Protocol”,即简单邮件传输协议。是一组用于从源地址到目的地址传输邮件的规范,通过来控制邮件的中转方式。SMTP 协议属于 TCP/IP 协议簇,帮助每台计算机在发送或中转信件时找到下一个目的地。SMTP 服务器就是遵循 SMTP 协议的发送邮件服务器。


  代码编写

  maven引包,其中,邮件模板需要用到thymeleaf

        <!-- springboot mail -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
        </dependency>
        <!-- thymeleaf模板 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <!-- springboot web(MVC)-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- springboot -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>


  appliaction.propertise配置文件

#设置服务端口
server.port=10010

# Email (MailProperties)
spring.mail.default-encoding=UTF-8
spring.mail.host=smtp.qq.com
spring.mail.username=huanzi.qch@qq.com #发送方邮件名 
spring.mail.password=#授权码 
spring.mail.properties.mail.smtp.auth=true 
spring.mail.properties.mail.smtp.starttls.enable=true 
spring.mail.properties.mail.smtp.starttls.required=true


  SpringBootMailServiceImpl.java

@Service
class SpringBootMailServiceImpl implements SpringBootMailService {

    @Autowired
    private JavaMailSender mailSender;

    /**
     * 发送方
     */
    @Value("${spring.mail.username}")
    private String from;

    /**
     * 发送简单邮件
     *
     * @param to      接收方
     * @param subject 邮件主题
     * @param text    邮件内容
     */
    @Override
    public void sendSimpleMail(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);
    }

    /**
     * 发送HTML格式的邮件
     *
     * @param to      接收方
     * @param subject 邮件主题
     * @param content HTML格式的邮件内容
     * @throws MessagingException
     */
    @Override
    public void sendHtmlMail(String to, String subject, String content) throws MessagingException {
        MimeMessage message=mailSender.createMimeMessage();
        //true表示需要创建一个multipart message
        MimeMessageHelper helper=new MimeMessageHelper(message, true);
        helper.setFrom(from);
        helper.setTo(to);
        helper.setSubject(subject);
        helper.setText(content, true);

        mailSender.send(message);
    }

    /**
     * 发送HTML格式的邮件,并可以添加附件
     * @param to      接收方
     * @param subject 邮件主题
     * @param content HTML格式的邮件内容
     * @param files   附件
     * @throws MessagingException
     */
    @Override
    public void sendAttachmentsMail(String to, String subject, String content, List<File> files) 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);
        //添加附件
        for(File file : files){
            helper.addAttachment(file.getName(), new FileSystemResource(file));
        }

        mailSender.send(message);
    }
}


  测试controller

    @Autowired
    private SpringBootMailService springBootMailService;

    @Autowired
    private TemplateEngine templateEngine;

    @GetMapping("/index")
    public String index() throws MessagingException {
        //简单邮件
        springBootMailService.sendSimpleMail("1726639183@qq.com","Simple Mail","第一封简单邮件");

        //HTML格式邮件
        Context context=new Context();
        context.setVariable("username","我的小号");
        springBootMailService.sendHtmlMail("1726639183@qq.com","HTML Mail",templateEngine.process("mail/mail",context));

        //HTML格式邮件,带附件
        Context context2=new Context();
        context2.setVariable("username","我的小号(带附件)");
        ArrayList<File> files=new ArrayList<>();
        files.add(new File("C:\\Users\\Administrator\\Desktop\\上传测试.txt"));
        files.add(new File("C:\\Users\\Administrator\\Desktop\\上传测试2.txt"));
        springBootMailService.sendAttachmentsMail("1726639183@qq.com","Attachments Mail",templateEngine.process("mail/attachment",context2),files);

        return "hello springboot!";
    }


  两个html模板,路径:myspringboot\src\main\resources\templates\mail\

  mail.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Mail Templates</title>
</head>
<body>
    <h3><span th:text="${username}"></span>,你好!</h3>
    <p style="color: red;">这是一封HTML格式的邮件。</p>
</body>
</html>

  attachment.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Mail Templates Accessory</title>
</head>
<body>
    <h3><span th:text="${username}"></span>,你好!</h3>
    <p>这是一封HTML格式的邮件。请收下附件!</p>
</body>
</html>


  效果

  Simple Mail

  HTML Mail


  Attachments Mail



  后记

  本文章部分参考:https://www.cnblogs.com/yangtianle/p/8811732.html


  代码开源

  代码已经开源、托管到我的GitHub、码云:

  GitHub:https://github.com/huanzi-qch/springBoot

  码云:https://gitee.com/huanzi-qch/springBoot



版权声明

作者:huanzi-qch

出处:https://www.cnblogs.com/huanzi-qch

若标题中有“转载”字样,则本文版权归原作者所有。若无转载字样,本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利.

开启邮箱 SMTP 服务

发送邮件需要使用 SMTP 服务器,常用的免费服务器有:163、126、qq 等邮箱。

QQ 邮箱配置方式如下:

1) 登录 qq 邮箱,选择【设置】-【账户】

2) 在POP3/IMAP/SMAP/Exchage/CardDAV/CalDAV服务中,找到 POP3/SMTP 服务和 IMAP/SMTP 服务,点击开启。

163 邮箱配置方式如下:

1) 注册 163 邮箱,登录后设置。

2)在新页面点击 “客户端授权密码”,勾选 “开启”,弹出新窗口填写手机验证码。

3) 填写授权码

4) 提示开启成功。

2使用 python 发送邮件

使用 python 自带的模块:smptlib、email

import smtplib
from email.mime.text import MIMEText
from email.header import Header

1、发送普通的邮件

# 发送邮件的步骤
import smtplib
from email.mime.text import MIMEText     # 用来构造文本类型的邮件
from email.header import Header          # 用来构造邮件的头部
# 第一步:创建一个SMTP的对象
s=smtplib.SMTP()
# 第二步:连接到SMTP的服务器
host='smtp.163.com'    # 设置163邮箱服务器,端口为:25
port=25
#  host='smtp.qq.com'  port=465  # 设置qq邮箱服务器,端口为:465
s.connect(host,port)       # 连接服务器
# s.connect(host='smtp.163.com',port=25)
# 第三步:登录SMTP服务器
mail_user='18814726725@163.com'           # 163邮箱的用户名
mail_pass='password'                      # 注意:此处填写的是邮箱的SMTP服务器授权码
s.login(user=mail_user,password=mail_pass)
# 第四步:构建邮件内容
content='使用python测试发送邮件'             # 构建邮件内容
msg=MIMEText(content,_charset='utf8')     # _charset 指定编码格式
msg['Subject']=Header('测试报告','utf8')   # 邮件主题
msg['From']='wl18814726725@163.com'       # 发件人邮箱,可传入列表,用于给多个人发送文件
msg['To']='1572533878@qq.com'             # 收件人

# 第五步:发送邮件
s.sendmail(from_addr=msg['From'],to_addrs=msg['To'],msg=msg.as_string())     #将邮件内容转换为字符串

2、发送 HTML 格式邮件及附件

import smtplib
from email.mime.text import MIMEText     # 文本类型的邮件,用来构造邮件
from email.header import Header          # 用来构造邮件的头部
from email.mime.application import MIMEApplication   
from email.mime.multipart import MIMEMultipart  # 用来构造附件

# 发送邮件的步骤
# 第一步:创建一个SMTP的对象
s=smtplib.SMTP()
# 第二步:连接到SMTP的服务器
host='smtp.163.com'    # 设置163邮箱服务器,端口为:25
port=25
#  host='smtp.qq.com'    # 设置qq邮箱服务器,端口为:465
s.connect(host,port)   # 连接服务器
# 第三步:登录SMTP服务器
mail_user='wl18814726725@163.com'     # 163邮箱的用户名
mail_pass='wl987654321'               # 注意:此处填写的是邮箱的SMTP服务器授权码
s.login(user=mail_user,password=mail_pass)

# 构造文本邮件内容
content='使用python测试发送邮件'             # 构建邮件内容
textcontent=MIMEText(content,_charset='utf8')        # _charset 指定编码格式
# 构造附件(二进制字节流形式)
part=MIMEApplication(open("report.html",'rb').read(),_subtype=None) 
# part=MIMEApplication(open("report.html",'rb').read()) 需要查看_subtype=None 是否会引发异常
part.add_header('content-disposition', 'attachment', filename='report18.html')  # 对方收到邮件之后,附件在邮件中显示的名称
# 封装一封邮件
msg=MIMEMultipart()
# 加入文本内容
msg.attach(textcontent)
msg.attach(part)
# 发送邮件
msg['From']='wl18814726725@163.com'       #发件人邮箱
msg['To']='1572533878@qq.com'             #收件人

#第五步:发送邮件
s.sendmail(from_addr='wl18814726725@163.com',to_addrs='1572533878@qq.com',msg=msg.as_string())      # 将邮件内容转换为字符串

3、定义 send_email 函数

import smtplib
from email.mime.text import MIMEText     #文本类型的邮件,用来构造邮件
from email.header import Header          #用来构造邮件的头部
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart  #用来构造附件

def send_email(filepath):
    """
    :param filepath:   #传入报告文件的路径
    :return:
    """
    # 发送邮件的步骤
    # 第一步:创建一个SMTP的对象
    s=smtplib.SMTP()
    # 第二步:连接到SMTP的服务器
    host='smtp.163.com'    #设置163邮箱服务器,端口为:25
    port=25
    #  host='smtp.qq.com'    #设置qq邮箱服务器,端口为:465
    s.connect(host,port)   #连接服务器
    # 第三步:登录SMTP服务器
    mail_user='wl18814726725@163.com'     #163邮箱的用户名
    mail_pass='wl987654321'               #注意:此处填写的是邮箱的SMTP服务器授权码
    s.login(user=mail_user,password=mail_pass)

    #构造文本邮件内容
    content='使用python测试发送邮件'             #构建邮件内容
    textcontent=MIMEText(content,_charset='utf8')        #_charset 指定编码格式
    #构造附件(二进制字节流形式)
    part=MIMEApplication(open(filepath,'rb').read())
    part.add_header('content-disposition', 'attachment', filename='report988.html')  #对方收到邮件之后,附件在邮件中显示的名称
    # 封装一封邮件
    msg=MIMEMultipart()
    #加入附件和文本内容
    msg.attach(textcontent)
    msg.attach(part)
    #发送邮件
    msg['From']='wl18814726725@163.com'       #发件人邮箱
    msg['To']='1572533878@qq.com'             #收件人

    #第五步:发送邮件
    s.sendmail(from_addr=msg['From'],to_addrs=msg['To'],msg=msg.as_string())      #将邮件内容转换为字符串

send_email('report.html')

4、使用 python 发送邮件时常见错误:

错误 1:smtplib.SMTPAuthenticationError: (550, b'User has no permission') 。

我们使用 python 发送邮件时相当于自定义客户端根据用户名和密码登录,然后使用 SMTP 服务发送邮件,新注册的 163 邮箱是默认不开启客户端授权的(对指定的邮箱大师客户端默认开启),因此登录总是被拒绝,解决办法(以 163 邮箱为例):进入 163 邮箱 - 设置 - 客户端授权密码 - 开启(授权码是用于登录第三方邮件客户端的专用密码)。上述有专门的设置方法。

错误 2:smtplib.SMTPAuthenticationError: (535, b'Error: authentication failed') 。

以 163 邮箱为例,在开启 POP3/SMTP 服务,并开启客户端授权密码时会设置授权码,将这个授权码代替 smtplib.SMTP().login(user,password) 方法中的 password 即可。

错误 3:给多人发送邮件是,可能会出现 “AttributeError: 'list' object has no attribute 'encode'” 或者写了多个人,实际只给第一个人发了邮件等错误。

当我们在一个网站中进行注册账户成功后,通常会收到一封来自该网站的邮件。邮件中显示我们刚刚申请的账户和密码以及一些其他的广告信息。在上一篇中用Java实现了发送qq邮件的功能,今天我们来实现一个这样的功能,用户注册成功后,网站将用户的注册信息(账号和密码等)以Email的形式发送到用户的注册邮箱当中。

a、电子邮件协议

电子邮件在网络中传输和网页一样需要遵从特定的协议,常用的电子邮件协议包括 SMTP,POP3,IMAP。其中邮件的创建和发送只需要用到 SMTP协议,所以本文也只会涉及到SMTP协议。SMTP 是 Simple Mail Transfer Protocol 的简称,即简单邮件传输协议。

b、JavaMail

我们平时通过 Java 代码打开一个 http 网页链接时,通常可以使用已经对 http 协议封装好的 HttpURLConnection 类来快速地实现。Java 官方也提供了对电子邮件协议封装的 Java 类库,就是JavaMail,但并没有包含到标准的 JDK 中,需要我们自己去官方下载。

1、准备工作

需要两个jar包 activation.jar / mail.jar

所要用到的授权码:qq邮件登录 -> 设置 -> 账户


其中
SMTP是接收协议
POP3是接收协议

2、 编写实体类

 public class User {
    private String name;
    private String password;
    private String email;
    public User(String name, String password, String email) {
        this.name=name;
        this.password=password;
        this.email=email;
    }
    //省略get/set和toString方法...
}

3、编写静态页面

index.jsp:一个简单的表单 包含用户名、密码、邮箱

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>
  <form action="${pageContext.request.contextPath}/mail.do" method="post">
    用户名: <input type="text" name="username" value="账户">
    <br>
    密码: <input type="password" name="password" value="密码">
    <br>
    邮箱: <input type="text" name="email" value="邮箱">
    <br>
    <input type="submit" value="注册">
  </form>
  </body>
</html>

4、编写发送邮件的工具类

发送邮件的步骤

  • 1.创建定义整个应用程序所需的环境信息的sessio对象
  • 2.通过session得到transport对象
  • 3.使用邮箱的用户名和授权码连上邮件服务器
  • 4.创建邮件
  • 5.发送邮件

这里用到了多线程,因为发送邮件是需要时间去连接邮箱的服务器,若不使用多线程,则会卡在提交的网页中不断加载直至响应 使用多线程可以异步处理,提高用户的体验度

public class SendMail extends Thread {
    private String from="发件人邮箱";
    private String username="发件人用户名";
    private String password="授权码";
    private String host="smtp.qq.com"; //QQ邮箱的主机协议
    private User user;
    public SendMail(User user) {
        this.user=user;
    }
    public void run() {
        Transport ts=null;
        try {
            Properties prop=new Properties();
            prop.setProperty("mail.host",host);
            prop.setProperty("mail.transport.protocol","smtp");
            prop.setProperty("mail.smtp.auth","true");
            //关于QQ邮箱 还要设置SSL加密
            MailSSLSocketFactory sf=new MailSSLSocketFactory();
            sf.setTrustAllHosts(true);
            prop.put("mail.smtp.ssl.enable","true");
            prop.put("mail.smtp.ssl.socketFactory",sf);
            //使用JavaMail发送邮件的5个步骤
            //1.创建定义整个应用程序所需的环境信息的sessio对象
            Session session=Session.getDefaultInstance(prop, new Authenticator() {
                @Override
                protected PasswordAuthentication getPasswordAuthentication() {
                    return new PasswordAuthentication(username,password);
                }
            });
            session.setDebug(true);//开启debug模式 看到发送的运行状态
            //2.通过session得到transport对象
            ts=session.getTransport();
            //3.使用邮箱的用户名和授权码连上邮件服务器
            ts.connect(host,username,password);
            //4.创建纯文本的简单邮件
            MimeMessage message=new MimeMessage(session);
            message.setSubject("只包含文本的普通邮件");//邮件主题
            message.setFrom(new InternetAddress(from));// 发件人
            message.setRecipient(Message.RecipientType.TO,new InternetAddress(user.getEmail()));//收件人
            String info="注册成功!你的账号信息为: username=" + user.getName() + "password=" + user.getPassword();
            message.setContent("<h1 style='color: red'>" + info + "</h1>","text/html;charset=UTF-8");//邮件内容
            message.saveChanges();//保存设置
            //5.发送邮件
            ts.sendMessage(message,message.getAllRecipients());
        } catch (GeneralSecurityException e) {
            e.printStackTrace();
        } catch (MessagingException e) {
            e.printStackTrace();
        } finally {
            //关闭连接
            try {
                ts.close();
            } catch (MessagingException e) {
                e.printStackTrace();
            }
        }
    }
}

5、编写处理请求的Servlet以及注册Servlet

public class MailServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取前端数据
        String username=req.getParameter("username");
        String password=req.getParameter("password");
        String email=req.getParameter("email");
        //封装成一个User对象
        User user=new User(username,password,email);
        SendMail send=new SendMail(user);
        send.start();//启动线程
        req.setAttribute("message","已发送 请等待");
        req.getRequestDispatcher("info.jsp").forward(req,resp);//发送成功跳转到提示页面
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}


<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <servlet>
        <servlet-name>mail</servlet-name>
        <servlet-class>com.xiaoyao.servlet.MailServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>mail</servlet-name>
        <url-pattern>/mail.do</url-pattern>
    </servlet-mapping>
</web-app>

测试ok!

补充:

工作中我用的是JavaMail 1.6.2的版本遇到过以下这个问题

这个问题就是没有使用授权码引起的,需要去发件人邮箱设置开启授权码;

1、怎么获取授权码?

先进入设置,帐户页面找到入口,按照以下流程操作。

(1)点击“开启”

(2)验证密保

(3)获取授权码

总结:项目中可能会遇到的问题

1、使用JavaMail发送邮件时发现,将邮件发送到sina或者sohu的邮箱时,不一定能够马上收取得到邮件,总是有延迟,有时甚至会延迟很长的时间,甚至会被当成垃圾邮件来处理掉,或者干脆就拒绝接收,有时候为了看到邮件发送成功的效果

2、在执行到 message.saveChanges(); 方法报错无法进行保存设置,也有可能时你的mail版本较低造成的。

在书写 File file=new File(); 时注意修改正确的路径,也可以写在form表单里用file进行传值,主题和内容也写在了方法里因人而异如果其他需求可以需改参数进行传值。

3、在执行到 File file=new File(“D:\Chat_Software\sky.JPG”);时出现错误,之前写的是xlsx文件,测试期间可以对.xls,jpg,文本,.doc文件进行发送。发送xlsx文件时出现报错。 问题解决方案: .xls文件扩展名对应的是Microsoft Office EXCEL 2003及以前的版本。 .xlsx文件扩展名对应的是Microsoft Office EXCEL 2007及后期的版本。 有可能时你下载的mai不是1.6以上版本的,建议下载1.6以上版本的mail