一、概述
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的坐标依赖包
<!-- 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.mail 和 javax.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("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 类唯一的构造函数是受保护的,但Session
、Store
都有一个类似的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_ONLY或Folder.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 |
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 对象。