这个时候了,你还不会不知道JavaMail API吧

在这里插入图片描述

一、概述

1.1 简述

  JavaMail API 顾名思义,提供给开发者处理电子邮件相关的编程接口,它是Sun发布的用来处理email的API,其提供独立于平台且与协议无关的框架来构建邮件和消息传递应用。JavaMail API 提供了一组抽象类,用于定义组成邮件系统的对象,它是一个可选包(标准扩展),用于阅读,撰写和发送电子信息。

1.2 邮件协议

  JavaMail 提供了用于构造消息系统接口的元素,包括系统组件和接口。虽然本规范没有定义任何特定的实现,但 JavaMail 确实包含了几个实现 RFC822 和 MIME Internet 消息传递标准的类,这些类是作为 JavaMail 类包的一部分提供的。在收发邮件的过程中,需要遵守相关的协议,JavaMail并不是绝对支持每一个协议,其中主要有:

协议说明
SMTP单间邮件传输协议,用于发送电子邮件的传输协议
POP3用于接受电子邮件的标准协议
IMAP互联网消息协议,是POP3的替代协议

1.2.1 什么是SMTP?

  SMTP 全称为Simple Mail Transfer Protocol,即简单邮件传输协议,它是一组用于从源地址到目的地址传输邮件的规范,通过它来控制邮件的中转方式。SMTP 认证要求必须提供账号和密码才能登陆服务器,其设计目的在于避免用户受到垃圾邮件的侵扰。
  针对不同的的邮件协议,JavaMail规定了服务提供者必须支持一系列属性,下表是针对SMTP协议的一些常见属性。

名称类型描述
mail.smtp.userStringSMTP默认的登录用户名
mail.smtp.hostStringSMTP服务器地址,如smtp.sina.com.cn
mail.smtp.portintSMTP服务器端口号,默认为25
mail.smtp.fromString默认的邮件发送源地址
mail.smtp.authbooleanSMTP服务器是否需要用户认证,默认为false
mail.smtp.connectiontimeoutint套接字连接超时值,以毫秒为单位.默认为无限超时
mail.smtp.timeoutint套接字I/O超时值毫秒,默认为无限超时
mail.smtp.ssl.enableboolean如果设置为true,则默认情况下使用SSL连接并使用SSL端口。
对于"smtp"协议,默认为false;对于"smtps"协议,默认为true.

1.2.2 什么是IMAP?

  IMAP全称为 Internet Message Access Protocol,即互联网邮件访问协议,IMAP允许从邮件服务器上获取邮件的信息、下载邮件等。IMAP 与 POP 类似,都是一种邮件获取协议。针对不同的的邮件协议,JavaMail规定了服务提供者必须支持一系列属性,下表是针对IMAP协议的一些常见属性。

名称类型说明
mail.imap.userStringIMAP的默认用户名
mail.imap.hostString要连接的IMAP服务器
mail.imap.portint要连接的IMAP服务器端口,默认为143
mail.imap.connectiontimeoutint套接字连接超时值,以毫秒为单位.默认为无限超时
mail.imap.timeoutint套接字I/O超时值毫秒,默认为无限超时
mail.imap.statuscachetimeoutint缓存的超时值(以毫秒为单位),默认值为1000(1秒),零禁用缓存
mail.imap.appendbuffersizeint要缓冲的邮件的最大大小附加到IMAP文件夹时的内存
mail.imap.connectionpoolsizeint最大可用数量连接池中的连接,默认值为1
mail.imap.connectionpooltimeoutint连接池连接的超时值(以毫秒为单位),默认值为45000(45秒).
mail.imap.ssl.enableboolean如果设置如果为true,则默认使用SSL连接并使用SSL端口。
"imap"协议默认为false,"imaps"协议默认为true.

1.2.3 什么是POP3?

  POP3 全称为 Post Office Protocol 3,即邮局协议,POP3 支持客户端远程管理服务器端的邮件。POP3 常用于 离线 邮件处理,即允许客户端下载服务器邮件,然后服务器上的邮件将会被删除。目前很多 POP3 的邮件服务器只提供下载邮件功能,服务器本身并不删除邮件,这种属于改进版的 POP3 协议。
  IMAP 和 POP3 协议两者最大的区别在于,IMAP 允许双向通信,即在客户端的操作会反馈到服务器上,例如在客户端收取邮件、标记已读等操作,服务器会跟着同步这些操作。而对于 POP 协议虽然也允许客户端下载服务器邮件,但是在客户端的操作并不会同步到服务器上面的,例如在客户端收取或标记已读邮件,服务器不会同步这些操作。
  针对不同的的邮件协议,JavaMail规定了服务提供者必须支持一系列属性,下表是针对POP3协议的一些常见属性。

名称类型说明
mail.pop3.userStringPOP3的默认用户名
mail.pop3.hostString要连接的POP3服务器
mail.pop3.portint要连接的POP3服务器端口,默认为110
mail.pop3.connectiontimeoutint套接字连接超时值,以毫秒为单位,默认为无限超时
mail.pop3.timeoutint套接字I/O超时值毫秒,默认为无限超时
mail.pop3.ssl.enableboolean如果设置为true,则默认情况下使用SSL连接并使用SSL端口。
"pop3"协议默认为false,"pop3s"协议默认为true

1.3 API 环境设置

  开发人员使用 JavaMail 编写邮件程序时,不再需要考虑底层的通讯细节如:Socket,而是关注在逻辑层面。JavaMail可以发送各种复杂MIME格式的邮件内容,注意JavaMail仅支持JDK4及以上版本。虽然JavaMail是JDK的API但它并没有直接加入JDK中,所以我们需要另外添加依赖。

  • 使用javax.mail的坐标依赖包

    <!-- JavaMail基本包 -->
    <dependency>
        <groupId>javax.mail</groupId>
        <artifactId>mail</artifactId>
        <version>1.4.7</version>
    </dependency>
    <!-- 邮件发送的扩展包 -->
    <dependency>
        <groupId>javax.activation</groupId>
        <artifactId>activation</artifactId>
        <version>1.1.1</version>
    </dependency>
    
  • 使用com.sun.mail的坐标依赖包

    <!-- https://mvnrepository.com/artifact/com.sun.mail/javax.mail -->
    <!-- 使用Sun提供的Email工具包 -->
    <dependency>
        <groupId>com.sun.mail</groupId>
        <artifactId>javax.mail</artifactId>
        <version>x.y.z</version>
    </dependency>
    
  • 使用Jakarta Mail发送邮件

    <dependency>
        <groupId>com.sun.mail</groupId>
        <artifactId>jakarta.mail</artifactId>
        <version>x.y.z</version>
    </dependency>
    

个人推荐使用 javax.JavaMail 方式。

二、JavaMail 的关键对象

  JavaMail 对收发邮件进行了高级的抽象,形成了一些关键的的接口和类,它们构成了程序的基础,JavaMail API 包含一些用于发送、读取和删除电子邮件的接口和类。虽然 JavaMail API 中有许多软件包,但它们将涵盖 JavaMail API 中经常使用的两个主要软件包:javax.mailjavax.mail.internet 软件包,这些包包含所有JavaMail核心类,它们是:

Class说明
javax.mail.SessionAPI的关键类,多线程对象表示连接工厂
javax.mail.Message为电子邮件建模的抽象类,子类提供实际的实现
javax.mail.Address抽象类,用于对消息中的地址进行建模,子类提供特定的实现
javax.mail.Authenticator用于保护邮件服务器上邮件资源的抽象类
javax.mail.Transport抽象类,它模拟用于发送电子邮件的邮件传输机制
javax.mail.Store为消息存储建模的抽象类及其访问协议,用于存储和检索消息
javax.mail.Folder表示邮件消息文件夹的抽象类,它可以包含子文件夹

2.1 Properties

  由于 JavaMail 需要和邮件服务器进行通信,这就要求程序提供许多诸如服务器地址、端口、用户名、密码等信息,JavaMail通过Properties对象封装这些属性西信息。如下面的代码封装了两个属性信息:

Properties properties = new Properties();
props.put("mail.smtp.host", "smtp.sina.com");
props.put("mail.smtp.auth", "true");

  针对不同的的邮件协议,JavaMail规定了服务提供者必须支持一系列属性。

2.1 Session 类

  javax.mail.Session 类定义了一个基本邮件会话(session)的主要类,用于定义整个应用程序所需的环境信息,以及客户端与邮件服务器建立网络连接的会话信息。它不创建子类,但所有其它类都是经由这个 session 才得以生效。Session 对象用 Java.util.Properties 对象接收各种配置属性信息,例如邮件服务器的主机名、端口号、采用的邮件发送和接收协议等,根据这些信息构建用于邮件收发的 Transport 和 Store 对象,以及为客户端创建 Message 对象时提供信息支持。
  Session通过JavaMail配置文件以及程序中设置的Properties对象构建一个邮件处理环境,后续的处理将在Session基础上进行。Session拥有多个静态工厂方法用于创建Session实例,如下所示:

/**
 * 当JVM中已经存在默认的Session实例中,直接返回这个实例,否则创建一个新的Session实例,并将其作为JVM中默认Session实例
 */
public static Session getDefaultInstance(Properties props)

    /**
 * 返回JVM中默认的Session实例,如果第一次创建Session未指定Authenticator入参,后续调用可以使用该访问获取Session
 */
public static Session getDefaultInstance(Properties props,Authenticator authenticator)

/**
 * 根据相关属性创建一个新的Session实例,未使用安全认证信息
 */
public static Session getInstance(Properties props)

/**
 * 创建一个新的Session实例,它不会在JVM中被作为默认实例共享
 */
public static Session getInstance(Properties props,Authenticator authenticator)

  Session 是 JavaMail 提供者配置文件以及设置属性信息的“容器”,Session 本身不会和邮件服务器进行任何的通信。所以在一般情况下,我们仅需要通过getDefaultInstance() 获取一个共享的 Session 实例就可以了,下面的代码创建了一个Session实例:

Properties props = System.getProperties();
props.setProperty("mail.transport.protocol", "smtp");
……
Session session = Session.getDefaultInstance(props);

2.2 Message 类

  javax.mail.Message 类是创建和解析邮件的核心API,一旦获得Session对象,就可以继续创建要发送的消息,这由 Message 类来完成。这是一个抽象类,通常使用它的子类 javax.mail.internet.MimeMessage 类。客户端程序发送邮件时,首先使用创建邮件的 JavaMail API 创建出封装了邮件数据的 Message 对象,然后把这个对象传递给邮件发送API——Transport 类进行发送。客户端程序接收邮件时,邮件接收API把接收到的邮件数据封装在Message 类的实例中,客户端程序在使用邮件解析API从这个对象中解析收到的邮件数据。
  为了建立一个MimeMessage对象,我们必须将Session对象作为MimeMessage构造方法的参数传入:

// 通过session对象来创建一个MimeMessage对象
MimeMessage message=new MimeMessage(session);

  message 对象一旦创建,就需要填充一些信息。Meesage类实现了 javax.mail.Part 接口,而MimeMessage类实现了 javax.mail.internet.MimePart 接口,如下表所示:

方法描述
void setFrom(Address address)用于设置发送者的邮件地址
void addRecipient(Message.RecipientType type,String address)设置邮件的收件人、抄送人、密送人(通过type区分)
void addRecipients(Message.RecipientType type,Address[] addresses)设置邮件的多个收件人、抄送人、密送人(通过type区分)
void setSubject(String subject)设置邮件标题
void setText(String textmessage)如果邮件内容是纯文本,可以使用此接口设置文本内容。
void setContent(Object obj,String type)设置邮件内容,通过 type 指定类型。
纯文本:“text/plain”,html格式:text/html;charset=UTF-8

2.3 Address 类

  一旦创建了Session和Message,并将内容填入消息后,需要通过 Address 来设置信件的地址信息。由于 Address 是个抽象类,因此大多数是使用它的实现类 javax.mial.internet.InternetAddress

// 若地址只包含电子邮件地址,直接通过一个邮箱地址来创建
Address address = new InternetAddress("dllwhcrawler@sina.com");

// 也可以通过邮箱地址和邮寄人姓名来创建
Address address = new InternetAddress("dllwhcrawler@sina.com", "dllwhcrawler");

一旦创建了 address,将它们与消息连接的方法有两种。如果要识别发件人,您可以用 setFrom() 方法。

message.setFrom(address);

// 需要消息显示多个 from 地址,可以使用 addFrom() 方法
Address[] address;
message.addFrom(address);

  为了设置收信人,我们使用addRecipient()方法增加收件人,此方法需要使用 Message.RecipientType 的常量来区分收信人的类型:

message.addRecipient(type, address)

  下面是Message.RecipientType的三个常量:

public static class RecipientType implements Serializable {
	/**
	 * 收信人
	 */
	public static final RecipientType TO = new RecipientType("To");
	/**
	 * 抄送
	 */
	public static final RecipientType CC = new RecipientType("Cc");
	/**
	 * 私密抄送
	 */
	public static final RecipientType BCC = new RecipientType("Bcc");
}

2.4 Authenticator 类

  JavaMail API 利用 Authenticator 通过用户名和密码访问受保护的资源。对于JavaMail API 来说,这些资源就是邮件服务器。Authenticator 位于 javax.mail 包中,代表一个知道如何获得网络连接认证的对象,是个抽象类,通过创建它的子类 PasswordAuthentication,从 getPasswordAuthentication() 方法中返回 PasswordAuthentication 实例。创建完成后,必需向 session 注册 Authenticator。

Properties props = new Properties();
Authenticator auth = new Authenticator() {
  	@Override
  	public PasswordAuthentication getPasswordAuthentication() {
    	return new PasswordAuthentication("发件人邮箱名", "SDFA授权码");
  	}
};
Session session = Session.getDefaultInstance(props, auth);

2.5 Transport 类

  javax.mail.Transport 是 发送邮件的核心API 类,它的实例对象代表实现了某个邮件发送协议的邮件发送对象,通常使用SMTP协议来发送消息。客户端程序创建好 Message 对象后,只需要使用邮件发送API 得到 Transport 对象,然后把 Message 对象传递给 Transport 对象,并调用它的发送方法,就可以把邮件发送给指定的 SMTP 服务器。

Transport.send(message);

  指定stmp协议和transport类型后,Session就会使用com.sun.mail.smtp.SMTPTransport实现类创建一个Transport实例,Transport 将根据 Session 中Properties 属性设置情况进行工作,属性包括:

属性名说明
mail.transport.protocol默认的邮件传输协议,例如,smtp
mail.host默认的邮件服务地址,例如:smtp.sina.com
mail.user默认的登陆用户名,例如:dllwhcrawler@sina.com
mail.port默认的邮件服务端口

  发送消息的另一种方法是通过从会话的协议得到一个特定的实例,传递下去的用户名和密码(空白,如果不必要的),发送消息,并关闭连接。

// 当Session实例设置了mail.transport.protocol属性时,通过  getTransport() 获取对应的Transport实例
// 如果Session没有设置mail.transport.protocol属性,可以通过该方法返回指定类型的Transport
Transport transport = session.getTransport("smtp");
// smtp验证,就是用来发邮件的邮箱用户名密码(若在之前的properties中指定默认值,这里可以不用再次设置)
transport.connect(host, username, password);
// 发送邮件
transport.sendMessage(message, message.getAllRecipients());
transport.close();

  这种方法在发送多条消息时最好,因为它能保持邮件服务器在消息间的活动状态,基本 send() 机制为每个方法的调用设置与服务器独立的连接。

  • 注意:要观察传到邮件服务器上的邮件命令,请用 session.setDebug(true) 设置调试标志。

2.6 Store 类

  javax.mail.Store 是 接收邮件的核心 API 类,它的实例对象代表实现了某个邮件接收协议的邮件接收对象,用来存储和查询消息。客户端程序接收邮件时,只需要使用邮件接收 API 得到 Store 对象,然后调用 Store 对象的接收方法,就可以从指定的 POP3 服务器获得邮件数据,并把这些邮件数据封装到表示邮件的 Message 对象中。

// 获得实现了数据访问协议的Store对象
Store store = session.getStore("pop3");
// connect方法进行身份验证
store.connect(host, username, password);

  指定pop3协议和store类型时,则会使用 com.sun.mail.pop3.POP3Store 实例类创建一个 Store 实例,Store 将根据 Session 中 Properties 属性设置情况进行工作,属性包括:

属性名说明
mail.store.protocol默认的存储邮件协议,例如:pop3
mail.host默认的邮件服务地址,例如:imap.sina.com
mail.user默认的登陆用户名,例如:dllwhcrawler@sina.com
mail.port默认的邮件服务端口

2.7 Folder 类

  javax.mail.Folder 是个抽象类,代表邮件消息的一个文件夹,其子类实现了特定的Folders,文件夹可以包含子文件夹,以及消息,从而提供了一种分层结构。其实例:

public abstract class Folder implements AutoCloseable

  由于 Folder 类唯一的构造函数是受保护的,但SessionStore都有一个类似的getFolder()方法获取Folder对象:

public abstract Folder getFolder(String name) throws MessagingException;

三、JavaMail API 基本操作

3.1 准备工作

创建一个邮件服务器的基本信息类BaseMailConfig,如下:

import lombok.*;

@Data
@AllArgsConstructor
@RequiredArgsConstructor
public class BaseMailConfig {
    /**
     * 服务器是否要验证用户的身份信息
     */
    private boolean validate = false;
    /**
     * 是否开启Session的debug模式,开启后可以查看到程序发送Email的运行状态
     */
    private boolean debugMode = false;
    /**
     * 发送邮件的服务器的IP或主机地址
     */
    private String mailServerHost;
    /**
     * 发送邮件的服务器的端口
     */
    private int mailServerPort = 25;
    /**
     * 邮件发送服务器的用户名(指的是邮箱地址)
     */
    private String mailServerUser;
    /**
     * 邮件发送服务器的密码或者授权码
     */
    private String mailServerPassword;
    /**
     * 发件人昵称
     */
    private String nickName;
    /**
     * 邮件发送的协议
     */
    private String transportType = "smtp";
    /**
     * 邮件存储的协议
     */
    private String storeType = "pop3";
}

3.2 发送邮件

  现在,我们对 JavaMail API 及其核心类有一个清晰的概念,现在让我们写这将发送简单的电子邮件,邮件带有附件、电子邮件、HTML内容和内嵌图像的邮件一个简单的程序。发送电子邮件消息这一过程包括获取一个会话,创建并填充一则消息,然后发送。得到 Session 时,经由设置传递的 Properties 对象中的 mail.smtp.host 属性,可以指定 SMTP 服务器,如下图所示:

请添加图片描述

  发送邮件首先需要有一个邮箱账号和密码,以新浪邮箱为例,邮箱账号必须要开启 SMTP 服务,在浏览器网页登录邮箱后一般在邮箱的“设置”选项中可以开启,并记下邮箱的 SMTP 服务器地址,如下所示(其他邮箱大同小异):

请添加图片描述

  邮件发送涉及多端(本地代码端、邮件发送服务器端、邮件接收服务器端),把邮件提交到邮件发送服务器,发送的服务器可以拒绝服务(比如认为发送的内容是垃圾广告,或者你频繁请求发送),有时邮件就算发送成功了,对方也有可能接收不到,成功发送到对方的邮件接收服务器后,对方的服务器可以根据内容拒绝收邮件(比如认为内容是广告诈骗等信息,或者发送过于频繁),对方的服务器可能直接把你的邮件扔垃圾箱,或者直接忽略。

3.2.1 发送简单邮件

即纯文本邮件,没有除文字以外的其他所有文件。

import org.apache.commons.lang3.*;
import javax.activation.*;
import javax.mail.*;
import javax.mail.internet.*;
import java.io.*;
import java.util.*;

public class SendEmailHelper {
    private final static String CHARSET = "UTF-8";

    /**
     * 根据参数配置,创建用于连接邮件服务器的参数配置,发送邮件时才需要用到
     */
    private static Properties getProperties(MailSenderInfo mailSenderInfo) {
        Properties properties = new Properties();
        // 默认的邮件传输协议
        properties.setProperty("mail.transport.protocol", mailSenderInfo.getTransportType());
        // 默认的存储邮件协议
        properties.setProperty("mail.store.protocol", mailSenderInfo.getStoreType());
        // 设置邮件服务器主机名
        properties.put("mail.host", mailSenderInfo.getMailServerHost());
        properties.put("mail.port", mailSenderInfo.getMailServerPort());
        properties.put("mail.user", mailSenderInfo.getMailServerUser());
        // 设置是否安全验证,默认为false,一般情况都设置为true
        properties.put("mail.smtp.auth", mailSenderInfo.isValidate());
        return properties;
    }

    /**
     * 获得会话 Session
     */
    private static Session getSession(MailSenderInfo mailSenderInfo) {
        Properties properties = getProperties(mailSenderInfo);
        // 基本邮件会话,是Java Mail API的入口
        Session sendMailSession;
        Authenticator authenticator = null;
        // 判断是否需要身份认证
        if (mailSenderInfo.isValidate()) {
            // 如果需要身份认证,则创建一个密码验证器
            authenticator = new Authenticator() {
                @Override
                public PasswordAuthentication getPasswordAuthentication() {
                    return new PasswordAuthentication(mailSenderInfo.getMailServerUser(), mailSenderInfo.getMailServerPassword());
                }
            };
        }

        // 根据邮件会话属性和密码验证器构造一个发送邮件的session
        sendMailSession = Session.getDefaultInstance(properties, authenticator);

        // 若是设置为debug模式,可以查看详细的发送日志
        sendMailSession.setDebug(mailSenderInfo.isDebugMode());
        return sendMailSession;
    }

    /**
     * 使用 JavaMail 以文本格式发送邮件
     *
     * @param mailSenderInfo 待发送的邮件信息
     */
    public static void sendTextEmail(MailSenderInfo mailSenderInfo) throws MessagingException, UnsupportedEncodingException {
        // 1. 根据邮件会话属性和密码验证器构造一个发送邮件的session
        Session session = getSession(mailSenderInfo);

        // 2. 根据session创建一个邮件对象
        Message mailMessage = new MimeMessage(session);

        // 3. From: 发件人。其中 InternetAddress 的三个参数分别为: 邮箱、显示的昵称(只用于显示, 没有特别的要求)、昵称
        mailMessage.setFrom(new InternetAddress(mailSenderInfo.getMailServerUser(), mailSenderInfo.getNickName(), CHARSET));

        // 4. To: 收件人
        mailMessage.setRecipient(MimeMessage.RecipientType.TO, new InternetAddress(mailSenderInfo.getReceiver()));

        // 5. To: 抄送收件人
        if (StringUtils.isNotBlank(mailSenderInfo.getCcReceiver())) {
            mailMessage.setRecipient(MimeMessage.RecipientType.CC, new InternetAddress(mailSenderInfo.getCcReceiver()));
        }

        // 6. To: 密送收件人
        if (StringUtils.isNotBlank(mailSenderInfo.getBccReceiver())) {
            mailMessage.setRecipient(MimeMessage.RecipientType.BCC, new InternetAddress(mailSenderInfo.getBccReceiver()));
        }

        // 7. 设置邮件消息的主题
        mailMessage.setSubject(mailSenderInfo.getSubject());

        // 8. 设置邮件消息的主要内容
        mailMessage.setContent(mailSenderInfo.getContent(), "text/html;charset=UTF-8");

        // 9. 设置邮件消息发送的时间
        mailMessage.setSentDate(new Date());

        // 10. 保存前面的设置
        mailMessage.saveChanges();

        // 11. 发送使用传输对象的消息
        Transport.send(mailMessage);
    }

    public static void main(String[] args) throws Exception {
        MailSenderInfo mailConfigInfo = new MailSenderInfo();
        mailConfigInfo.setMailServerHost("smtp.sina.com");
        mailConfigInfo.setMailServerUser("dllwhcrawler@sina.com");
        mailConfigInfo.setMailServerPassword("4f38d72caa78ffec");
        mailConfigInfo.setReceiver("duleilewuhen@sina.com");
        mailConfigInfo.setValidate(true);
        mailConfigInfo.setSubject("TEST邮件主题");
        mailConfigInfo.setContent("TEST这是邮件正文。。。");
        mailConfigInfo.setFilePath("/Users/dllwh/Desktop/redis.sh");
        mailConfigInfo.setImagePath("/Users/dllwh/Downloads/禅.jpeg");
    }
}

有时处于业务需要,我们需要群发邮件,示例代码如下:

package org.dllwh.utils.application.email.test;

import org.apache.commons.lang3.*;
import org.dllwh.utils.application.email.model.MailSenderInfo;

import javax.activation.*;
import javax.mail.*;
import javax.mail.internet.*;
import java.io.*;
import java.util.*;

public class SendEmailHelper {
    private final static String CHARSET = "UTF-8";

    /**
     * 根据参数配置,创建用于连接邮件服务器的参数配置,发送邮件时才需要用到
     */
    private static Properties getProperties(MailSenderInfo mailSenderInfo) {
        Properties properties = new Properties();
        // 默认的邮件传输协议
        properties.setProperty("mail.transport.protocol", mailSenderInfo.getTransportType());
        // 默认的存储邮件协议
        properties.setProperty("mail.store.protocol", mailSenderInfo.getStoreType());
        // 设置邮件服务器主机名
        properties.put("mail.host", mailSenderInfo.getMailServerHost());
        properties.put("mail.port", mailSenderInfo.getMailServerPort());
        properties.put("mail.user", mailSenderInfo.getMailServerUser());
        // 设置是否安全验证,默认为false,一般情况都设置为true
        properties.put("mail.smtp.auth", mailSenderInfo.isValidate());
        return properties;
    }

    /**
     * 获得会话 Session
     */
    private static Session getSession(MailSenderInfo mailSenderInfo) {
        Properties properties = getProperties(mailSenderInfo);
        // 基本邮件会话,是Java Mail API的入口
        Session sendMailSession;
        Authenticator authenticator = null;
        // 判断是否需要身份认证
        if (mailSenderInfo.isValidate()) {
            // 如果需要身份认证,则创建一个密码验证器
            authenticator = new Authenticator() {
                @Override
                public PasswordAuthentication getPasswordAuthentication() {
                    return new PasswordAuthentication(mailSenderInfo.getMailServerUser(), mailSenderInfo.getMailServerPassword());
                }
            };
        }

        // 根据邮件会话属性和密码验证器构造一个发送邮件的session
        sendMailSession = Session.getDefaultInstance(properties, authenticator);

        // 若是设置为debug模式,可以查看详细的发送日志
        sendMailSession.setDebug(mailSenderInfo.isDebugMode());
        return sendMailSession;
    }

    /**
     * 使用 JavaMail 群发邮件
     *
     * @param mailSenderInfo 待发送的邮件信息
     */
    public void sendTextEmails(MailSenderInfo mailSenderInfo) throws MessagingException, UnsupportedEncodingException {
        // 1. 创建一封邮件,获取一个Session
        Session session = getSession(mailSenderInfo);

        // 2. 创建邮件对象
        Message mailMessage = new MimeMessage(session);

        // 3. From: 发件人。其中 InternetAddress 的三个参数分别为: 邮箱、显示的昵称(只用于显示, 没有特别的要求)、昵称的字符集编码
        mailMessage.setFrom(new InternetAddress(mailSenderInfo.getMailServerUser(), mailSenderInfo.getNickName(), CHARSET));

        // 4. To: 收件人
        String[] receivers = mailSenderInfo.getReceivers();
        if (ArrayUtils.isNotEmpty(receivers)) {
            InternetAddress[] addresses = new InternetAddress[receivers.length];
            for (int i = 0; i < receivers.length; i++) {
                addresses[i] = new InternetAddress(receivers[i]);
            }
            mailMessage.setRecipients(MimeMessage.RecipientType.TO, addresses);
        }

        // 5. To: 抄送收件人
        String[] ccReceivers = mailSenderInfo.getCcReceivers();
        if (ArrayUtils.isNotEmpty(ccReceivers)) {
            InternetAddress[] addresses = new InternetAddress[receivers.length];
            for (int i = 0; i < receivers.length; i++) {
                addresses[i] = new InternetAddress(receivers[i]);
            }
            mailMessage.setRecipients(MimeMessage.RecipientType.CC, addresses);
        }

        // 6. To: 密送收件人
        String[] bccReceivers = mailSenderInfo.getBccReceivers();
        if (ArrayUtils.isNotEmpty(bccReceivers)) {
            InternetAddress[] addresses = new InternetAddress[receivers.length];
            for (int i = 0; i < receivers.length; i++) {
                addresses[i] = new InternetAddress(receivers[i]);
            }
            mailMessage.setRecipients(MimeMessage.RecipientType.BCC, addresses);
        }

        // 7. 设置邮件的主题
        mailMessage.setSubject(mailSenderInfo.getSubject());

        // 8. 设置邮件的内容
        mailMessage.setContent(mailSenderInfo.getContent(), "text/html;charset=UTF-8");

        // 9. 设置显示的发送时间
        mailMessage.setSentDate(new Date());

        // 10. 保存前面的设置
        mailMessage.saveChanges();

        // 11. 发送使用传输对象的消息
        Transport.send(mailMessage);
    }

    public static void main(String[] args) throws Exception {
        MailSenderInfo mailConfigInfo = new MailSenderInfo();
        mailConfigInfo.setMailServerHost("smtp.sina.com");
        mailConfigInfo.setMailServerUser("dllwhcrawler@sina.com");
        mailConfigInfo.setMailServerPassword("4f38d72caa78ffec");
        mailConfigInfo.setReceiver("duleilewuhen@sina.com");
        mailConfigInfo.setValidate(true);
        mailConfigInfo.setSubject("TEST邮件主题");
        mailConfigInfo.setContent("TEST这是邮件正文。。。");
        mailConfigInfo.setFilePath("/Users/dllwh/Desktop/redis.sh");
        mailConfigInfo.setImagePath("/Users/dllwh/Downloads/禅.jpeg");
    }
}

3.2.2 发送附件的邮件

  一封复杂的邮件内容可以看做是由很多节点(或者可以说是片段、部分、零件)组成,文本、图片、附件等都可以看成是邮件内容中的一个节点。这些节点之间又可以相互关联组合成一个节点,最终组合成一个大节点就是邮件的正文内容。

import org.apache.commons.lang3.*;
import javax.activation.*;
import javax.mail.*;
import javax.mail.internet.*;
import java.io.*;
import java.util.*;

public class SendEmailHelper {
    private final static String CHARSET = "UTF-8";

    /**
     * 根据参数配置,创建用于连接邮件服务器的参数配置,发送邮件时才需要用到
     */
    private static Properties getProperties(MailSenderInfo mailSenderInfo) {
        Properties properties = new Properties();
        // 默认的邮件传输协议
        properties.setProperty("mail.transport.protocol", mailSenderInfo.getTransportType());
        // 默认的存储邮件协议
        properties.setProperty("mail.store.protocol", mailSenderInfo.getStoreType());
        // 设置邮件服务器主机名
        properties.put("mail.host", mailSenderInfo.getMailServerHost());
        properties.put("mail.port", mailSenderInfo.getMailServerPort());
        properties.put("mail.user", mailSenderInfo.getMailServerUser());
        // 设置是否安全验证,默认为false,一般情况都设置为true
        properties.put("mail.smtp.auth", mailSenderInfo.isValidate());
        return properties;
    }

    /**
     * 获得会话 Session
     */
    private static Session getSession(MailSenderInfo mailSenderInfo) {
        Properties properties = getProperties(mailSenderInfo);
        // 基本邮件会话,是Java Mail API的入口
        Session sendMailSession;
        Authenticator authenticator = null;
        // 判断是否需要身份认证
        if (mailSenderInfo.isValidate()) {
            // 如果需要身份认证,则创建一个密码验证器
            authenticator = new Authenticator() {
                @Override
                public PasswordAuthentication getPasswordAuthentication() {
                    return new PasswordAuthentication(mailSenderInfo.getMailServerUser(), mailSenderInfo.getMailServerPassword());
                }
            };
        }

        // 根据邮件会话属性和密码验证器构造一个发送邮件的session
        sendMailSession = Session.getDefaultInstance(properties, authenticator);

        // 若是设置为debug模式,可以查看详细的发送日志
        sendMailSession.setDebug(mailSenderInfo.isDebugMode());
        return sendMailSession;
    }

    /**
     * 使用 JavaMail 发送带附件的邮件
     *
     * @param mailSenderInfo 待发送的邮件信息
     */
    public static void sendAttachEmail(MailSenderInfo mailSenderInfo) throws MessagingException, UnsupportedEncodingException {
        // 1. 创建一封邮件,获取一个Session
        Session session = getSession(mailSenderInfo);

        // 2. 创建邮件对象
        MimeMessage message = new MimeMessage(session);

        // 3. From: 发件人。其中 InternetAddress 的三个参数分别为: 邮箱、显示的昵称(只用于显示, 没有特别的要求)、昵称的字符集编码
        message.setFrom(new InternetAddress(mailSenderInfo.getMailServerUser(), mailSenderInfo.getNickName(), CHARSET));

        // 4. To: 收件人
        String[] receivers = mailSenderInfo.getReceivers();
        if (ArrayUtils.isNotEmpty(receivers)) {
            InternetAddress[] addresses = new InternetAddress[receivers.length];
            for (int i = 0; i < receivers.length; i++) {
                addresses[i] = new InternetAddress(receivers[i]);
            }
            message.setRecipients(MimeMessage.RecipientType.TO, addresses);
        }

        // 5. To: 抄送收件人
        String[] ccReceivers = mailSenderInfo.getCcReceivers();
        if (ArrayUtils.isNotEmpty(ccReceivers)) {
            InternetAddress[] addresses = new InternetAddress[receivers.length];
            for (int i = 0; i < receivers.length; i++) {
                addresses[i] = new InternetAddress(receivers[i]);
            }
            message.setRecipients(MimeMessage.RecipientType.CC, addresses);
        }

        // 6. To: 密送收件人
        String[] bccReceivers = mailSenderInfo.getBccReceivers();
        if (ArrayUtils.isNotEmpty(bccReceivers)) {
            InternetAddress[] addresses = new InternetAddress[receivers.length];
            for (int i = 0; i < receivers.length; i++) {
                addresses[i] = new InternetAddress(receivers[i]);
            }
            message.setRecipients(MimeMessage.RecipientType.BCC, addresses);
        }

        // 7. 设置邮件的主题
        message.setSubject(mailSenderInfo.getSubject(), CHARSET);

        // 8. 创建一个MimeMultipart的对象
        BodyPart messageBodyPart = new MimeBodyPart();
        messageBodyPart.setText(mailSenderInfo.getContent());
        messageBodyPart = new MimeBodyPart();
        DataSource source = new FileDataSource(mailSenderInfo.getFilePath());
        // 设置dhFile附件处理
        messageBodyPart.setDataHandler(new DataHandler(source));
        // 设置中文附件名称
        messageBodyPart.setFileName(mailSenderInfo.getFilePath());

        // 9. 设置邮件的内容
        Multipart multipart = new MimeMultipart();
        // 把附件资源混合到 Multipart 多资源邮件模块里
        multipart.addBodyPart(messageBodyPart);
        message.setContent(multipart);

        // 10. 设置显示的发送时间
        message.setSentDate(new Date());

        // 11. 保存前面的设置
        message.saveChanges();

        // 12. 发送使用传输对象的消息
        Transport.send(message);
    }

    public static void main(String[] args) throws Exception {
        MailSenderInfo mailConfigInfo = new MailSenderInfo();
        mailConfigInfo.setMailServerHost("smtp.sina.com");
        mailConfigInfo.setMailServerUser("dllwhcrawler@sina.com");
        mailConfigInfo.setMailServerPassword("4f38d72caa78ffec");
        mailConfigInfo.setReceiver("duleilewuhen@sina.com");
        mailConfigInfo.setValidate(true);
        mailConfigInfo.setSubject("TEST邮件主题");
        mailConfigInfo.setContent("TEST这是邮件正文。。。");
        mailConfigInfo.setFilePath("/Users/dllwh/Desktop/redis.sh");
        mailConfigInfo.setImagePath("/Users/dllwh/Downloads/禅.jpeg");
    }
}

3.2.3 发送HTML的邮件

发送HTML格式电子邮件跟发送简单的电子邮件非常相似,除非,在使用setContent()方法来设置内容的第二个参数为“"text/html"指定的HTML内容。

package org.dllwh.utils.application.email.test;

import org.apache.commons.lang3.*;
import org.dllwh.utils.application.email.model.MailSenderInfo;

import javax.activation.*;
import javax.mail.*;
import javax.mail.internet.*;
import java.io.*;
import java.util.*;

public class SendEmailHelper {
    private final static String CHARSET = "UTF-8";

    /**
     * 根据参数配置,创建用于连接邮件服务器的参数配置,发送邮件时才需要用到
     */
    private static Properties getProperties(MailSenderInfo mailSenderInfo) {
        Properties properties = new Properties();
        // 默认的邮件传输协议
        properties.setProperty("mail.transport.protocol", mailSenderInfo.getTransportType());
        // 默认的存储邮件协议
        properties.setProperty("mail.store.protocol", mailSenderInfo.getStoreType());
        // 设置邮件服务器主机名
        properties.put("mail.host", mailSenderInfo.getMailServerHost());
        properties.put("mail.port", mailSenderInfo.getMailServerPort());
        properties.put("mail.user", mailSenderInfo.getMailServerUser());
        // 设置是否安全验证,默认为false,一般情况都设置为true
        properties.put("mail.smtp.auth", mailSenderInfo.isValidate());
        return properties;
    }

    /**
     * 获得会话 Session
     */
    private static Session getSession(MailSenderInfo mailSenderInfo) {
        Properties properties = getProperties(mailSenderInfo);
        // 基本邮件会话,是Java Mail API的入口
        Session sendMailSession;
        Authenticator authenticator = null;
        // 判断是否需要身份认证
        if (mailSenderInfo.isValidate()) {
            // 如果需要身份认证,则创建一个密码验证器
            authenticator = new Authenticator() {
                @Override
                public PasswordAuthentication getPasswordAuthentication() {
                    return new PasswordAuthentication(mailSenderInfo.getMailServerUser(), mailSenderInfo.getMailServerPassword());
                }
            };
        }

        // 根据邮件会话属性和密码验证器构造一个发送邮件的session
        sendMailSession = Session.getDefaultInstance(properties, authenticator);

        // 若是设置为debug模式,可以查看详细的发送日志
        sendMailSession.setDebug(mailSenderInfo.isDebugMode());
        return sendMailSession;
    }

    /**
     * 使用 JavaMail 以HTML格式发送邮件
     *
     * @param mailSenderInfo 待发送的邮件信息
     */
    public static void sendHtmlMail(MailSenderInfo mailSenderInfo) throws UnsupportedEncodingException, MessagingException {
        // 1. 根据邮件会话属性和密码验证器构造一个发送邮件的session
        Session session = getSession(mailSenderInfo);

        // 2. 根据session创建一个邮件消息
        Message mailMessage = new MimeMessage(session);

        //  3. From: 发件人。其中 InternetAddress 的三个参数分别为: 邮箱、显示的昵称(只用于显示, 没有特别的要求)、昵称的字符集编码
        mailMessage.setFrom(new InternetAddress(mailSenderInfo.getMailServerUser(), mailSenderInfo.getNickName(), CHARSET));

        // 4. To: 收件人
        mailMessage.setRecipient(MimeMessage.RecipientType.TO, new InternetAddress(mailSenderInfo.getReceiver()));

        // 5. To: 抄送收件人
        if (StringUtils.isNotBlank(mailSenderInfo.getCcReceiver())) {
            mailMessage.setRecipient(MimeMessage.RecipientType.CC, new InternetAddress(mailSenderInfo.getCcReceiver()));
        }

        // 6. To: 密送收件人
        if (StringUtils.isNotBlank(mailSenderInfo.getBccReceiver())) {
            mailMessage.setRecipient(MimeMessage.RecipientType.BCC, new InternetAddress(mailSenderInfo.getBccReceiver()));
        }

        // 7. 设置邮件的主题
        mailMessage.setSubject(mailSenderInfo.getSubject());

        // 8. 设置邮件的内容
        mailMessage.setContent(mailSenderInfo.getContent(), "text/html;charset=UTF-8");

        // 9. 设置显示的发送时间
        mailMessage.setSentDate(new Date());

        // 10. 保存前面的设置
        mailMessage.saveChanges();

        // 11. 发送使用传输对象的消息
        Transport.send(mailMessage);
    }

    public static void main(String[] args) throws Exception {
        MailSenderInfo mailConfigInfo = new MailSenderInfo();
        mailConfigInfo.setMailServerHost("smtp.sina.com");
        mailConfigInfo.setMailServerUser("dllwhcrawler@sina.com");
        mailConfigInfo.setMailServerPassword("4f38d72caa78ffec");
        mailConfigInfo.setReceiver("duleilewuhen@sina.com");
        mailConfigInfo.setValidate(true);
        mailConfigInfo.setSubject("TEST邮件主题");
        mailConfigInfo.setContent("TEST这是邮件正文。。。");
        mailConfigInfo.setFilePath("/Users/dllwh/Desktop/redis.sh");
        mailConfigInfo.setImagePath("/Users/dllwh/Downloads/禅.jpeg");
    }
}

3.2.4 发送内嵌图像中的邮件

要发送包含一个内嵌图像的电子邮件,需要创建一个 DataHandler 类的来添加图像,

messageBodyPart = new MimeBodyPart();
DataSource fds = new FileDataSource("图像位置或者访问地址");
messageBodyPart.setDataHandler(new DataHandler(fds));
messageBodyPart.setHeader("Content-ID", "<image>");
multipart.addBodyPart(messageBodyPart);
message.setContent(multipart);

示例代码如下:

package org.dllwh.utils.application.email.test;

import org.apache.commons.lang3.*;
import org.dllwh.utils.application.email.model.MailSenderInfo;

import javax.activation.*;
import javax.mail.*;
import javax.mail.internet.*;
import java.io.*;
import java.util.*;

public class SendEmailHelper {
    private final static String CHARSET = "UTF-8";

    /**
     * 根据参数配置,创建用于连接邮件服务器的参数配置,发送邮件时才需要用到
     */
    private static Properties getProperties(MailSenderInfo mailSenderInfo) {
        Properties properties = new Properties();
        // 默认的邮件传输协议
        properties.setProperty("mail.transport.protocol", mailSenderInfo.getTransportType());
        // 默认的存储邮件协议
        properties.setProperty("mail.store.protocol", mailSenderInfo.getStoreType());
        // 设置邮件服务器主机名
        properties.put("mail.host", mailSenderInfo.getMailServerHost());
        properties.put("mail.port", mailSenderInfo.getMailServerPort());
        properties.put("mail.user", mailSenderInfo.getMailServerUser());
        // 设置是否安全验证,默认为false,一般情况都设置为true
        properties.put("mail.smtp.auth", mailSenderInfo.isValidate());
        return properties;
    }

    /**
     * 获得会话 Session
     */
    private static Session getSession(MailSenderInfo mailSenderInfo) {
        Properties properties = getProperties(mailSenderInfo);
        // 基本邮件会话,是Java Mail API的入口
        Session sendMailSession;
        Authenticator authenticator = null;
        // 判断是否需要身份认证
        if (mailSenderInfo.isValidate()) {
            // 如果需要身份认证,则创建一个密码验证器
            authenticator = new Authenticator() {
                @Override
                public PasswordAuthentication getPasswordAuthentication() {
                    return new PasswordAuthentication(mailSenderInfo.getMailServerUser(), mailSenderInfo.getMailServerPassword());
                }
            };
        }

        // 根据邮件会话属性和密码验证器构造一个发送邮件的session
        sendMailSession = Session.getDefaultInstance(properties, authenticator);

        // 若是设置为debug模式,可以查看详细的发送日志
        sendMailSession.setDebug(mailSenderInfo.isDebugMode());
        return sendMailSession;
    }

    /**
     * 使用 JavaMail 发送内嵌图像中的邮件
     *
     * @param mailSenderInfo 待发送的邮件信息
     */
    public static void sendImageEmail(MailSenderInfo mailSenderInfo) throws UnsupportedEncodingException, MessagingException {
        // 1. 创建一封邮件,获取一个Session
        Session session = getSession(mailSenderInfo);

        // 2. 创建邮件对象
        MimeMessage message = new MimeMessage(session);

        // 3. From: 发件人。其中 InternetAddress 的三个参数分别为: 邮箱、显示的昵称(只用于显示, 没有特别的要求)、昵称的字符集编码
        message.setFrom(new InternetAddress(mailSenderInfo.getMailServerUser(), mailSenderInfo.getNickName(), CHARSET));

        // 4. To: 收件人
        message.setRecipient(MimeMessage.RecipientType.TO, new InternetAddress(mailSenderInfo.getReceiver()));

        // 5. To: 抄送收件人
        if (StringUtils.isNotBlank(mailSenderInfo.getCcReceiver())) {
            message.setRecipient(MimeMessage.RecipientType.CC, new InternetAddress(mailSenderInfo.getCcReceiver()));
        }

        // 6. To: 密送收件人
        if (StringUtils.isNotBlank(mailSenderInfo.getBccReceiver())) {
            message.setRecipient(MimeMessage.RecipientType.BCC, new InternetAddress(mailSenderInfo.getBccReceiver()));
        }

        // 7. 设置邮件的主题
        message.setSubject(mailSenderInfo.getSubject(), CHARSET);
        MimeMultipart multipart = new MimeMultipart("related");

        // 8. 创建一个MimeMultipart的对象
        BodyPart messageBodyPart = new MimeBodyPart();
        String htmlText = "<H1>Hello</H1><img src=\"cid:image\">";
        messageBodyPart.setContent(htmlText, "text/html");
        multipart.addBodyPart(messageBodyPart);

        // 9. 设置邮件的内容
        messageBodyPart = new MimeBodyPart();
        DataSource fds = new FileDataSource(mailSenderInfo.getImagePath());
        // //设置dhImg图片处理
        messageBodyPart.setDataHandler(new DataHandler(fds));
        messageBodyPart.setHeader("Content-ID", "<image>");
        multipart.addBodyPart(messageBodyPart);
        message.setContent(multipart);

        // 10. 设置显示的发送时间
        message.setSentDate(new Date());

        // 11. 保存前面的设置
        message.saveChanges();

        // 12. 发送使用传输对象的消息
        Transport.send(message);
    }

    public static void main(String[] args) throws Exception {
        MailSenderInfo mailConfigInfo = new MailSenderInfo();
        mailConfigInfo.setMailServerHost("smtp.sina.com");
        mailConfigInfo.setMailServerUser("dllwhcrawler@sina.com");
        mailConfigInfo.setMailServerPassword("4f38d72caa78ffec");
        mailConfigInfo.setReceiver("duleilewuhen@sina.com");
        mailConfigInfo.setValidate(true);
        mailConfigInfo.setSubject("TEST邮件主题");
        mailConfigInfo.setContent("TEST这是邮件正文。。。");
        mailConfigInfo.setFilePath("/Users/dllwh/Desktop/redis.sh");
        mailConfigInfo.setImagePath("/Users/dllwh/Downloads/禅.jpeg");
    }
}

3.3 收取邮件

  为读邮件,先要获取一个会话,获取并连接一个用于邮箱的适宜的存储(store),打开适宜的文件夹,然后获取相关的消息。同样,切记完成后关闭连接。

package org.dllwh.utils.application.email.test;

import org.apache.commons.lang3.*;
import org.dllwh.utils.application.email.model.*;

import javax.mail.*;
import javax.mail.internet.*;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;

public class ReceiveEmailHelper {

    /**
     * 根据参数配置,创建会话对象,用于连接邮件服务器的参数配置,发送邮件时才需要用到
     */
    private static Properties getProperties(BaseMailConfig mailConfigInfo) {
        Properties properties = new Properties();
        // 默认的邮件传输协议
        properties.setProperty("mail.transport.protocol", mailConfigInfo.getTransportType());
        // 默认的存储邮件协议
        properties.setProperty("mail.store.protocol", mailConfigInfo.getStoreType());
        // 设置邮件服务器主机名
        properties.put("mail.host", mailConfigInfo.getMailServerHost());
        properties.put("mail.port", mailConfigInfo.getMailServerPort());
        properties.put("mail.user", mailConfigInfo.getMailServerUser());
        // 设置是否安全验证,默认为false,一般情况都设置为true
        properties.put("mail.smtp.auth", mailConfigInfo.isValidate());
        return properties;
    }


    /**
     * 获得会话 Session
     */
    private static Session getSession(BaseMailConfig mailConfigInfo) {
        Properties properties = getProperties(mailConfigInfo);
        // 基本邮件会话,是Java Mail API的入口
        Session sendMailSession;
        Authenticator authenticator = null;

        // 判断是否需要身份认证
        if (mailConfigInfo.isValidate()) {
            // 如果需要身份认证,则创建一个密码验证器
            authenticator = new Authenticator() {
                @Override
                public PasswordAuthentication getPasswordAuthentication() {
                    return new PasswordAuthentication(mailConfigInfo.getMailServerUser(), mailConfigInfo.getMailServerPassword());
                }
            };
        }

        // 根据邮件会话属性和密码验证器构造一个发送邮件的session
        sendMailSession = Session.getDefaultInstance(properties, authenticator);

        // 若是设置为debug模式,可以查看详细的发送日志
        sendMailSession.setDebug(mailConfigInfo.isDebugMode());
        return sendMailSession;
    }

    /**
     * 获取邮箱的基本邮件信息
     *
     * @param folder 收件箱对象
     * @return 返回邮箱基本信息
     */
    private static Map<String, Integer> emailInfo(Folder folder) throws MessagingException {
        Map<String, Integer> emailInfo = new HashMap<>();
        // 未读邮件数。由于POP3协议无法获知邮件的状态,所以getUnreadMessageCount得到的是收件箱的邮件总数
        emailInfo.put("unreadMessageCount", folder.getUnreadMessageCount());
        // 删除邮件数。由于POP3协议无法获知邮件的状态,所以下面(删除、新邮件)得到的结果始终都是为0
        emailInfo.put("deletedMessageCount", folder.getDeletedMessageCount());
        // 新邮件
        emailInfo.put("newMessageCount", folder.getNewMessageCount());
        // 获得收件箱中的邮件总数
        emailInfo.put("messageCount", folder.getMessageCount());
        return emailInfo;
    }


    /***
     * 获得邮件主题
     */
    private static String getSubject(MimeMessage msg) throws UnsupportedEncodingException, MessagingException {
        return decodeText(msg.getSubject());
    }

    /***
     * 获得邮件发件人
     */
    private static String getFrom(MimeMessage msg) throws MessagingException, UnsupportedEncodingException {
        Address[] froms = msg.getFrom();
        if (froms.length < 1) {
            throw new MessagingException("没有发件人!");
        }

        InternetAddress address = (InternetAddress) froms[0];
        String person = address.getPersonal();
        person = (person != null) ? decodeText(person) + " " : "";
        return person + "<" + address.getAddress() + ">";
    }

    /***
     * 根据收件人类型,获取邮件收件人、抄送和密送地址。如果收件人类型为空,则获得所有的收件人
     * type可选值
     * <p>Message.RecipientType.TO  收件人</p>
     * <p>Message.RecipientType.CC  抄送</p>
     * <p>Message.RecipientType.BCC 密送</p>
     * @param msg  邮件内容
     * @param type 收件人类型
     * @return 收件人1 <邮件地址1>, 收件人2 <邮件地址2>, ...
     */
    private static String getReceiveAddress(Message msg, Message.RecipientType type) throws MessagingException {
        StringBuilder recipientAddress = new StringBuilder();
        Address[] address;
        if (type == null) {
            address = msg.getAllRecipients();
        } else {
            address = msg.getRecipients(type);
        }

        if (address == null || address.length < 1) {
            if (type == null) {
                throw new MessagingException("没有收件人!");
            } else if ("cc".equalsIgnoreCase(type.toString())) {
                throw new MessagingException("没有抄送人!");
            } else if ("bcc".equalsIgnoreCase(type.toString())) {
                throw new MessagingException("没有密送人!");
            }
        }

        for (Address add : Objects.requireNonNull(address)) {
            InternetAddress internetAddress = (InternetAddress) add;
            recipientAddress.append(internetAddress.toUnicodeString()).append(",");
        }
        //删除最后一个逗号
        recipientAddress.deleteCharAt(recipientAddress.length() - 1);
        return recipientAddress.toString();
    }

    /***
     * 获得邮件发送时间
     * @param msg 邮件内容
     * @return 默认返回:yyyy年mm月dd日 星期X HH:mm
     */
    private static String getSentDate(Message msg, String pattern) throws MessagingException {
        Date receivedDate = msg.getSentDate();
        if (receivedDate == null) {
            return "";
        }
        pattern = StringUtils.isNotBlank(pattern) ? "yyyy年MM月dd日 E HH:mm " : pattern;
        return new SimpleDateFormat(pattern).format(receivedDate);
    }

    /***
     * 获得邮件接收时间
     * @param msg 邮件内容
     * @return 默认返回:yyyy年mm月dd日 星期X HH:mm
     */
    private static String getReceivedDate(Message msg, String pattern) throws MessagingException {
        Date receivedDate = msg.getReceivedDate();
        if (receivedDate == null) {
            return "";
        }
        pattern = StringUtils.isNotBlank(pattern) ? "yyyy年MM月dd日 E HH:mm " : pattern;
        return new SimpleDateFormat(pattern).format(receivedDate);
    }

    /***
     * 判断邮件是否已读  www.2cto.com
     * @param msg 邮件内容
     * @return 如果邮件已读返回true, 否则返回false
     */
    private static boolean isSeen(Message msg) throws MessagingException {
        return msg.getFlags().contains(Flags.Flag.SEEN);
    }

    /***
     * 判断邮件是否需要阅读回执
     * @param msg 邮件内容
     * @return 需要回执返回true, 否则返回false
     */
    private static boolean isReplySign(Message msg) throws MessagingException {
        return ArrayUtils.isNotEmpty(msg.getHeader("Disposition-Notification-To"));
    }

    /***
     * 获得邮件的优先级
     * @param msg 邮件内容
     * @return 1(High):紧急  3:普通(Normal)  5:低(Low)
     */
    private static String getPriority(Message msg) throws MessagingException {
        String priority = "普通";
        String[] headers = msg.getHeader("X-Priority");
        if (headers != null) {
            String headerPriority = headers[0];
            if (headerPriority.contains("1") || headerPriority.contains("High")) {
                priority = "紧急";
            } else if (headerPriority.contains("5") || headerPriority.contains("Low")) {
                priority = "低";
            } else {
                priority = "普通";
            }
        }
        return priority;
    }

    /***
     * 获得邮件文本内容
     * @param part    邮件体
     * @param content 存储邮件文本内容的字符串
     */
    private static void getMailTextContent(Part part, StringBuffer content) throws MessagingException, IOException {
        //如果是文本类型的附件,通过getContent方法可以取到文本内容,但这不是我们需要的结果,所以在这里要做判断
        boolean isContainTextAttach = part.getContentType().indexOf("name") > 0;
        if (part.isMimeType("text/*") && !isContainTextAttach) {
            content.append(part.getContent().toString());
        } else if (part.isMimeType("message/rfc822")) {
            getMailTextContent((Part) part.getContent(), content);
        } else if (part.isMimeType("multipart/*")) {
            Multipart multipart = (Multipart) part.getContent();
            int partCount = multipart.getCount();
            for (int i = 0; i < partCount; i++) {
                BodyPart bodyPart = multipart.getBodyPart(i);
                getMailTextContent(bodyPart, content);
            }
        }
    }

    /***
     * 文本解码
     * @param encodeText 解码MimeUtility.encodeText(String text)方法编码后的文本
     * @return 解码后的文本
     */
    private static String decodeText(String encodeText) throws UnsupportedEncodingException {
        if (encodeText == null || "".equals(encodeText)) {
            return "";
        } else {
            return MimeUtility.decodeText(encodeText);
        }
    }

    /***
     * 判断邮件中是否包含附件 (Part为Message接口),邮件中存在附件返回true,不存在返回false
     */
    private static boolean isContainAttachment(Part part) throws MessagingException, IOException {
        boolean flag = false;
        if (part.isMimeType("multipart/*")) {
            MimeMultipart multipart = (MimeMultipart) part.getContent();
            int partCount = multipart.getCount();
            for (int i = 0; i < partCount; i++) {
                BodyPart bodyPart = multipart.getBodyPart(i);
                String disposition = bodyPart.getDisposition();
                if (disposition != null && (disposition.equalsIgnoreCase(Part.ATTACHMENT) || disposition.equalsIgnoreCase(Part.INLINE))) {
                    flag = true;
                } else if (bodyPart.isMimeType("multipart/*")) {
                    flag = isContainAttachment(bodyPart);
                } else {
                    String contentType = bodyPart.getContentType();
                    if (contentType.contains("application")) {
                        flag = true;
                    }
                    if (contentType.contains("name")) {
                        flag = true;
                    }
                }
                if (flag) {
                    break;
                }
            }
        } else if (part.isMimeType("message/rfc822")) {
            flag = isContainAttachment((Part) part.getContent());
        }
        return flag;
    }

    /**
     * 使用 JavaMail 接收邮件
     */
    public static void recipientMail(MailReceiveInfo mailReceiveInfo) throws MessagingException, IOException {
        // 1. 创建一封邮件,获取一个Session
        Session session = getSession(mailReceiveInfo);

        // 2. 获取Store对象
        Store emailStore = session.getStore(mailReceiveInfo.getStoreType());
        // POP3服务器登录认证,user我们在properties中已经指定默认
        emailStore.connect(mailReceiveInfo.getMailServerUser(), mailReceiveInfo.getMailServerPassword());

        // 3. 获取收件箱内容:(电子邮件)收件箱  folder:邮件夹
        Folder emailFolder = emailStore.getFolder("INBOX");

        // 4. 设置对邮件帐户的访问权限。 Folder.READ_ONLY (只读或者1)、Folder.READ_WRITE(只写或者2)
        emailFolder.open(Folder.READ_ONLY);

        // 获取邮箱基本信息
        System.out.println(emailInfo(emailFolder));

        // 5. 获取收件箱中的所有邮件
        Message[] messages = emailFolder.getMessages();

        // 解析所有邮件
        for (Message message : messages) {
            System.out.println("------------------解析第" + message.getMessageNumber() + "封邮件-------------------- ");
            System.out.println("主题: " + MimeUtility.decodeText(message.getSubject()));
            System.out.println("发件人: " + InternetAddress.toString(message.getFrom()));
            System.out.println("收件人:" + getReceiveAddress(message, Message.RecipientType.TO));
            System.out.println("邮件正文: " + message.getContent().toString());
            System.out.println("接收时间:" + getReceivedDate(message, "yyyy-MM-dd HH:mm:ss"));
            System.out.println("发送时间:" + getSentDate(message, "yyyy-MM-dd HH:mm:ss"));
            System.out.println("是否已读:" + isSeen(message));
            System.out.println("是否需要回执:" + isReplySign(message));
            System.out.println("邮件大小:" + message.getSize() * 1024 + "kb");
            System.out.println("邮件优先级:" + getPriority(message));
            System.out.println("是否包含附件:" + isContainAttachment(message));
            //用来存储正文的对象
            StringBuffer content = new StringBuffer();
            getMailTextContent(message, content);
            System.out.println("邮件正文:" + content);
            System.out.println("-----------第" + message.getMessageNumber() + "封邮件解析结束------------");
            System.out.println();
        }
        // 6. 关闭邮件夹对象
        emailFolder.close(false);
        // 7. 关闭连接对象
        emailStore.close();
    }

    public static void main(String[] args) throws MessagingException, IOException {
        MailReceiveInfo mailConfigInfo = new MailReceiveInfo();
        mailConfigInfo.setMailServerHost("imap.sina.com");
        mailConfigInfo.setMailServerUser("dllwhcrawler@sina.com");
        mailConfigInfo.setMailServerPassword("4f38d72caa78ffec");
        mailConfigInfo.setValidate(true);

        ReceiveEmailHelper.recipientMail(mailConfigInfo);
    }
}

3.4 删除邮件

  我们将使用JavaMail API来删除电子邮件。删除信息涉及与该消息相关联的标志工作。有不同的标志为不同的状态,一些系统定义和一些用户定义的。预定义的标志在内部类中定义的标志。标志如下所列:

标志说明
Flags.Flag.ANSWERED邮件回复标记,标识邮件是否已回复
Flags.Flag.DELETED邮件删除标记,标识邮件是否需要删除
Flags.Flag.DRAFT草稿邮件标记,标识邮件是否为草稿
Flags.Flag.FLAGGED表示邮件是否为回收站中的邮件
Flags.Flag.RECENT新邮件标记,表示邮件是否为新邮件
Flags.Flag.SEEN邮件阅读标记,标识邮件是否已被阅读
Flags.Flag.USER底层系统是否支持用户自定义标记,应用程序只能检索这个属性,而不能设置。

3.5 邮件文件夹管理

  到目前为止,我们在上面章节中主要使用了 INBOX 文件夹,这是大多数邮件所在的默认文件夹。一些系统可能将其称为 INBOX,而另一些系统可能会用其他名称来称呼它。但是,我们始终可以使用名称 INBOX 从 JavaMail API 访问它。JavaMail API 将文件夹表示为抽象 Folder 类的实例:

public abstract class Folder extends Object

此类声明用于从服务器请求命名文件夹、从文件夹中删除邮件、在文件夹中搜索特定邮件、列出文件夹中的邮件等的方法。

3.5.1 打开文件夹

  我们不能直接创建文件夹,因为 Folder 类中唯一的构造函数是 protected。我们可以通过Session、Store、Folder类获取文件夹,都有一个类似的 getFolder() 方法,具有类似的签名:

public abstract Folder getFolder(String name) throws MessagingException;

以下是有助于获取 Folder 对象的以下方法:

方法描述
boolean exists()检查文件夹是否真的存在,在获取 Folder 对象之前使用
void open(int mode)Folder.READ_ONLYFolder.READ_WRITE模式打开文件夹
boolean isOpen()如果文件夹打开,返回 true,否则返回 false
void close(boolean expunge)关闭文件夹。
如果 expunge 为 true ,则会从服务器上的实际文件中删除该文件夹中的所有已删除邮件。
否则,它们只是标记为 已删除,但邮件仍然可以取消删除.

3.5.2 基本文件夹信息

以下是 Folder 类中的一些方法,它们返回有关文件夹的基本信息:

方法描述
String getName()返回文件夹的名称
String getFullName()从根目录返回完整的层次结构名称
URLName getURLName()返回表示此文件夹的URLName
Folder getParent()返回包含此文件夹的文件夹的名称,即父文件夹
int getType()返回一个int,指示文件夹是否可以包含消息和/或其他文件夹
int getMode()返回Folder.READ_ONLY、Folder.READ_WRITE、-1
Store getStore()返回从中检索此文件夹的 Store 对象
char getSeparator()返回分隔此文件夹的路径名与直接子文件夹的名称的分隔符

3.5.3 管理文件夹

以下是一些有助于管理文件夹以及文件夹中的消息的方法:

方法描述
create(int type)在此文件夹的Store中创建一个新文件夹,成功返回 true,否则返回 false
delete(boolean recurse)仅当文件夹关闭时,才会删除。如果recurse是true,则删除子文件夹
renameTo(Folder f)更改文件夹的名称,必须关闭文件夹才能重命名,否则抛出异常
appendMessages(Message[] messages)数组中的消息放置在此文件夹的末尾
copyMessages(Message[] msgs,Folder folder)将此文件夹中的消息复制到作为参数给出的指定文件夹中
Message[] expunge()从文件夹中物理删除已删除的邮件

3.5.4 列出文件夹的内容

以下几种方法可以列出文件夹包含的文件夹:

方法描述
Folder[] list()返回一个数组,列出该文件夹包含的文件夹
Folder[] listSubscribed()返回一个数组,列出该文件夹包含的所有订阅文件夹.
Folder[] list(String pattern)
Folder[] listSubscribed(String pattern)

3.5.5 检查邮件

方法描述
int getMessageCount()获取邮件总数
boolean hasNewMessages()
int getNewMessageCount()
int getUnreadMessageCount()未读邮件数
int getDeletedMessageCount()删除邮件数

3.5.6 从文件夹获取消息

Folder 类提供了以下几种从打开的文件夹中检索消息的方法:

方法描述
Messageget Message(int msgnum)这将返回文件夹中的第n条消息。
文件夹中的第一条消息是数字 1
Message[] getMessages()返回一组Message对象,表示此文件夹中的所有消息
Message[] getMessages(int start,int end)返回文件夹中的Message对象数组,从 start 开始,以 end 结束
Message[] getMessages(int[] msgnums)

3.5.7 修改文件夹标记

当需要更改文件夹中整个邮件集的标记时,标志修改非常有用。以下是 Folder 类中提供的方法:

方法描述
void setFlags(Message[] msgs,Flags flag,boolean value)在数组中指定的消息上设置指定的标志
void setFlags(intstart,intend,Flags flag,boolean value)设置从开始到结束编号的消息上的指定标志,包括起点和终点
void setFlags(int[] msgnums,Flags flag,boolean value)设置消息号在数组中的消息的指定标志
Flags getPermanentFlags()返回此文件夹支持所有邮件的标志

四、附录

4.1 邮箱配置

针对不同的邮箱有不同的配置,所以我们介绍几种我们常用的邮箱配置,可以直接拿来配置。

邮箱类型POP3服务器SMTP服务器IMAP服务器端口
新浪pop.sina.comsmtp.sina.comimap.sina.com25
QQpop.qq.comsmtp.qq.comimap.qq.com465
网易163pop.163.comsmtp.163.comimap.163.com465
谷歌邮箱smtp.gmail.com587
outlooksmtp-mail.outlook.com587

4.2 SMTP 服务器

SMTP 协议提供程序支持以下属性,这些属性可以在 JavaMail Session 对象中设置属性

属性说明
mail.smtp.userStringSMTP 的默认用户名
mail.smtp.hostString要连接的 SMTP 服务器
mail.smtp.portint要连接的 SMTP 服务器端口,默认为 25
mail.smtp.connectiontimeoutint以毫秒为单位的套接字连接超时值默认为无限超时
mail.smtp.timeoutint以毫秒为单位的套接字 I/O 超时值默认为无限超时
mail.smtp.authboolean如果为 true,则尝试使用 AUTH 命令对用户进行身份验证默认为假
mail.smtp.auth.login.disableboolean如果为 true,则阻止使用 AUTH LOGIN 命令默认为假
mail.smtp.auth.plain.disableboolean如果为 true,则阻止使用 AUTH PLAIN 命令默认为假
mail.smtp.auth.digest-md5.disableboolean如果为 true,则阻止使用 AUTH DIGEST-MD5 命令默认为假
mail.smtp.auth.ntlm.disableboolean如果为 true,则阻止使用 AUTH NTLM 命令默认为假
mail.smtp.auth.ntlm.domainStringNTLM 身份验证域
mail.smtp.auth.ntlm.flagsintNTLM 协议特定标志
mail.smtp.dsn.retStringMAIL 命令的 RET 选项FULL 或 HDRS
mail.smtp.sasl.authorizationidString在 SASL 身份验证中使用的授权 ID如果未设置,则使用身份验证 ID
mail.smtp.sasl.realmString用于 DIGEST-MD5 身份验证的领域
mail.smtp.quitwaitboolean如果设置为 false,则发送 QUIT 命令并立即关闭连接
如果设置为 true(默认值),则导致传输等待对 QUIT 命令的响应
mail.smtp.socketFactory.portint指定使用指定套接字工厂时要连接的端口如果未设置,将使用默认端口
mail.smtp.ssl.enableboolean如果设置为 true,则默认使用 SSL 连接并使用 SSL 端口“smtp”协议
mail.smtp.ssl.checkserveridentityboolean如果设置为 true,则检查 RFC 2595 指定的服务器标识。默认为 false
mail.smtp.ssl.trustString如果设置,并且未指定套接字工厂,则启用 MailSSLSocketFactory
mail.smtp.socks.hoststring指定将用于连接到邮件服务器的 SOCKS5 代理服务器的主机名
mail.smtp.mailextensionString附加到 MAIL 命令的扩展字符串

  一般来说,应用程序不需要直接使用这个包中的类。相反,应该使用 javax.mail 包以及子包定义的 API。例如,应用程序永远不应该直接构造 SMTPTransport 的实例相反,应该使用 Session 方法 getTransport 来获取适当的 Transport 对象。

4.2 IMAP 服务器

  IMAP 支持在线和离线操作模式,使用 IMAP 的电子邮件客户端通常会将消息留在服务器上,直到用户明确删除它们。IMAP 协议提供程序支持以下属性,这些属性可以在 JavaMail Session 对象中设置。

属性类型描述
mail.imap.userStringIMAP 的默认用户名。
mail.imap.hostString要连接的 IMAP 服务器。
mail.imap.portint要连接的 IMAP 服务器端口。默认为 143
mail.imap.partialfetchboolean控制是否应使用 IMAP 部分提取功能。默认为真
mail.imap.fetchsizeint部分提取大小(以字节为单位)。默认为 16K
mail.imap.connectiontimeoutint以毫秒为单位的套接字连接超时值。默认为无限超时
mail.imap.timeoutint以毫秒为单位的套接字 I/O 超时值。默认为无限超时
mail.imap.statuscachetimeoutint响应缓存的超时值(以毫秒为单位)。
默认值为 1000,零禁用
mail.imap.appendbuffersizeint附加到 IMAP 文件夹时要在内存中缓冲的消息的最大大小
mail.imap.connectionpoolsizeint连接池中可用连接的最大数量。默认值为 1
mail.imap.connectionpooltimeoutint连接池连接的超时值(以毫秒为单位),默认值为 45000
mail.imap.separatestoreconnectionboolean用于指示是否对存储命令使用专用存储连接的标志
mail.imap.auth.plain.disableboolean如果为 true,则阻止使用 AUTHENTICATE PLAIN 命令
mail.imap.auth.ntlm.disableboolean如果为 true,则阻止使用 AUTHENTICATE NTLM 命令
mail.imap.sasl.mechanismsString要尝试使用的 SASL 机制名称的空格或逗号分隔列表。
mail.imap.sasl.authorizationidString在 SASL 身份验证中使用的授权 ID。
如果未设置,则使用身份验证 ID(用户名)
mail.imap.sasl.realmString与需要领域的 SASL 身份验证机制一起使用的领域
mail.imap.auth.ntlm.domainStringNTLM 身份验证域。
mail.imap.auth.ntlm.flagsintNTLM 协议特定标志。
mail.imap.ssl.enableboolean如果设置为 true,则默认使用 SSL 连接并使用 SSL 端口
mail.imap.ssl.checkserveridentityboolean如果设置为 true,请检查 RFC 2595 指定的服务器标识
mail.imap.ssl.trustString如果设置,并且未指定套接字工厂,则启用 MailSSLSocketFactory
mail.imap.socks.hoststring指定将用于连接到邮件服务器的 SOCKS5 代理服务器的主机名
mail.imap.minidletimeint此属性以毫秒为单位设置延迟。如果未设置,则默认为 10 毫秒

  一般来说,应用程序不需要直接使用这个包中的类。相反,他们应该使用 javax.mail 包及其子包定义的 API。应用程序不应直接构造 IMAPStore 或 IMAPFolder 的实例。相反,应该使用 Session 方法 getStore 来获取适当的 Store 对象,并从中获取 Folder 对象。

4.3 POP3 服务器

POP3 协议提供程序支持以下属性,这些属性可以在 JavaMail Session 对象中设置。

Name类型描述
mail.pop3.userStringPOP3 的默认用户名
mail.pop3.hostString要连接的 POP3 服务器
mail.pop3.portint要连接的 POP3 服务器端口,默认为 110
mail.pop3.connectiontimeoutint以毫秒为单位的套接字连接超时值。默认为无限超时
mail.pop3.timeoutint以毫秒为单位的套接字 I/O 超时值。默认为无限超时
mail.pop3.rsetbeforequitboolean关闭文件夹时发送 POP3 RSET 命令,然后发送 QUIT 命令
mail.pop3.ssl.checkserveridentityboolean如果设置为 true,请检查 RFC 2595 指定的服务器标识
mail.pop3.socks.portstring指定 SOCKS5 代理服务器的端口号。
mail.pop3.disabletopboolean如果设置为 true,则 POP3 TOP 命令将不会用于获取邮件头

  通常,应用程序不应直接使用此包中的类。相反,他们应该使用javax.mail包及其子包定义的 API 。应用程序不应直接构造POP3Store或POP3Folder 的实例。相反,应该使用 Session 方法 getStore 来获取适当的 Store 对象,并从中获取 Folder 对象。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/3985.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

第十四届蓝桥杯三月真题刷题训练——第 24 天

目录 第 1 题&#xff1a;旋转 题目描述 输入描述 输出描述 输入输出样例 运行限制 代码&#xff1a; 思路&#xff1a; 第 2 题&#xff1a;附近最小_单调队列模板 代码&#xff1a; 第 3 题&#xff1a;扫地机器人_二分 题目描述 输入描述 输出描述 输入输出样…

【蓝桥杯】​蓝桥杯——每日四道编程题(两道真题+两道模拟)​| 第 二 天

专栏&#xff1a; 蓝桥杯——每日四道编程题&#xff08;两道真题两道模拟&#xff09; “蓝桥杯就要开始了&#xff0c;这些题刷到就是赚到” ₍ᐢ..ᐢ₎♡ 另一个专栏&#xff1a; 蓝桥杯——每日四道填空题&#xff08;两道真题两道模拟题&#xff09; 目录 第一道真题&…

Kafka 基础整理、 Springboot 简单整合

定义&#xff1a; Kafka 是一个分布式的基于发布/订阅默认的消息队列是一个开源的分布式事件流平台&#xff0c;被常用用于数据管道、流分析、数据集成、关键任务应用 消费模式&#xff1a; 点对点模式 (少用) 消费者主动拉取数据&#xff0c;消息收到后清除消息 发布/订阅模式…

【蓝桥杯嵌入式】第十四届蓝桥杯嵌入式[模拟赛2]客观题及详细题解

题1 解析 USART_CR1:控制寄存器1&#xff0c;其中的M位定义了数据字的长度&#xff0c;由软件对其设置和清零。USART_CR2:控制寄存器2。USART_BRR:波特率寄存器。USART_DR:数据寄存器。 (如果现场不记得&#xff0c;可以查阅芯片手册) 答案: A 题2 解析 在STM32微控制器中&a…

每日学术速递3.29

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 Subjects: cs.CV 1.CC3D: Layout-Conditioned Generation of Compositional 3D Scenes 标题&#xff1a;CC3D&#xff1a;合成 3D 场景的布局条件生成 作者&#xff1a;Sherwin Bahmani, Jeong Joon …

五、MyBatis各种查询功能

MyBatis的各种查询功能 如果查询出的数据只有一条&#xff0c;可以通过 实体类对象接收List集合接收Map集合接收 如果查询出的数据有多条&#xff0c;一定不能用实体对象接收&#xff0c;会抛TooManyResultsException&#xff0c;可以通过 实体类类型的List集合接收Map类型的L…

学习系统编程No.11【重定向的本质】

引言&#xff1a; 北京时间&#xff1a;2023/3/27/7:05&#xff0c;哈哈哈&#xff0c;首先是开心&#xff0c;因为上篇博客热榜目前第15&#xff0c;让我初步掌握了上热榜的小妙招&#xff0c;不单单只是要日更&#xff0c;还有非常多的上榜小技巧&#xff0c;但是首先连续更…

【备战蓝桥杯】----01背包问题(动态规划)

&#x1f339;作者:云小逸 &#x1f4dd;个人主页:云小逸的主页 &#x1f4dd;Github:云小逸的Github &#x1f91f;motto:要敢于一个人默默的面对自己&#xff0c;强大自己才是核心。不要等到什么都没有了&#xff0c;才下定决心去做。种一颗树&#xff0c;最好的时间是十年前…

【数据结构】堆(堆的实现 堆向下调整算法 堆的创建 堆的插入 堆的删除 堆的代码实现 堆的应用)

文章目录堆的实现堆向下调整算法堆的创建堆的插入堆的删除堆的代码实现堆的应用堆的实现 堆是属于操作系统进程地址空间内存区域的划分。 我们下面实现数据结构中的堆。 堆是一个完全二叉树&#xff1a;分为小根堆和大根堆。 小根堆&#xff1a;任何一个节点的值都<孩子的…

YOLOv8原理解析:重新定义实时目标检测的速度和精度

文章目录0.前言1.YOLOv51.1 YOLOv5网络回顾1.2 YOLOv5网络结构图2.YOLOv82.1 YOLOv8概述2.2 YOLOv8整体结构图2.3 YOLOv8yaml 文件与 YOLOv5yaml 文件对比2.3.1 参数部分2.3.2 主干部分2.3.3 Neck部分2.3.4 Head部分2.4 正负样本分配策略2.4.1 静态分配策略和动态分配策略有什么…

【嵌入式烧录/刷写文件】-1.1-详解Motorola S-record(S19/SREC/mot/SX)格式文件

目录 1 什么是Motorola S-record 2 Motorola S-record的格式 2.1 Motorola S-record的结构 2.1.1 “Record type记录类型”的说明 2.1.2 “Record length记录长度”的说明 2.1.3 如何计算“Checksum校验和” 2.2 Record order记录顺序 2.3 Text line terminator文本行终…

【C语言】柔性数组

柔性数组1. 柔性数组介绍2. 柔性数组特点3. 用例3.1 代码一&#xff1a;3.2 代码二&#xff1a;4. 柔性数组优势&#xff1a;1. 柔性数组介绍 也许你从来没有听说过柔性数组&#xff08;flexible array&#xff09;这个概念&#xff0c;但是它确实是存在的。 C99 中&#xff0c…

#详细介绍!!! 线程池的拒绝策略(经典面试题)

本篇单独讲解线程池的拒绝策略&#xff0c;介绍了当线程池任务满了之后&#xff0c;线程池会以什么样的方式来响应添加进来的任务 目录 一&#xff1a;理解线程池拒绝策略的触发情况代码理解 二&#xff1a;线程池的四种常见的拒绝策略 1.ThreadPoolExecutor.AbortPolicy 2…

【Spring6】| GoF之代理模式(静态代理和动态代理)

目录 一&#xff1a;GoF之代理模式 1. 对代理模式的理解 2. 静态代理 3. 动态代理 3.1 JDK动态代理 3.2 CGLIB动态代理 一&#xff1a;GoF之代理模式 1. 对代理模式的理解 生活场景1&#xff1a;牛村的牛二看上了隔壁村小花&#xff0c;牛二不好意思直接找小花&#xff…

内网渗透之某后渗透利用【网络安全】

0x01 工具介绍 工具原理 Mimikatz 的主要原理是在 Windows 系统中用户登录后系统会将身份凭证存储于lsass.exe进程的内存当中&#xff0c;Mimikatz 通过注入lsass.exe进程读取进程内存&#xff0c;从中获取对应的明文密码。 常见问题 在 Windows Vista 系统之后不再存储 LM…

0203优先级下的调度问题_环_拓扑排序-有向图-数据结构和算法(Java)

1 概述 在和有向图相关的实际应用中&#xff0c;有向环特别的重要。在实际应用中&#xff0c;一般只会重点关注其中的一小部分&#xff0c;或者只想知道它们是否存在。 2 调度问题 一种应用广泛的模型是给定一组任务并安排它们的执行顺序&#xff0c;限制条件是这些任务的执…

机器学习:逻辑回归模型算法原理(附案例实战)

机器学习&#xff1a;逻辑回归模型算法原理 作者&#xff1a;i阿极 作者简介&#xff1a;Python领域新星作者、多项比赛获奖者&#xff1a;博主个人首页 &#x1f60a;&#x1f60a;&#x1f60a;如果觉得文章不错或能帮助到你学习&#xff0c;可以点赞&#x1f44d;收藏&#…

Github学生包申请秒过经验并使用Copilot

写在前面 前提是在校学生&#xff0c;且有学校邮箱&#xff0c;当然你也得有Github账户前往学信网下载 教育部学籍在线验证报告将报告转换成英文版本&#xff0c;我用的是手机夸克自带的拍照翻译功能 具体流程 设置Github个人信息 来到 https://github.com/settings/profil…

如何用Postman做接口自动化测试?没有比这个更详细的了

目录 前言 什么是自动化测试 自动化测试有哪些分类 为什么需要自动化测试 Postman自动化测试演示 1.新建集合 2.新建接口 3.填写自动化测试脚本 4.录入所有接口 5.执行自动化测试 前言 什么是自动化测试 把人对软件的测试行为转化为由机器执行测试行为的一种实践。 …

腾讯Coding平台学习笔记二:自定义团队插件的使用方法

目录一、前言二、系统环境三、工作目标四、流水线设置五、开发工具5.1 教程地址5.2 开发工具程序结构5.3 qciplugin.yml文件5.4 main.py文件六、插件的安装6.1 打包成zip6.2 上传zip包6.3 构建新插件6.4 质量门禁7、流水线设置7.1 添加质量管理阶段节点7.2 添加其它动作八、流水…