• 邮件发送原理及实现



    学习视频来自于:秦疆(遇见狂神说)Bilibili地址
    他的自学网站:kuangstudy

    我们缺乏的不是知识,而是学而不厌的态度


    一、邮件发送原理

    1.1 接收发送过程

    在这里插入图片描述
    ①、用户A的电子邮箱为:xx@qq.com,通过邮件客户端软件写好一封邮件,交到QQ的邮件服务器,这一步使用的协议是SMTP,对应图示的①;

    ②、QQ邮箱会根据用户A发送的邮件进行解析,也就是根据收件地址判断是否是自己管辖的账户,如果收件地址也是QQ邮箱,那么会直接存放到自己的存储空间。这里我们假设收件地址不是QQ邮箱,而是163邮箱,那么QQ邮箱就会将邮件转发到163邮箱服务器,转发使用的协议也是SMTP,对应图示的②;
      
    ③、163邮箱服务器接收到QQ邮箱转发过来的邮件,也会判断收件地址是否是自己,发现是自己的账户,那么就会将QQ邮箱转发过来的邮件存放到自己的内部存储空间,对应图示的③;

    ④、用户A将邮件发送了之后,就会通知用户B去指定的邮箱收取邮件。用户B会通过邮件客户端软件先向163邮箱服务器请求,要求收取自己的邮件,对应图示的④;

    ⑤、163邮箱服务器收到用户B的请求后,会从自己的存储空间中取出B未收取的邮件,对应图示⑤;

    ⑥、163邮箱服务器取出用户B未收取的邮件后,将邮件发给用户B,对应图示的⑥;最后三步用户B收取邮件的过程,使用的协议是POP3;

    1.2 邮件服务器

    要在网络上实现邮件功能,必须要有专门的邮件服务器。

    电子邮箱(E-Mail地址)的获得需要在邮件服务器上进行申请。比如我们要使用QQ邮箱,就需要开通邮箱功能;

    ①、SMTP邮件服务器:用户替用户发送邮件和接收外面发送给本地用户的邮件,对应上图的第一、二步。它相当于现实生活中邮局的邮件接收部门(可接收普通用户要投出的邮件和其他邮局投递进来的邮件)。

    ②、POP3/IMAP邮件服务器:用户帮助用户读取SMTP邮件服务器接收进来的邮件,对应上图的第六步。它相当于专门为前来取包裹的用户提供服务的部门。

    1.3 邮件传输协议

    1. SMTP协议:全称为 Simple Mail Transfer Protocol,简单邮件传输协议。它定义了邮件客户端软件和SMTP邮件服务器之间,以及两台SMTP邮件服务器之间的通信规则。
    2. POP3协议:全称为 Post Office Protocol,邮局协议。它定义了邮件客户端软件和POP3邮件服务器的通信规则。
    3. IMAP协议:全称为 Internet Message Access Protocol,Internet消息访问协议,它是对POP3协议的一种扩展,也是定义了邮件客户端软件和IMAP邮件服务器的通信规则。

    二、Java邮件发送

    2.1 准备环境

    我们将用代码完成邮件的发送。这在实际项目中应用的非常广泛,比如注册需要发送邮件进行账号激活,再比如OA项目中利用邮件进行任务提醒等等。

    使用Java发送 E-mail 十分简单,但是首先你应该准备 JavaMail API 和Java Activation Framework 。
    得到两个jar包:
    1.mail.jar
    2.activation.jar

    
    <dependency>
        <groupId>javax.mailgroupId>
        <artifactId>mailartifactId>
        <version>1.4.7version>
    dependency>
    
    <dependency>
        <groupId>javax.activationgroupId>
        <artifactId>activationartifactId>
        <version>1.1.1version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2.2 介绍

    JavaMail 是sun公司(现以被甲骨文收购)为方便Java开发人员在应用程序中实现邮件发送和接收功能而提供的一套标准开发包,它支持一些常用的邮件协议,如前面所讲的SMTP,POP3,IMAP,还有MIME等。我们在使用JavaMail API 编写邮件时,无须考虑邮件的底层实现细节,只要调用JavaMail 开发包中相应的API类就可以了。

    我们可以先尝试发送一封简单的邮件,确保电脑可以连接网络。

    • 创建包含邮件服务器的网络连接信息的Session对象。
    • 创建代表邮件内容的Message对象
    • 创建Transport对象,连接服务器,发送Message,关闭连接
      主要有四个核心类,我们在编写程序时,记住这四个核心类,就很容易编写出Java邮件处理程序。

    在这里插入图片描述

    2.2.1 授权码

    需要发送邮件首先就要我们的邮箱账号支持POP3和SMTP协议,所以我们需要开启邮箱的POP3+SMTP服务,在邮箱设置–>账户–>下拉到开启服务,然后我们需要复制下图中的授权码,这个授权码就相当于你的QQ密码,你可以使用你的邮箱账号+授权码来发送邮件,而SMTP服务器也就是使用这个来识别你的身份的

    2.3 简单邮件

    2.3.1 引入

    import com.sun.mail.util.MailSSLSocketFactory;
    
    import javax.mail.*;
    import javax.mail.internet.InternetAddress;
    import javax.mail.internet.MimeMessage;
    import java.util.Properties;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2.3.2 步骤一:准备参数

    // 配置文件
    Properties prop = new Properties();
    prop.put("mail.host","smtp.qq.com");  //设置QQ邮件服务器
    prop.put("mail.transport.protocol","smtp"); // 邮件发送协议
    prop.put("mail.smtp.auth","true");// 需要验证用户名密码
    // 关于qq还需要设置ssl加密,加上以下代码
    MailSSLSocketFactory factory = new MailSSLSocketFactory();
    factory.setTrustAllHosts(true);
    prop.put("mail.smtp.ssl.enable","true");
    prop.put("mail.smtp.ssl.socketFactory",factory);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2.3.3 步骤二:获取session对象

    // 1、创建定义整个应用程序所需要的环境信息,session对象
    //使用QQ邮箱的时候才需要,其他邮箱不需要这一段代码
    Session session = Session.getDefaultInstance(prop, new Authenticator() {
        // 获取和SMTP服务器的连接对象
        public PasswordAuthentication getPasswordAuthentication(){
          return new PasswordAuthentication("用户邮箱","授权码");
        };
    });
    // 开启Session的debug模式,可以看见email的运行状态
    session.setDebug(true);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2.3.4 获取传输对象

    // 2、通过session得到transport对象
    // 通过这一次和SMTP服务器的连接对象获取发送邮件的传输对象
    Transport ts = session.getTransport();
    
    • 1
    • 2
    • 3

    2.3.5 登录授权

    // 3、使用邮箱的用户名和授权码连接上SMTP邮件服务器,
    ts.connect("用户邮箱","授权码");
    
    • 1
    • 2

    2.3.6 写邮件

    // 4、创建邮件对象MinmeMessage
    MimeMessage message = new MimeMessage(session);
    // 设置发件人邮箱地址
    message.setFrom(new InternetAddress("用户邮箱"));
    // 设置收件人类型,收件人邮箱地址
    message.setRecipient(Message.RecipientType.TO,new InternetAddress("收件人邮箱"));
    // 邮件的标题
    message.setSubject("唐人街探案");
    // 邮件的文本内容
    message.setContent("

    那一箱金子

    "
    ,"text/html;charset=UTF-8");
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2.3.7 发送邮件

    // 5、发送邮件(邮件信息,接收人信息)
    ts.sendMessage(message,message.getAllRecipients());
    
    • 1
    • 2

    2.3.8 关闭资源

    // 6. 关闭连接对象,即关闭服务器上的连接资源
    ts.close();
    
    • 1
    • 2

    2.4 复杂邮箱

    2.4.1 介绍

    复杂邮件就是非纯文本的邮件,可能还包含了图片和附件等资源

    MIME

    多用途互联网邮件扩展类型

    MimeBodyPart类

    ​ javax.mail.internet.MimeBodyPart类表示的是一个MIME消息,它和MimeMessage类一样都是从Part接口继承过来。即一个MIME消息对应

    一个MimeBodyPart对象,而MimeBodyPart对象就是我们写的邮件内容中的元素。

    MimeMultipart类

    javax.mail.internet.MimeMultipart是抽象类 Multipart的实现子类,它用来组合多个MIME消息。一个MimeMultipart对象可以包含多个代表

    MIME消息的MimeBodyPart对象。即一个MimeMultipart对象表示多个MimeBodyPart的集合,而一个MimeMultipart表示的就是我们一封邮件

    的内容

    MimeMultipart对象的使用的时候需要设置setSubType()的属性值,一共就下面3种取值

    setSubType()的属性值对象类型
    alternative表明这个MimeMultipart对象中的MimeMessage对象的数据是纯文本文件
    related表明这个MimeMultipart对象中的MimeMessage对象的数据包含非纯文本文件
    mixed表明这个MimeMultipart对象中的MimeMessage对象的数据包含附件

    我们在使得的时候如果不知道使用哪一个,直接使用mixed即可,使用这个属性值一定不会报错
    在这里插入图片描述

    2.4.2 步骤

    1. 准备一些参数
    2. 获取session对象
    3. 获取传输对象
    4. 登陆授权
    5. 写邮件 (和简单邮件相区别)
    6. 发送邮件
    7. 关闭服务器资源

    2.4.3 发送包含图片的复杂邮件

    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.util.Properties;
    
    // 发送带图片邮件
    public class ComplexMail {
        public static void main(String[] args) {
            ComplexMail mail = new ComplexMail();
            try {
                mail.mail();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        private void mail() 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);
    
            //1、创建定义整个应用程序所需的环境信息的 Session 对象
            //使用QQ邮箱的时候才需要,其他邮箱不需要这一段代码
            Session session = Session.getDefaultInstance(prop, new Authenticator() {//获取和SMTP服务器的连接对象
                public PasswordAuthentication getPasswordAuthentication() {
                    //发件人邮件用户名、授权码
                    return new PasswordAuthentication("XXXX@qq.com", "授权码");
                }
            });
            //开启Session的debug模式,这样就可以查看到程序发送Email的运行状态
            session.setDebug(true);
    
            //2、通过session得到transport对象
            Transport ts = session.getTransport();//通过这一次和SMTP服务器的连接对象获取发送邮件的传输对象
    
            //3、使用邮箱的用户名和授权码连上SMTP邮件服务器,即登陆
            ts.connect("smtp.qq.com", "XXXX@qq.com", "授权码");
    
            //4、创建邮件对象MimeMessage——点击网页上的写信
            //创建一个邮件对象
            MimeMessage message = new MimeMessage(session);
            //指明邮件的发件人——在网页上填写发件人
            message.setFrom(new InternetAddress("XXXX@qq.com"));//设置发件人
            //指明邮件的收件人,现在发件人和收件人是一样的,那就是自己给自己发——在网页上填写收件人
            message.setRecipient(Message.RecipientType.TO, new InternetAddress("XXXX@qq.com"));//设置收件人
            //邮件的标题——在网页上填写邮件标题
            message.setSubject("邮件发送实现");//设置邮件主题
    
            // ==========复杂邮件的邮件内容设置=========
    
            // 准备邮件数据
    
            // 准备图片数据
            MimeBodyPart image = new MimeBodyPart();// 获取一个图片的MimeBadyPart对象
            DataHandler dh = new DataHandler(new FileDataSource("C:\\Users\\85411\\Downloads\\b88f-kksmnwu1552426.jpg"));// 图片需要字符化才能传输,需要使用DataHandler对象
            image.setDataHandler(dh);//将图片序列化
            image.setContentID("bz.jpg");//为图片的MimeBodyPart对象设置一个ID,我们在文字中就可以使用他了
    
            // 准备正文数据
            MimeBodyPart text = new MimeBodyPart();
            // 设置文本内容,注意在里面嵌入了图片
            text.setContent("","text/html;charset=UTF-8");
    
            // 描述关系
            MimeMultipart mm = new MimeMultipart(); // 获取对象
            mm.addBodyPart(text);// 将文本包含其中
            mm.addBodyPart(image);// 将图片包含其中
            mm.setSubType("related"); // 设置MimeMultipart对象的相对属性为related,发送数据包含非纯文本文件+非附件资源
    
            // 设置到邮件对象中,保存修改
            message.setContent(mm);//将MimeMultipart放入消息对象中
            message.saveChanges();//保存上面修改
    
            //5、发送邮件——在网页上点击发送按钮
            ts.sendMessage(message, message.getAllRecipients());
            //6、关闭连接对象,即关闭服务器上的连接资源
            ts.close();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92

    2.4.4 发送包含图片、附件的复杂邮件

    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.util.Properties;
    
    public class ComplexFileMail {
        public static void main(String[] args) {
            ComplexFileMail mail = new ComplexFileMail();
            try {
                mail.mial();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    
        private void mial() 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);
    
            //1、创建定义整个应用程序所需的环境信息的 Session 对象
            //使用QQ邮箱的时候才需要,其他邮箱不需要这一段代码
            Session session = Session.getDefaultInstance(prop, new Authenticator() {//获取和SMTP服务器的连接对象
                public PasswordAuthentication getPasswordAuthentication() {
                    //发件人邮件用户名、授权码
                    return new PasswordAuthentication("XXXX@qq.com", "授权码");
                }
            });
            //开启Session的debug模式,这样就可以查看到程序发送Email的运行状态
            session.setDebug(true);
    
            //2、通过session得到transport对象
            Transport ts = session.getTransport();//通过这一次和SMTP服务器的连接对象获取发送邮件的传输对象
    
            //3、使用邮箱的用户名和授权码连上SMTP邮件服务器,即登陆
            ts.connect("smtp.qq.com", "XXXX@qq.com", "授权码");
    
            //4、创建邮件对象MimeMessage——点击网页上的写信
            //创建一个邮件对象
            MimeMessage message = new MimeMessage(session);
            //指明邮件的发件人——在网页上填写发件人
            message.setFrom(new InternetAddress("XXXX@qq.com"));//设置发件人
            //指明邮件的收件人,现在发件人和收件人是一样的,那就是自己给自己发——在网页上填写收件人
            message.setRecipient(Message.RecipientType.TO, new InternetAddress("XXXX@qq.com"));//设置收件人
            //邮件的标题——在网页上填写邮件标题
            message.setSubject("邮件发送实现");//设置邮件主题
            /*
            编写邮件内容
            1.图片
            2.附件
            3.文本
             */
            //图片
            MimeBodyPart image = new MimeBodyPart();// 获取一个图片的MimeBadyPart对象
            DataHandler dh = new DataHandler(new FileDataSource("C:\\Users\\85411\\Downloads\\b88f-kksmnwu1552426.jpg"));// 图片需要字符化才能传输,需要使用DataHandler对象
            image.setDataHandler(dh);//将图片序列化
            image.setContentID("bz.jpg");//为图片的MimeBodyPart对象设置一个ID,我们在文字中就可以使用他了
            //附件
            MimeBodyPart file = new MimeBodyPart();
            file.setDataHandler(new DataHandler(new FileDataSource("C:\\Users\\85411\\Downloads\\4fsaas.exe")));
            file.setFileName("4fsaas.exe");
            //文本
            MimeBodyPart text = new MimeBodyPart();
            text.setContent("

    文本测试

    "
    , "text/html;charset=utf-8"); // 拼接邮件内容 MimeMultipart email = new MimeMultipart(); email.addBodyPart(image); email.addBodyPart(text); email.setSubType("related");// 文本和图片内嵌成功! MimeBodyPart contentText = new MimeBodyPart(); contentText.setContent(email); // 拼接附件 MimeMultipart allFile = new MimeMultipart(); allFile.addBodyPart(file);//附件 allFile.addBodyPart(contentText);//正文 allFile.setSubType("mixed");//正文和附件都存在邮件中,所有类型设置为mixed; //设置到消息中,保存修改 message.setContent(allFile);// 将MimeMultipart放入消息对象中 message.saveChanges();// 保存上面的修改 //5、发送邮件——在网页上点击发送按钮 ts.sendMessage(message, message.getAllRecipients()); //6、关闭连接对象,即关闭服务器上的连接资源 ts.close(); } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
  • 相关阅读:
    web网页大作业——基于HTML+CSS+JavaScript制作摄影之家网站
    99年表示真干不过,部门新来的00后测试员已把我卷崩溃,想离职了...
    [ruby on rails]rails6.0升级6.1
    Spring Cloud Alibaba系列之nacos:(4)配置管理
    前端高度变化实现过渡动画
    pdf导出实例(itestpdf)
    Java:SpringBoot整合Spring Batch示例
    MOOC——多项式加法(5分)好难!
    高压差分探头导致的驱动电压离谱的原因
    【Django | 开发】面试招聘信息网站(划分面试官权限&集成钉钉消息)
  • 原文地址:https://blog.csdn.net/zhao854116434/article/details/125874086