前言

发送邮件可以说是我们日常生活中最常见的应用了,比如我们注册账号时,官方会给我们注册的邮箱发送一封邮件,只要点击跳转就能进行相应的授权。今天我们以腾讯的QQ邮箱做一个简单的收发业务。

1. 开发准备

[1] 开发环境: IDEA 2019-3 (建立一个普通的java项目,当然maven项目也可以)

[2] 导入jar 包 (若是maven项目则直接导入依赖即可)

原java的普通项目中新建lib目录,并加入以下两个jar包

activation-1.1.1.jar

mail-1.4.7.jar

Java发送邮件显示表格 javaweb发送邮件_User


记得把该目录添加到 lib 依赖中

Java发送邮件显示表格 javaweb发送邮件_发送邮件_02


加入lib包后项目的目录为

Java发送邮件显示表格 javaweb发送邮件_Java发送邮件显示表格_03


[3] 查看QQ邮箱中是否开通了POP3/SMTP服务

点击设置–>账户 (往下拖动查看是否开通)

Java发送邮件显示表格 javaweb发送邮件_发送邮件_04


申请开通并获得授权码

Java发送邮件显示表格 javaweb发送邮件_java_05


若第二次登录忘记了授权码,可以重新获取

Java发送邮件显示表格 javaweb发送邮件_发送邮件_06


图中涂黑的部分就为你的授权码,虽然可以重新授权获取,不过一般还是不要轻易泄露,因为这样别人只要知道你的邮箱和授权码,就可以以你的名义发送邮件了

Java发送邮件显示表格 javaweb发送邮件_发送邮件_07

2. 进行业务开发

使用JavaMail发送邮件的5个步骤:
[1] 创建定义整个应用程序所需要的环境信息的Session对象
[2] .通过session得到transport对象
[3] 使用邮箱的用户名和授权码连上邮件服务器
[4] 创建邮件(需要传递session)
[5] 发送邮件
[6] 关闭连接

package com.gs;

import com.sun.mail.util.MailSSLSocketFactory;

import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import java.security.GeneralSecurityException;
import java.util.Properties;

/**
 * @Auther: Gs
 * @Date: 2020/6/4
 * @Description: com.gs
 * @version: 1.0
 */
//发送一封简单的邮件
public class MailDemo01 {

    public static void main(String[] args) throws Exception {

        Properties prop = new Properties();
        prop.setProperty("mail.host","smtp.qq.com"); //设置QQ邮件服务器
        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.创建定义整个应用程序所需要的环境信息的Session对象
        //(QQ才用,其他邮箱不用)
        Session session = Session.getDefaultInstance(prop, new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                //发件人邮件用户名,授权码(我们上面开通时获取的字符串)
                return new PasswordAuthentication("发件人的邮箱", "发件人的授权码");
            }
        });

        //开启Session的debug模式,这样就可以查看到程序发送Email的运行状态
        session.setDebug(true);

        // 2.通过session得到transport对象
        Transport ts = session.getTransport();
        // 3.使用邮箱的用户名和授权码连上邮件服务器
        ts.connect("smtp.qq.com","发件人邮箱","授权码");

        //4. 创建邮件(需要传递session)
        MimeMessage message = new MimeMessage(session);

        //指明邮件的发件人
        message.setFrom(new InternetAddress("发件人邮箱"));

        //指明邮件的收件人,现在收件人是一样的,那就是自己给自己发
        message.setRecipient(Message.RecipientType.TO, new InternetAddress("收件人邮箱"));

        //邮件的标题
        message.setSubject("欢迎来到我的CSDN博客");

        //邮件的文本内容(简单的邮件内容)====>这里对应我们普通文本的发送
       /* message.setContent("<h1 style='color:red'>你好,想睡觉了</h1>","text/html;charset=UTF-8");*/

        //准备图片数据 ======>这里对应我们图片的发送
        MimeBodyPart image = new MimeBodyPart();
        //图片要经过数据处理..... DataHandler: 数据处理
        DataHandler dh = new DataHandler(new FileDataSource("文件地址"));
        image.setDataHandler(dh); //在我们的Body中放入这个处理图片的数据
        image.setContentID("bz.jpg"); //给图片设置一个ID,我们在后面可以使用

        //准备正文数据
        MimeBodyPart text = new MimeBodyPart();
        text.setContent("这是一张带有图片<img src='cid:bz.jpg'>的邮件","text/html;charset=UTF-8");

        //描述数据关系
        MimeMultipart mm = new MimeMultipart();
        mm.addBodyPart(text);
        mm.addBodyPart(image);
        //这里根据类型设置发送时类型(默认为"multipart/mixed"这个类型最大,所以这里可以不进行设置)
        //related表示发送的内嵌有图片, mixed表示发送的带有附件
        mm.setSubType("related");

        //设置到消息中,保存修改
        message.setContent(mm); //把最后编辑好的邮件放到消息当中
        message.saveChanges();


        //5.发送邮件
        ts.sendMessage(message, message.getAllRecipients());

        //6.关闭连接
        ts.close();
        System.out.println("发送邮件成功");


    }
}

这里运行后,指定邮箱就会收到相应的邮件。

3. 模拟实现注册业务

基于上面我们已经了解了如何通过一个简单的java类实现发送邮件,那我们平时注册账号,它们又是如何给我们发送邮件的呢。这里我们进行一个简单的介绍。
[1] 开发准备:我们建立一个maven的web项目
[2] 导入我们上面的两个jar包依赖

<!-- https://mvnrepository.com/artifact/javax.activation/activation -->
<!--activation-1.1.1.jar-->
<dependency>
    <groupId>javax.activation</groupId>
    <artifactId>activation</artifactId>
    <version>1.1.1</version>
</dependency>
<!--javax.mail.mail-->
<!-- https://mvnrepository.com/artifact/javax.mail/mail -->
<dependency>
    <groupId>javax.mail</groupId>
    <artifactId>mail</artifactId>
    <version>1.4.7</version>
</dependency>

<!--这个lambok是为了方便我们开发pojo类-->
 <dependency>
      <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.12</version>
</dependency>

[3] 创建一个模拟注册的登录表单的jsp页面
这里我们提交给后端的/RegisterServlet.do进行处理,所以我们要进行相关的Servlet类的编写

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

[4] 创建一个User类(对前端的数据进行封装)
这里我们之所以可以不用写get,set方法。是因为我们使用了lambok组件,并用相关注解进行可该实体类的简化。

package com.gs.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

/**
 * @Auther: Gs
 * @Date: 2020/6/4
 * @Description: com.gs.pojo
 * @version: 1.0
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {

    private String username;
    private String password;
    private String email;


}

[5] 创建一个RegisterServlet类
这里所做的业务就是获取前端表单登录的用户信息进行封装成一个User类,再把这个User类放到我们封装好的Sendmail 类中进行邮件的发送(这个类和我们上面所写的发送邮件的逻辑时一样的);这里我们使用了一个多线程的思想,是因为我们发送邮件时可能需要很长的一段时间,这时我们不能让用户一直等待,而是应该开启一个线程去处理这个耗时的业务,然后主线程进行页面的跳转,让用户有一个更好的体验。

package com.gs.servlet;

import com.gs.pojo.User;
import com.gs.utils.Sendmail;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;


@WebServlet(name = "RegisterServlet")
public class RegisterServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String email = request.getParameter("email");


        User user = new User(username, password, email);
        //用户注册成功之后,给用户一封邮件
        //我们使用线程来专门发送邮件,防止耗时,和网站注册人数过多的情况
        Sendmail send = new Sendmail(user);
        //启动线程,线程启动之后就会执行run方法来发送邮件
        send.start();

        //注册用户
        request.setAttribute("message","注册成功,我们已经发了一封注册信息的电子邮件,请查收");
        request.getRequestDispatcher("info.jsp").forward(request,response);


    }

}

[6] 我们进行发送邮件时封装的一个工具类Sendmail

package com.gs.utils;

import com.gs.pojo.User;
import com.sun.mail.util.MailSSLSocketFactory;

import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import java.security.GeneralSecurityException;
import java.util.Properties;
/**
 * @Auther: Gs
 * @Date: 2020/6/4
 * @Description: com.gs.utils
 * @version: 1.0
 */
//网站3秒原则: 用户体验
//多线程实现用户体验 (异步处理)
public class Sendmail extends Thread {

    private User user;
    public Sendmail(User user){
        this.user = user;
    }

    @Override
    public void run() {


        Properties prop = new Properties();
        prop.setProperty("mail.host","smtp.qq.com"); //设置QQ邮件服务器
        prop.setProperty("mail.transport.protocol","smtp"); //邮件发送协议
        prop.setProperty("mail.smtp.auth","true"); //需要验证用户名和密码

        //关于QQ邮箱,还要设置SSL加密,加上以下代码
        MailSSLSocketFactory sf = null;
        try {
            sf = new MailSSLSocketFactory();
            sf.setTrustAllHosts(true);
            prop.put("mail.smtp.ssl.enable","true");
            prop.put("mail.smtp.ssl.socketFactory",sf);

            //使用JavaMail发送邮件的5个步骤

            // 1.创建定义整个应用程序所需要的环境信息的Session对象
            //(QQ才用,其他邮箱不用)
            Session session = Session.getDefaultInstance(prop, new Authenticator() {
                @Override
                protected PasswordAuthentication getPasswordAuthentication() {
                    //发件人邮件用户名,授权码
                    return new PasswordAuthentication("发件人邮箱", "发件人授权码");
                }
            });

            //开启Session的debug模式,这样就可以查看到程序发送Email的运行状态
            session.setDebug(true);

            // 2.通过session得到transport对象
            Transport ts = session.getTransport();
            // 3.使用邮箱的用户名和授权码连上邮件服务器
            ts.connect("smtp.qq.com","发件人邮箱","发件人授权码");

            //4. 创建邮件(需要传递session)
            MimeMessage message = new MimeMessage(session);

            //指明邮件的发件人
            message.setFrom(new InternetAddress("发件人邮箱"));

            //指明邮件的收件人,现在收件人是一样的,那就是自己给自己发
            message.setRecipient(Message.RecipientType.TO, new InternetAddress(user.getEmail()));

            //邮件的标题
            message.setSubject("用户注册邮件");

            //邮件的文本内容(简单的邮件内容)
            /* message.setContent("<h1 style='color:red'>你好,想睡觉了</h1>","text/html;charset=UTF-8");*/

            String info = "恭喜您注册成功,您的用户名:"+user.getUsername()+
                    ",您的密码:"+user.getPassword()+",请妥善保管,若有问题请咨询本网站";
            message.setContent(info,"text/html;charset=UTF-8");
            message.saveChanges();

            //5.发送邮件
            ts.sendMessage(message, message.getAllRecipients());

            //6.关闭连接
            ts.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
            System.out.println("发送邮件成功");
    }
}

[7] 记得在web.xml进行相关Servlet类的注册

<servlet>
    <servlet-name>RegisterServlet</servlet-name>
    <servlet-class>com.gs.servlet.RegisterServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>RegisterServlet</servlet-name>
    <url-pattern>/RegisterServlet.do</url-pattern>
</servlet-mapping>

[8] 编写响应给用户的info.jsp页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>xxxxx网站温馨提示</h1>
    ${message}
</body>
</html>

运行代码

Java发送邮件显示表格 javaweb发送邮件_发送邮件_08


输入注册信息后进行页面跳转

Java发送邮件显示表格 javaweb发送邮件_Java发送邮件显示表格_09


我们会收到一封相应的邮件

Java发送邮件显示表格 javaweb发送邮件_Java发送邮件显示表格_10

4. 使用SpringBoot实现简易的邮件发送

我们现在开发一个发送邮箱的业务根本不需要我们自己去拼接相关的邮件,boot已经帮我们把中简繁琐的步骤都做完了,我们唯一需要做的就是导入相关的邮件启动类,编写相关的配置类,以及邮件的主体内容就可以进行邮件发送的开发。

[1] 我们新建一个普通的Spring项目(这里我们使用一个空启动类,后期再在pom.xml进行添加)

Java发送邮件显示表格 javaweb发送邮件_Java发送邮件显示表格_11


[2] 在pom.xml中导入邮件的启动类

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

[3] 在application.properties中编写相关的配置信息

spring.mail.username= 邮箱
spring.mail.password= 授权码
spring.mail.host=smtp.qq.com
spring.mail.properties.mail.smtp.ssl.enable = true

[4] 进行发送邮件的业务开发

package com.gs.demo;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.mail.javamail.MimeMessagePreparator;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.File;

@SpringBootTest
class DemoApplicationTests {

	//Springboot为我们封装好的一个发送邮件的类
    @Autowired
    JavaMailSenderImpl javaMailSender;

	//进行简单邮件的发送测试
    @Test
    void contextLoads() {

        //发送邮件
        //收件人
        //内容
		//建立一个简单的信息类(这里只封装简单的文本信息)
        SimpleMailMessage message = new SimpleMailMessage();
        //设置主题
        message.setSubject("Hello Stephen GS");
        //设置文本信息
        message.setText("Hello World");

        message.setFrom("发件人邮箱");
        message.setTo("收件人邮箱");

		//发送邮件
        javaMailSender.send(message);

    }

	//进行复杂邮件(可以带有图片,附件)的发送测试
    @Test
    public void test2() throws Exception {
    	//新建一个复杂的邮件信息
        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        //通过一个辅助类对该邮件信息进行封装
        MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);

		//设置主题
        helper.setSubject("Hello Stephen GS");
        //设置文本内容
        helper.setText("<h1>Hello World</h1>",true);


        //附件(第一个参数为附件名,第二个文件路径)
        helper.addAttachment("1.jpg",new File(""));

        helper.setFrom("发件人邮箱");
        helper.setTo("收件人邮箱");

        javaMailSender.send((MimeMessagePreparator) helper);
    }

}

小结

随着框架技术的逐渐成熟,我们在开发这些之前看起来比较复杂的业务时,变的极其简单,但我们在便捷开发的同时,一定不能忘本,因为便捷封装的同时,底层的很多东西我们我们都不知道,只有循序渐进,才能真正做到知其然并知其所以然。