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

这个时候了,你还不会不知道JavaMail API吧_第1张图片

一、概述

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.user String SMTP默认的登录用户名
mail.smtp.host String SMTP服务器地址,如smtp.sina.com.cn
mail.smtp.port int SMTP服务器端口号,默认为25
mail.smtp.from String 默认的邮件发送源地址
mail.smtp.auth boolean SMTP服务器是否需要用户认证,默认为false
mail.smtp.connectiontimeout int 套接字连接超时值,以毫秒为单位.默认为无限超时
mail.smtp.timeout int 套接字I/O超时值毫秒,默认为无限超时
mail.smtp.ssl.enable boolean 如果设置为true,则默认情况下使用SSL连接并使用SSL端口。
对于"smtp"协议,默认为false;对于"smtps"协议,默认为true.

1.2.2 什么是IMAP?

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

名称 类型 说明
mail.imap.user String IMAP的默认用户名
mail.imap.host String 要连接的IMAP服务器
mail.imap.port int 要连接的IMAP服务器端口,默认为143
mail.imap.connectiontimeout int 套接字连接超时值,以毫秒为单位.默认为无限超时
mail.imap.timeout int 套接字I/O超时值毫秒,默认为无限超时
mail.imap.statuscachetimeout int 缓存的超时值(以毫秒为单位),默认值为1000(1秒),零禁用缓存
mail.imap.appendbuffersize int 要缓冲的邮件的最大大小附加到IMAP文件夹时的内存
mail.imap.connectionpoolsize int 最大可用数量连接池中的连接,默认值为1
mail.imap.connectionpooltimeout int 连接池连接的超时值(以毫秒为单位),默认值为45000(45秒).
mail.imap.ssl.enable boolean 如果设置如果为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.user String POP3的默认用户名
mail.pop3.host String 要连接的POP3服务器
mail.pop3.port int 要连接的POP3服务器端口,默认为110
mail.pop3.connectiontimeout int 套接字连接超时值,以毫秒为单位,默认为无限超时
mail.pop3.timeout int 套接字I/O超时值毫秒,默认为无限超时
mail.pop3.ssl.enable boolean 如果设置为true,则默认情况下使用SSL连接并使用SSL端口。
"pop3"协议默认为false,"pop3s"协议默认为true

1.3 API 环境设置

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

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

    
    <dependency>
        <groupId>javax.mailgroupId>
        <artifactId>mailartifactId>
        <version>1.4.7version>
    dependency>
    
    <dependency>
        <groupId>javax.activationgroupId>
        <artifactId>activationartifactId>
        <version>1.1.1version>
    dependency>
    
  • 使用com.sun.mail的坐标依赖包

    
    
    <dependency>
        <groupId>com.sun.mailgroupId>
        <artifactId>javax.mailartifactId>
        <version>x.y.zversion>
    dependency>
    
  • 使用Jakarta Mail发送邮件

    <dependency>
        <groupId>com.sun.mailgroupId>
        <artifactId>jakarta.mailartifactId>
        <version>x.y.zversion>
    dependency>
    

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

二、JavaMail 的关键对象

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

Class 说明
javax.mail.Session API的关键类,多线程对象表示连接工厂
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("[email protected]");

// 也可以通过邮箱地址和邮寄人姓名来创建
Address address = new InternetAddress("[email protected]", "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 默认的登陆用户名,例如:[email protected]
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 默认的登陆用户名,例如:[email protected]
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 服务器,如下图所示:

这个时候了,你还不会不知道JavaMail API吧_第2张图片

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

这个时候了,你还不会不知道JavaMail API吧_第3张图片

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

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("[email protected]");
        mailConfigInfo.setMailServerPassword("4f38d72caa78ffec");
        mailConfigInfo.setReceiver("[email protected]");
        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("[email protected]");
        mailConfigInfo.setMailServerPassword("4f38d72caa78ffec");
        mailConfigInfo.setReceiver("[email protected]");
        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("[email protected]");
        mailConfigInfo.setMailServerPassword("4f38d72caa78ffec");
        mailConfigInfo.setReceiver("[email protected]");
        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("[email protected]");
        mailConfigInfo.setMailServerPassword("4f38d72caa78ffec");
        mailConfigInfo.setReceiver("[email protected]");
        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", "");
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 = "

Hello

"
; 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", ""); 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("[email protected]"); mailConfigInfo.setMailServerPassword("4f38d72caa78ffec"); mailConfigInfo.setReceiver("[email protected]"); 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可选值
     * 

Message.RecipientType.TO 收件人

*

Message.RecipientType.CC 抄送

*

Message.RecipientType.BCC 密送

* @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("[email protected]"); 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.com smtp.sina.com imap.sina.com 25
QQ pop.qq.com smtp.qq.com imap.qq.com 465
网易163 pop.163.com smtp.163.com imap.163.com 465
谷歌邮箱 smtp.gmail.com 587
outlook smtp-mail.outlook.com 587

4.2 SMTP 服务器

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

属性 说明
mail.smtp.user String SMTP 的默认用户名
mail.smtp.host String 要连接的 SMTP 服务器
mail.smtp.port int 要连接的 SMTP 服务器端口,默认为 25
mail.smtp.connectiontimeout int 以毫秒为单位的套接字连接超时值默认为无限超时
mail.smtp.timeout int 以毫秒为单位的套接字 I/O 超时值默认为无限超时
mail.smtp.auth boolean 如果为 true,则尝试使用 AUTH 命令对用户进行身份验证默认为假
mail.smtp.auth.login.disable boolean 如果为 true,则阻止使用 AUTH LOGIN 命令默认为假
mail.smtp.auth.plain.disable boolean 如果为 true,则阻止使用 AUTH PLAIN 命令默认为假
mail.smtp.auth.digest-md5.disable boolean 如果为 true,则阻止使用 AUTH DIGEST-MD5 命令默认为假
mail.smtp.auth.ntlm.disable boolean 如果为 true,则阻止使用 AUTH NTLM 命令默认为假
mail.smtp.auth.ntlm.domain String NTLM 身份验证域
mail.smtp.auth.ntlm.flags int NTLM 协议特定标志
mail.smtp.dsn.ret String MAIL 命令的 RET 选项FULL 或 HDRS
mail.smtp.sasl.authorizationid String 在 SASL 身份验证中使用的授权 ID如果未设置,则使用身份验证 ID
mail.smtp.sasl.realm String 用于 DIGEST-MD5 身份验证的领域
mail.smtp.quitwait boolean 如果设置为 false,则发送 QUIT 命令并立即关闭连接
如果设置为 true(默认值),则导致传输等待对 QUIT 命令的响应
mail.smtp.socketFactory.port int 指定使用指定套接字工厂时要连接的端口如果未设置,将使用默认端口
mail.smtp.ssl.enable boolean 如果设置为 true,则默认使用 SSL 连接并使用 SSL 端口“smtp”协议
mail.smtp.ssl.checkserveridentity boolean 如果设置为 true,则检查 RFC 2595 指定的服务器标识。默认为 false
mail.smtp.ssl.trust String 如果设置,并且未指定套接字工厂,则启用 MailSSLSocketFactory
mail.smtp.socks.host string 指定将用于连接到邮件服务器的 SOCKS5 代理服务器的主机名
mail.smtp.mailextension String 附加到 MAIL 命令的扩展字符串

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

4.2 IMAP 服务器

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

属性 类型 描述
mail.imap.user String IMAP 的默认用户名。
mail.imap.host String 要连接的 IMAP 服务器。
mail.imap.port int 要连接的 IMAP 服务器端口。默认为 143
mail.imap.partialfetch boolean 控制是否应使用 IMAP 部分提取功能。默认为真
mail.imap.fetchsize int 部分提取大小(以字节为单位)。默认为 16K
mail.imap.connectiontimeout int 以毫秒为单位的套接字连接超时值。默认为无限超时
mail.imap.timeout int 以毫秒为单位的套接字 I/O 超时值。默认为无限超时
mail.imap.statuscachetimeout int 响应缓存的超时值(以毫秒为单位)。
默认值为 1000,零禁用
mail.imap.appendbuffersize int 附加到 IMAP 文件夹时要在内存中缓冲的消息的最大大小
mail.imap.connectionpoolsize int 连接池中可用连接的最大数量。默认值为 1
mail.imap.connectionpooltimeout int 连接池连接的超时值(以毫秒为单位),默认值为 45000
mail.imap.separatestoreconnection boolean 用于指示是否对存储命令使用专用存储连接的标志
mail.imap.auth.plain.disable boolean 如果为 true,则阻止使用 AUTHENTICATE PLAIN 命令
mail.imap.auth.ntlm.disable boolean 如果为 true,则阻止使用 AUTHENTICATE NTLM 命令
mail.imap.sasl.mechanisms String 要尝试使用的 SASL 机制名称的空格或逗号分隔列表。
mail.imap.sasl.authorizationid String 在 SASL 身份验证中使用的授权 ID。
如果未设置,则使用身份验证 ID(用户名)
mail.imap.sasl.realm String 与需要领域的 SASL 身份验证机制一起使用的领域
mail.imap.auth.ntlm.domain String NTLM 身份验证域。
mail.imap.auth.ntlm.flags int NTLM 协议特定标志。
mail.imap.ssl.enable boolean 如果设置为 true,则默认使用 SSL 连接并使用 SSL 端口
mail.imap.ssl.checkserveridentity boolean 如果设置为 true,请检查 RFC 2595 指定的服务器标识
mail.imap.ssl.trust String 如果设置,并且未指定套接字工厂,则启用 MailSSLSocketFactory
mail.imap.socks.host string 指定将用于连接到邮件服务器的 SOCKS5 代理服务器的主机名
mail.imap.minidletime int 此属性以毫秒为单位设置延迟。如果未设置,则默认为 10 毫秒

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

4.3 POP3 服务器

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

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

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

你可能感兴趣的:(服务器,网络,http)