这个时候了,你还不会不知道JavaMail API吧
一、概述
1.1 简述
JavaMail API 顾名思义,提供给开发者处理电子邮件相关的编程接口,它是Sun发布的用来处理email的API,其提供独立于平台且与协议无关的框架来构建邮件和消息传递应用。JavaMail API 提供了一组抽象类,用于定义组成邮件系统的对象,它是一个可选包(标准扩展),用于阅读,撰写和发送电子信息。
1.2 邮件协议
JavaMail 提供了用于构造消息系统接口的元素,包括系统组件和接口。虽然本规范没有定义任何特定的实现,但 JavaMail 确实包含了几个实现 RFC822 和 MIME Internet 消息传递标准的类,这些类是作为 JavaMail 类包的一部分提供的。在收发邮件的过程中,需要遵守相关的协议,JavaMail并不是绝对支持每一个协议,其中主要有:
协议 | 说明 |
---|---|
SMTP | 单间邮件传输协议,用于发送电子邮件的传输协议 |
POP3 | 用于接受电子邮件的标准协议 |
IMAP | 互联网消息协议,是POP3的替代协议 |
1.2.1 什么是SMTP?
SMTP 全称为Simple Mail Transfer Protocol
,即简单邮件传输协议,它是一组用于从源地址到目的地址传输邮件的规范,通过它来控制邮件的中转方式。SMTP 认证要求必须提供账号和密码才能登陆服务器,其设计目的在于避免用户受到垃圾邮件的侵扰。
针对不同的的邮件协议,JavaMail规定了服务提供者必须支持一系列属性,下表是针对SMTP协议的一些常见属性。
名称 | 类型 | 描述 |
---|---|---|
mail.smtp.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() {@Overridepublic 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,一般情况都设置为trueproperties.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() {@Overridepublic PasswordAuthentication getPasswordAuthentication() {return new PasswordAuthentication(mailSenderInfo.getMailServerUser(), mailSenderInfo.getMailServerPassword());}};}// 根据邮件会话属性和密码验证器构造一个发送邮件的sessionsendMailSession = Session.getDefaultInstance(properties, authenticator);// 若是设置为debug模式,可以查看详细的发送日志sendMailSession.setDebug(mailSenderInfo.isDebugMode());return sendMailSession;}/*** 使用 JavaMail 以文本格式发送邮件** @param mailSenderInfo 待发送的邮件信息*/public static void sendTextEmail(MailSenderInfo mailSenderInfo) throws MessagingException, UnsupportedEncodingException {// 1. 根据邮件会话属性和密码验证器构造一个发送邮件的sessionSession 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,一般情况都设置为trueproperties.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() {@Overridepublic PasswordAuthentication getPasswordAuthentication() {return new PasswordAuthentication(mailSenderInfo.getMailServerUser(), mailSenderInfo.getMailServerPassword());}};}// 根据邮件会话属性和密码验证器构造一个发送邮件的sessionsendMailSession = Session.getDefaultInstance(properties, authenticator);// 若是设置为debug模式,可以查看详细的发送日志sendMailSession.setDebug(mailSenderInfo.isDebugMode());return sendMailSession;}/*** 使用 JavaMail 群发邮件** @param mailSenderInfo 待发送的邮件信息*/public void sendTextEmails(MailSenderInfo mailSenderInfo) throws MessagingException, UnsupportedEncodingException {// 1. 创建一封邮件,获取一个SessionSession 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,一般情况都设置为trueproperties.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() {@Overridepublic PasswordAuthentication getPasswordAuthentication() {return new PasswordAuthentication(mailSenderInfo.getMailServerUser(), mailSenderInfo.getMailServerPassword());}};}// 根据邮件会话属性和密码验证器构造一个发送邮件的sessionsendMailSession = Session.getDefaultInstance(properties, authenticator);// 若是设置为debug模式,可以查看详细的发送日志sendMailSession.setDebug(mailSenderInfo.isDebugMode());return sendMailSession;}/*** 使用 JavaMail 发送带附件的邮件** @param mailSenderInfo 待发送的邮件信息*/public static void sendAttachEmail(MailSenderInfo mailSenderInfo) throws MessagingException, UnsupportedEncodingException {// 1. 创建一封邮件,获取一个SessionSession 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,一般情况都设置为trueproperties.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() {@Overridepublic PasswordAuthentication getPasswordAuthentication() {return new PasswordAuthentication(mailSenderInfo.getMailServerUser(), mailSenderInfo.getMailServerPassword());}};}// 根据邮件会话属性和密码验证器构造一个发送邮件的sessionsendMailSession = 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. 根据邮件会话属性和密码验证器构造一个发送邮件的sessionSession 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,一般情况都设置为trueproperties.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() {@Overridepublic PasswordAuthentication getPasswordAuthentication() {return new PasswordAuthentication(mailSenderInfo.getMailServerUser(), mailSenderInfo.getMailServerPassword());}};}// 根据邮件会话属性和密码验证器构造一个发送邮件的sessionsendMailSession = Session.getDefaultInstance(properties, authenticator);// 若是设置为debug模式,可以查看详细的发送日志sendMailSession.setDebug(mailSenderInfo.isDebugMode());return sendMailSession;}/*** 使用 JavaMail 发送内嵌图像中的邮件** @param mailSenderInfo 待发送的邮件信息*/public static void sendImageEmail(MailSenderInfo mailSenderInfo) throws UnsupportedEncodingException, MessagingException {// 1. 创建一封邮件,获取一个SessionSession 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,一般情况都设置为trueproperties.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() {@Overridepublic PasswordAuthentication getPasswordAuthentication() {return new PasswordAuthentication(mailConfigInfo.getMailServerUser(), mailConfigInfo.getMailServerPassword());}};}// 根据邮件会话属性和密码验证器构造一个发送邮件的sessionsendMailSession = 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协议无法获知邮件的状态,所以下面(删除、新邮件)得到的结果始终都是为0emailInfo.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. 创建一封邮件,获取一个SessionSession 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 对象。
相关文章:

这个时候了,你还不会不知道JavaMail API吧
一、概述 1.1 简述 JavaMail API 顾名思义,提供给开发者处理电子邮件相关的编程接口,它是Sun发布的用来处理email的API,其提供独立于平台且与协议无关的框架来构建邮件和消息传递应用。JavaMail API 提供了一组抽象类,用于定义组…...

JavaScript var let区别
文章目录JavaScript var & let区别变量作用域变量提升变量重复声明全局对象属性for循环中的作用域JavaScript var & let区别 var和let都是用来声明变量的关键字。 变量作用域 var声明的变量作用域是函数作用域或全局作用域,而let声明的变量作用域是块级作…...

Thinkphp 6.0容器和依赖注入
本节课我们来学习一下依赖注入的用法,以及容器的用法。 一.依赖注入 1. 手册对依赖注入比较严谨的说明,具体如下: 依赖注入其实本质上是指对类的依赖通过构造器完成自动注入,例如在控制器架构方法和操作 方法中一旦对参…...

Type javax.servlet.http.HttpServletRequest not present
运行环境 Swagger 3.0.0、springboot 3.0.0 产生原因: Swagger 3.0.0不支持spring3.0.0 两个解决方案: 1.降低springboot版本为2.x 2.放弃Swagger,使用 springdoc-openapi-starter-webmvc-ui 第二种解决方案: <dependen…...

一键配置Ubuntu的OpenHarmony基础编译环境
一键配置Ubuntu的OpenHarmony基础编译环境 一、配置前说明 该更新源仅适用于Ubuntu以下系列 Ubuntu18.04 Ubuntu20.04 Ubuntu22.04 强烈推荐Ubuntu20.04,本人使用的一直都是Ubuntu20.04 wsl的配置参见 如果使用的window wsl安装,则关于wsl配置可参考&a…...

ASP网络求职招聘系统的设计与实现
本文主要介绍了ASP,数据库等相关知识,同时较为详尽的阐述了网络求职招聘系统的实现。本系统是使用基于HTML语言,嵌套JavaScript源代码的ASP编程技术来开发,并以IIS为服务平台实现网络求职招聘系统的构建。后台数据库选用的是ACCES…...

面试—C++《智能指针》常考点
目录 1.为什么需要智能指针 2. 内存泄漏 2.1 什么是内存泄漏,内存泄漏的危害 2.2 内存泄漏分类 2.3 如何检测内存泄漏 2.4如何避免内存泄漏 3.智能指针的使用及原理 3.3 std::auto_ptr 3.4 std::unique_ptr 3.5 std::shared_ptr 1.为什么需要智能指针 下…...

自动化测试方案编写思路
澄清问题: 目标:完成项目的自动化测试,设计一个方案,告诉领导打算怎么做?有哪些流程?花多长时间?需要哪些资源帮助?达到什么样的效果? 现状:需求分析-是个什么样的项目&a…...

【爬虫】案例04:某小说网多线程小说下载
时光轮回,冬去春来,转眼时间来到了2023年4月。天空沥沥淅淅下着小雨,逐渐拉上了幕布。此刻,正值魔都的下班高峰,从地铁站出来的女孩子纷纷躲到一边,手指飞快的划过手机屏幕,似乎在等待男朋友送来…...

海外独立站创业,Shopify网站如何引流
上一期给大家科普了如何快速创建自己的独立站 但往往独立站的难点在于站外引流 今天就给大家分享可以通过哪些渠道给独立站引流 - ⚡SEO排名:Google SEO的重要性不必多说,尽快注册歌账号,并开通Google Ad和Google Merchant Center&#…...

基于51单片机的室内湿度加湿温度声光报警智能自动控制装置设计
wx供重浩:创享日记 对话框发送:单片机湿度 获取完整无水印论文报告(内含电路原理图和源程序代码) 在日常生活中加湿器得到了广泛的应用,但是现有的加湿器都需要手工控制开启和关闭并且不具备对室内空气温湿度的监测&am…...

解决:github爆 WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!
目录1. 背景2. 解决办法3. 原因,感兴趣的可以看看1. 背景 在拉取github上一个新项目的时候爆出 WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! 第一反应是电脑被黑了,传说中的中间人攻击(题外话一下,其实所有的代理软件都算是中间人哦~…...

【django开发手册】如何使用select_related进行一次连表查询
前言 Django是一款Python Web框架,致力于充分利用Python的简洁语法和语言特性来提高Web开发的效率。其中一个强大的特性是ORM(Object-Relational Mapping),它使开发者可以使用Python代码而不是SQL查询语言来访问数据库。ORM不仅使…...

二、MySQL 基础
二、MySQL 基础 2.1 MySQL 简介 MySQL 是一款流行的开源数据库,也是一个关系型数据库管理系统 在 WEB 应用方面 MySQL 是最好的 RDBMS(Relational Database Management System:关系数据库管理系统)应用软件之一 2.1.1 MySQL 发展历史 时间里程碑1996…...

项目中常用写法(前端)
项目中常用写法(前端)vue等待某个方法执行结束后,在执行判断js是不是undefined类型父组件传值到子组件state的值在标签中直接使用读取html,去掉字符串中的html标签字符串去掉中括号去掉双引号判断数组中是否包含某个值在某个ui框架…...

【面试】Java并发编程面试题
文章目录基础知识为什么要使用并发编程多线程应用场景并发编程有什么缺点并发编程三个必要因素是什么?在 Java 程序中怎么保证多线程的运行安全?并行和并发有什么区别?什么是多线程多线程的好处多线程的劣势:线程和进程区别什么是…...

HAProxy和Nginx搭建负载均衡器
负载均衡器是一个常用于分布式计算和网络应用中的系统组件,主要用于将客户端的请求分发到多个后端服务器上,以实现高可用性、高性能和可扩展性。常见的负载均衡器软件包括HAProxy和Nginx。 本文将介绍负载均衡器的原理和应用,以及使用HAProx…...

【集大成篇】数据类型( C、C++、Java )对比
1、C 语言数据类型关键字取值范围内存占用字符型char -128~1271整 型short-32768~327672int-2147483648~2147483647 (10位数)4long (int)-2147483648~2147483647 (10位数)4/8long long (int)-9223372036854775808~-9223372036854775807 (19位数ÿ…...

python编程:从键盘输入一个正整数n(n>2),请编程求解并输出大小最接近n的素数(n本身除外)
python编程实现:从键盘输入一个正整数n(n>2),请编程求解并输出大小最接近n的素数(n本身除外) 一、编程题目 从键盘输入一个正整数n(n>2),请编程求解并输出大小最接近n的素数(n本身除外)。 (温馨提示,结果可能是2个哦) 二、输入输出样例…...

spring的面试宝典
1、什么是spring框架? spring是一个开放源代码的设计层面框架,它解决的是业务逻辑层和其他各层的松耦合问题,是一个分层的javaEE一站式轻量级开源框 架. 2.spring的作用? 方便解耦,简化开发,AOP编程支持,声明式事务支持,集成Juni…...

ArcGIS Pro地理空间数据处理完整工作流实训及python技术融合深度应用
查看原文>>>ArcGIS Pro地理空间数据处理完整工作流实训及python技术融合深度应用 目录 第一章、ArcGIS Pro基础讲解 第二章、数据获取、整合与管理 第三章、坐标系基础与地理配准 第四章、数据编辑与查询、拓扑检查 第五章、制图基础讲解 第六章、地理处理工具…...

(二)MyBatis源码阅读:SqlSession分析
一、核心流程 以下代码便是MyBatis的核心流程,我们从该代码出发分析MyBatis的源码。 Testpublic void test2() throws Exception{// 1.获取配置文件InputStream in Resources.getResourceAsStream("mybatis-config.xml");// 2.加载解析配置文件并获取Sq…...

小白学Pytorch系列-- torch.autograd API
小白学Pytorch系列-- torch.autograd API torch.Autograd提供了实现任意标量值函数的自动微分的类和函数。它只需要对现有代码进行最小的更改-你只需要声明张量s,它的梯度应该用requires gradTrue关键字计算。到目前为止,我们只支持浮点张量类型(half, f…...

【大数据基础】基于零售交易数据的Spark数据处理与分析
环境搭建 sudo apt-get install python3-pip pip3 install bottle数据预处理 首先,将数据集E_Commerce_Data.csv上传至hdfs上,命令如下: ./bin/hdfs dfs -put /home/hadoop/E_Commerce_Data.csv /user/hadoop接着,使用如下命令…...

【机器学习】P14 Tensorflow 使用指南 Dense Sequential Tensorflow 实现
Tensorflow 第一节:使用指南Tensorflow 安装神经网络一些基本概念隐藏层和输出层:神经元的输出公式Tensorflow 全连接层 Dense 与 顺序模型 SequentialDense LayerSequential Model代码实现一个神经网络实现方式一:手写神经网络* 实现方式二&…...

ubuntu18.04安装nvidia驱动,3种方式图文详解+卸载教程
教程目录一、关闭secure boot二、禁用nouveau驱动2.1 创建配置文件2.2 添加内容2.3 重启电脑2.4 输入命令验证三、安装显卡驱动3.1 软件和更新(失败)3.2 PPA源安装3.3 官网安装包安装四、卸载显卡驱动笔记本类型Ubuntu系统显卡版本联想拯救者Y7000win10U…...

多线程进阶学习11------CountDownLatch、CyclicBarrier、Semaphore详解
CountDownLatch ①. CountDownLatch主要有两个方法,当一个或多个线程调用await方法时,这些线程会阻塞 ②. 其它线程调用countDown方法会将计数器减1(调用countDown方法的线程不会阻塞) ③. 计数器的值变为0时,因await方法阻塞的线程会被唤醒,继续执行 public static void m…...

华为OD机试用java实现 -【RSA 加密算法】
最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为od机试,独家整理 已参加机试人员的实战技巧本篇题解:RSA 加密算法 题目 RSA 加密…...

技术宅小伙:大龄程序员就业,未来我们将何去何从?
程序员是一个高薪高压的职业,同时也是一个需要不断学习的职业。随着技术的不断更新换代,程序员需要不断地学习新的知识和技能,以适应市场的需求。然而,有些程序员可能会遭遇裁员,失去了稳定的收入来源。有些程序员可能…...

Spring Boot+Vue实现Socket通知推送
目录 Spring Boot端 第一步,引入依赖 第二步,创建WebSocket配置类 第三步,创建WebSocket服务 第四步,创建Controller进行发送测试 Vue端 第一步,创建连接工具类 第二步,建立连接 编辑 第三步&a…...