邮件的发送和接收过程
图示的六个步骤分别进行如下的说明:
①、用户A的电子邮箱为:xx@qq.com,通过邮件客户端软件写好一封邮件,交到QQ的邮件服务器,这一步使用的协议是SMTP,对应图示的①;
②、QQ邮箱会根据用户A发送的邮件进行解析,也就是根据收件地址判断是否是自己管辖的账户,如果收件地址也是QQ邮箱,那么会直接存放到自己的存储空间。这里我们假设收件地址不是QQ邮箱,而是163邮箱,那么QQ邮箱就会将邮件转发到163邮箱服务器,转发使用的协议也是SMTP,对应图示的②;
③、163邮箱服务器接收到QQ邮箱转发过来的邮件,也会判断收件地址是否是自己,发现是自己的账户,那么就会将QQ邮箱转发过来的邮件存放到自己的内部存储空间,对应图示的③;
④、用户A将邮件发送了之后,就会通知用户B去指定的邮箱收取邮件。用户B会通过邮件客户端软件先向163邮箱服务器请求,要求收取自己的邮件,对应图示的④;
⑤、163邮箱服务器收到用户B的请求后,会从自己的存储空间中取出B未收取的邮件,对应图示⑤;
⑥、163邮箱服务器取出用户B未收取的邮件后,将邮件发给用户B,对应图示的⑥;最后三步用户B收取邮件的过程,使用的协议是POP3;
上面的步骤可能大家不太明白,这里面出现了很多名词,比如邮件客户端软件,邮件服务器,SMTP和POP3协议(邮件传输协议)等等。不明白没关系,接下来我们来详细介绍这些名词。
1、邮件服务器
图示出现了两个邮件服务器,QQ和163邮件服务器。用户想要在网上收发邮件,必须要有专门的邮件服务器。邮件服务器我们可以假想为现实生活中的邮局。
如果按功能划分,邮件服务器可以划分为两种类型:
①、SMTP邮件服务器:用户替用户发送邮件和接收外面发送给本地用户的邮件,对应上图的第一、二步。它相当于现实生活中邮局的邮件接收部门(可接收普通用户要投出的邮件和其他邮局投递进来的邮件)。
②、POP3/IMAP邮件服务器:用户帮助用户读取SMTP邮件服务器接收进来的邮件,对应上图的第六步。它相当于专门为前来取包裹的用户提供服务的部门。
2、电子邮箱
电子邮箱也称为E-mail地址,比如用户A的xx@qq.com,和用户B的xx@163.com。用户能通过E-mail地址标识自己发送的电子邮件,同时也可以通过这个地址接收别人发来的电子邮件。电子邮箱需要到邮件服务器进行申请,也就是说,电子邮箱其实就是用户在邮件服务器上申请的账户。邮件服务器会把接收到的邮件保存到为该账户所分配的邮箱空间中,用户通过用户名密码登录到邮件服务器查收该地址已经收到的邮件。一般来讲,邮件服务器为用户分配的邮箱空间是有限的。
3、邮件传输协议
电子邮件需要在邮件客户端和邮件服务器之间,以及两个邮件服务器之间进行邮件传递,那就必须要遵守一定的规则,这个规则就是邮件传输协议。下面我们分别简单介绍几种协议(后面会详细讲解):
①、SMTP协议:全称为 Simple Mail Transfer Protocol,简单邮件传输协议。它定义了邮件客户端软件和SMTP邮件服务器之间,以及两台SMTP邮件服务器之间的通信规则。
②、POP3协议:全称为 Post Office Protocol,邮局协议。它定义了邮件客户端软件和POP3邮件服务器的通信规则。
③、IMAP协议:全称为 Internet Message Access Protocol,Internet消息访问协议,它是对POP3协议的一种扩展,也是定义了邮件客户端软件和IMAP邮件服务器的通信规则。
我们说所有的邮件服务器和邮件客户端软件程序都是基于上面的协议编写的。
JavaMail介绍
JavaMail 是sun公司(现以被甲骨文收购)为方便Java开发人员在应用程序中实现邮件发送和接收功能而提供的一套标准开发包,它支持一些常用的邮件协议,如前面所讲的SMTP,POP3,IMAP,还有MIME等。我们在使用JavaMail API 编写邮件时,无须考虑邮件的底层实现细节,只要调用JavaMail 开发包中相应的API类就可以了。
1、JavaMail API
JavaMail API 按照功能可以划分为如下三大类:
①、创建和解析邮件的API
②、发送邮件的API
③、接收邮件的API
以上三种类型的API在JavaMail 中由多个类组成,但是主要有四个核心类,我们在编写程序时,记住这四个核心类,就很容易编写出Java邮件处理程序。
①、Message 类:javax.mail.Message 类是创建和解析邮件的核心 API,这是一个抽象类,通常使用它的子类javax.mail.internet.MimeMessage 类。它的实例对象表示一份电子邮件。客户端程序发送邮件时,首先使用创建邮件的 JavaMail API 创建出封装了邮件数据的 Message 对象,然后把这个对象传递给邮件发送API(Transport 类) 发送。客户端程序接收邮件时,邮件接收API把接收到的邮件数据封装在Message 类的实例中,客户端程序在使用邮件解析API从这个对象中解析收到的邮件数据。
②、Transport 类:javax.mail.Transport 类是发送邮件的核心API 类,它的实例对象代表实现了某个邮件发送协议的邮件发送对象,例如 SMTP 协议,客户端程序创建好 Message 对象后,只需要使用邮件发送API 得到 Transport 对象,然后把 Message 对象传递给 Transport 对象,并调用它的发送方法,就可以把邮件发送给指定的 SMTP 服务器。
③、Store 类:javax.mail.Store 类是接收邮件的核心 API 类,它的实例对象代表实现了某个邮件接收协议的邮件接收对象,例如 POP3 协议,客户端程序接收邮件时,只需要使用邮件接收 API 得到 Store 对象,然后调用 Store 对象的接收方法,就可以从指定的 POP3 服务器获得邮件数据,并把这些邮件数据封装到表示邮件的 Message 对象中。
④、Session 类:javax.mail.Session 类用于定义整个应用程序所需的环境信息,以及收集客户端与邮件服务器建立网络连接的会话信息,例如邮件服务器的主机名、端口号、采用的邮件发送和接收协议等。Session 对象根据这些信息构建用于邮件收发的 Transport 和 Store 对象,以及为客户端创建 Message 对象时提供信息支持。
JavaMail实现简单的纯文本传输
package com.wheatdr.util;
import javax.mail.*;
import javax.mail.Message.RecipientType;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Date;
import java.util.Properties;
public class MailUtil {
// 发件人的 邮箱 和 密码(替换为自己的邮箱和密码)
// PS: 某些邮箱服务器为了增加邮箱本身密码的安全性,给 SMTP 客户端设置了独立密码(有的邮箱称为“授权码”),
// 对于开启了独立密码的邮箱, 这里的邮箱密码必需使用这个独立密码(授权码)。
public static String account = "729328918@qq.com";
public static String password = "lmlgyaeryizobdfj";
// 发件人邮箱的 SMTP 服务器地址, 必须准确, 不同邮件服务器地址不同, 一般(只是一般, 绝非绝对)格式为: smtp.xxx.com
// 网易163邮箱的 SMTP 服务器地址为: smtp.163.com
public static String myEmailSMTPHost = "smtp.qq.com";
/**
* 发送邮件的方法
*
* @param to
* 邮件的接收方
* @param code
* 邮件的激活码
*/
public static void sendMail(String to, String code) {
// 1.创建连接对象,链接到邮箱服务器
Properties props = new Properties();// 参数配置
props.setProperty("mail.transport.protocol", "smtp");// 使用的协议(JavaMail规范要求)
props.setProperty("mail.smtp.host", myEmailSMTPHost);// 发件人的邮箱的 SMTP
// 服务器地址
props.setProperty("mail.smtp.auth", "true");// 需要请求认证
// 2.根据配置创建会话对象, 用于和邮件服务器交互
Session session = Session.getInstance(props, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(account, password);
}
});
try {
// 3.创建邮件对象
Message message = new MimeMessage(session);
// 3.1设置发件人
message.setFrom(new InternetAddress(account));
// 3.2设置收件人
message.setRecipient(RecipientType.TO, new InternetAddress(to));
// 3.3设置邮件的主题
message.setSubject("来自麦博士的激活邮件");
// 3.4设置邮件的正文
// message.setContent("<h1>来自智慧电梯的激活邮件,您的验证码是:</h1><h3><a href='http://localhost:10080/Demo_JavaMail/active?code="
// + code + "'>http://localhost:10080/Demo_JavaMail/active?code=" +
// code + "</h3>", "text/html;charset=UTF-8");
message.setContent("<h1>来自麦博士的激活邮件,您的验证码是:" + code,
"text/html;charset=UTF-8");
// 4.发送邮件
Transport.send(message);
} catch (MessagingException e) {
e.printStackTrace();
}
}
/**
* 发送找回密码邮件的方法
*
* @param to
* 邮件的接收方
* @param code
* 邮件的验证码
*/
public static void findPasswordMail(String to, String code) {
// 1.创建连接对象,链接到邮箱服务器
Properties props = new Properties(); // 参数配置
props.setProperty("mail.transport.protocol", "smtp");// 使用的协议(JavaMail规范要求)
props.setProperty("mail.smtp.host", myEmailSMTPHost);// 发件人的邮箱的 SMTP
// 服务器地址
props.setProperty("mail.smtp.auth", "true"); // 需要请求认证
// 2.根据配置创建会话对象, 用于和邮件服务器交互
Session session = Session.getInstance(props, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(account, password);
}
});
try {
// 3.创建邮件对象
Message message = new MimeMessage(session);
// 3.1设置发件人
message.setFrom(new InternetAddress(account));
// 3.2设置收件人
message.setRecipient(RecipientType.TO, new InternetAddress(to));
// 3.3设置邮件的主题
message.setSubject("来自平台的验证邮件");
// 3.4设置邮件的正文
message.setContent(
"<h1>来自平台的验证邮件,请点击以下链接进行重置密码:</h1><h3><a href='http://localhost:10080/Demo_JavaMail/check?code="
+ code
+ "'>http://localhost:10080/Demo_JavaMail/check?code="
+ code + "</h3>", "text/html;charset=UTF-8");
// 4.发送邮件
Transport.send(message);
} catch (MessagingException e) {
e.printStackTrace();
}
}
/**
* 创建一封只包含文本的简单邮件
*
* @param session
* 和服务器交互的会话
* @param sendMail
* 发件人邮箱
* @param receiveMail
* 收件人邮箱
* @return
* @throws Exception
*/
public static MimeMessage createMimeMessage(Session session,
String sendMail, String receiveMail) throws Exception {
// 1. 创建一封邮件
MimeMessage message = new MimeMessage(session);
// 2. From: 发件人
message.setFrom(new InternetAddress(sendMail, "某宝网", "UTF-8"));
// 3. To: 收件人(可以增加多个收件人、抄送、密送)
message.setRecipient(MimeMessage.RecipientType.TO, new InternetAddress(
receiveMail, "XX用户", "UTF-8"));
// 4. Subject: 邮件主题
message.setSubject("打折钜惠", "UTF-8");
// 5. Content: 邮件正文(可以使用html标签)
message.setContent("XX用户你好, 今天全场5折, 快来抢购, 错过今天再等一年。。。",
"text/html;charset=UTF-8");
// 6. 设置发件时间
message.setSentDate(new Date());
// 7. 保存设置
message.saveChanges();
return message;
}
public static void main(String[] args) {
MailUtil mailUtil = new MailUtil();
mailUtil.sendMail("1578065005@qq.com", "zjp");//接收方 接受码
}
}
3.问题:
①、发件人的邮箱账户名和密码:有的邮箱设置了独立密码,还有的必须用授权码登录(qq邮箱),这在 手工体验smtp和pop3协议 这篇博客中有介绍。
②、发件人的SMTP服务器地址:一般是 smtp.xxx.com,比如163邮箱是smtp.163.com,qq邮箱是smtp.qq.com。
③、有可能你收件人地址,发件人地址等信息都正确了,控制台也打印了正确的信息,但是在收件箱就是收不到信息。这是因为可能收件箱服务器拒收了你发的邮件(比如认为你的邮件是广告),这时候可能在垃圾箱里能找到,可能找不到。解决办法是重复的邮件内容不要多次发送,或者更换收件箱试试。
④、本实例使用的是JavaMail1.6版本,支持的JDK必须是jdk1.7版本!!!