email学习笔记
邮件发送的基本过程与概念
邮件发送的过程
graph LR userA(("用户A
xx@qq.com")) userA--"1"-->clientA clientA["邮件客户端
FoxMail"] clientA--"2"-->qqServerModule2 subgraph QQ邮箱服务器 qqServerModule1("POP3服务器") qqServerModule2("SMTP服务器") qqServerModule3("QQ邮箱
内部存储空间") end qqServerModule2--"3"-->163ServerModule2 subgraph 163邮箱服务器 163ServerModule1("POP3服务器") 163ServerModule2("SMTP服务器") 163ServerModule3("163邮箱
内部存储空间") 163ServerModule2--"4"-->163ServerModule3 163ServerModule1--"7"-->163ServerModule3 163ServerModule3--"8"-->163ServerModule1 end userB(("用户B
xx@163.com")) userB--"5"-->clientB clientB["邮件客户端
FoxMail"] clientB--"6"-->163ServerModule1 163ServerModule1--"9"-->clientB clientB--"10"-->userB
1.用户A写完一封邮件通过客户端(如Foxmail)使用SMTP协议发送到邮箱的SMTP服务器
2.邮箱SMTP服务器收到邮件后会判断收件人是否是自己管辖内的账户
如果是就会直接放入自己的存储空间
如果不是就会通过SMTP协议发送给对应的对应地址的SMTP服务器
3.用户B通过客户端向POP3服务端服务器请求收取自己的邮件
4.POP3服务器收到请求之后查询内部存储空间
如果有邮件则通过POP3协议发送给用户B
如果没有就返回空
邮件传输协议
- SMTP协议:全称为 Simple Mail Transfer Protocol,简单邮件传输协议
它定义了邮件客户端软件和SMTP邮件服务器之间,以及两台SMTP邮件服务器之间的通信规则 - POP3协议:全称为 Post Office Protocol,邮局协议
它定义了邮件客户端软件和POP3邮件服务器的通信规则 - IMAP协议:全称为 Internet Message Access Protocol,Internet消息访问协议
它是对POP3协议的一种扩展,也是定义了邮件客户端软件和IMAP邮件服务器的通信规则邮件服务器于客户端
- SMTP服务器:通过SMTP协议接收和发送邮件
- POP3服务器:通过POP3协议发送邮件的服务器
- 客户端:邮件客户端软件通常集邮件撰写/发送和收发功能于一体
主要用于帮助用户将邮件发送给SMTP邮件服务器和从POP3/IMAP邮件服务器读取用户的电子邮件
比如常见的FoxMail,Outlook Express手工体验smtp和pop3协议
SMTP简介
SMTP协议:全称为 Simple Mail Transfer Protocol,简单邮件传输协议.它定义了邮件客户端软件和SMTP邮件服务器之间,以及两台SMTP邮
件服务器之间的通信规则
SMTP协议的通信双方采用一问一答的命令/响应形式进行对话
SMTP协议分为标准SMTP协议和扩展SMTP协议标准SMTP协议是1982年在RFC821 文档中定义的
扩展SMTP协议是1995年在RFC1869 文档中定义的扩展SMTP协议在标准 SMTP协议基础上的改动非常小,主要增加了邮件安全方面的认证功能,现在我们说的SMTP协议基本上都是扩展SMTP协议
参考文档:https://tools.ietf.org/html/rfc1869
SMTP协议中的命令
SMTP 协议中一共定义了18条命令
但是发送一封电子邮件的过程通常只需要6条命令
SMTP命令及格式 <SP>表示空格 <CRLF>表示回车换行 |
说明 |
---|---|
ehlo<SP><domain><CRLF> | ehlo命令是SMTP邮件发送程序与SMTP邮件接收程序建立连接后必须发送的第一条SMTP命令,参数<domain>表示SMTP邮件发送者的主机名,ehlo命令用于代替传统命令中的helo命令 |
auth<SP><para><CRLF> | 如果SMTP邮件接收程序需要SMTP邮件发送程序进行认证时,他向SMTP邮件发送程序提示它所采用的认证方式,SMTP邮件发送程序接着应该使用这个命令回应SMTP邮件接收程序,参数<para>表示回应的认证方式,通常是SMTP邮件接收程序先提示的认证方式 |
mail<SP>from:<reverse-path><CRLF> | 此命令用于指定邮件发送者的邮箱地址,参数<reverse-path>表示邮件发送人的邮箱地址 |
rcpt<SP>to:<froword-path><CRLF> | 此命令用于指定邮件接收者的邮箱地址,参数<forword-path>表示收件人的邮箱地址, 如果邮件要发送给多个接受者,那么应该使用多条rcpt<SP>to命令来分别指定每一个接受者的邮箱地址 |
data<CRLF> | 此命令用于表示SMTP邮件发送程序开始传动邮件内容,在这命令后面发送的所有数据都被当成邮件内容,直到遇见”<CRLF>.<CRLF>“标识符,则表示邮件内容结束 |
quit<CRLF> | 此命令表示要借宿邮件发送过程,SMTP邮件接收程序接收到此命令后将关闭与SMTP邮件服务器的连接 |
手动发送过程
graph LR root(使用SMTP协议手工发送邮件的步骤) root---step1("1.和SMTP服务器建立连接:
telnet smtp.163.com 25") root---step2("2.ehlo 邮件发送者用户名") root---step3("3.选择登陆认证方式") root---step4("4.分别输入经过Base64编码后的用户名和密码") root---step5("5.指明邮件的发送人和收件人") root---step6("6.编写邮件内容") root---step7("7.输入.表示邮件内容结束") root---step8("8.输入quit命令断开与邮件服务器的连接")
解释:
- 如果是qq,那么就将163换成qq即可,25换成587,25或者587是端口,其他邮箱同理
- 告诉SMTP服务器发送者的用户名
- 登录认证方式,我们一般使用login,即输入命令:auth:login qq邮箱需要先输入 starttls
- qq邮箱需要的是进过Base64编码的授权码
5.6.7.8. 没有什么坑,按照范例来就好
qq邮箱范例:
括号内的为备注
1 | telnet smtp.qq.com 587 |
手动接收邮件
graph LR root(使用SMTP协议手工接收邮件的步骤) root---step1("1.和SMTP服务器建立连接:
telnet pop3.163.com 110
telnet pop.qq.com 110") root---step2("2.user 用户名 qq要求必须是邮箱") root---step3("3.pass 密码 qq是授权码") root---step4("4.其他各种查看服务器邮件的命令") root---step5("8.输入quit命令断开与邮件服务器的连接")
qq邮箱范例:
1 | telnet pop.qq.com 110 |
这里有个比较坑的地方就是user和pass这一块的内容必须一次性的输入正确,不能修改,修改对了也没有用
相关命令详解
SMTP命令及格式 <SP>表示空格 <CRLF>表示回车换行 |
说明 |
---|---|
user<SP>username<CRLF> | user命令是POP3客户端程序与POP3邮件服务器建立后发送的第一条命令,参数username表示收件人的人账户名称(这里用原来的就好) |
pass<SP>password<CRLF> | pass命令是在user命令执行成功后接着发送的命令,参数password表示账户密码 |
stat<CRLF> | stat命令用于查询邮箱统计信息,后面的两个数字表示邮件的数目和占用字节大小(不过qq邮箱网页上的和我在这里看到不太一样) |
list<SP>[msg#]<CRLF> | list命令用于查出邮箱中邮件信息,msg#表示邮件序列号,是可选参数.当不指定时列出所有的邮件信息, |
uidl<SP>msg#<CRLF> | uidl命令查询谋一份邮件的唯一标识,参数msg#表示邮件序列号 |
retr<SP>msg#<CRLF> | retr命令获取某一封邮件内容,参数msg#表示邮件序列号 |
dele<SP>msg#<CRLF> | dele命令用于标记删除某一封邮件,不是立刻真的删除,只有执行quit命令退出POP3邮件服务器时才会真的删除 |
rest<CRLF> | rest命令用于清除所有删除标记 |
top<SP>msg#<SP>n<CRLF> | top命令用于获取序号为msg的邮件前n行内容 |
noop<CRLF> | noop命令用于检查POP3客户端与服务器的连接情况 |
quit<CRLF> | quit命令用于借宿邮件接收过程,执行此命令,POP3服务器会删除所有标记了的邮件,关闭与POP3客户端的连接 |
邮件内容详解
邮件遵循RFC822文档和MIME协议
RFC822文档定义邮件的基本格式
MIME协议定义邮件的具体细节
范例:
1 | Received: from vip.ccb.com (unknown [113.57.178.241]) |
RFC822文档
RFC822由邮件头和邮件组成
邮件头字段|说明
—|—
Received|该字段基本格式为Received: from A by B for C
,A为发送方,B为接收方,C为吉首人邮箱地址.由SMTP服务器填写
From|发件人邮件地址,邮件阅读器中发件人地址来源于此,可以乱写,可以不写,可以伪造.所以发件人不一定为真的
To|收件人地址
Subject|指定邮件主题,如果主题内容中包含ASCII码以外的字符,通常要对其内容编码
cc|邮件抄送地址
bcc|邮件密送地址,邮件阅读器通常不会显示密送地址,而会显示抄送地址
BRC822文档的两个问题:
- 定义了邮件的主体结构和邮件有地段的详细细节,但是没有定义邮件提的格式,RFC822文档定义的邮件体部分通常都只能用于表述一段普通的文本,而无法表达出图片/声音等二进制数据
- SMTP服务器在接收邮件内容是当收到单行
.
时会认为邮件已接收,可能造成内容缺失
MIME解决了这两个问题MIME协议
- 全称:Multipurpose Internet Mail Extension(协议)
- 中文翻译:多用途因特网邮件扩展(协议)
1
2
3
4
5
6
7Subject: =?GBK?B?1tC5+r2oyejS+NDQ0MXTw7+otefX09XLtaU=?=
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="----=_Part_1525_1669750793.1577397823338"
------=_Part_1525_1669750793.1577397823338
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: base64
一个采用了MIME协议的电子邮件就叫做MIME邮件
MIME邮件在RFC822文档中定义的邮件头字段的基础上,扩充了一些自己专用的邮件头字段,例如:使用MIME-Version头字段指定MIME协议的版本
使用Content-Type头字段指定邮件体的MIME类型
使用Content-Transfer-Encoding头字段指定编码方法其中,“multipart/mixed”部分说明邮件体中包含有多段数据,每段数据之间使用boundary属性中指定的字符文本作为分隔标识符
MIME邮件也扩展了RFC822文档中已经定义了的邮件头字段的内涵,例如:定义了subject头字段中的值内容的格式,以便通过编码的方式让邮件主题中也可以使用非ASCII码的字符
subject头字段中的值嵌套在一对=?
和?=
标记符之间,标记符之间的内容由三部分组成:
- 邮件主题的原始内容的字符集
- 当前采用的编码方式
- 编码后的结果
这三部分之间使用
?
进行分隔
JavaMail发送(带图片和附件)和接收邮件
JavaMail介绍
JavaMail是sun公司(现以被甲骨文收购)为方便Java开发人员在应用程序中实现邮件发送和接收功能而提供的一套标准开发包
它支持一些常用的邮件协议,如前面所讲的SMTP,POP3,IMAP,还有MIME等
我们在使用JavaMail API 编写邮件时,无须考虑邮件的底层实现细节,只要调用JavaMail开发包中相应的API类就可以了
JavaMail API
JavaMail API按照功能可以分为三大类:
- 创建和解析邮件的API
- 发送邮件的API
- 接收邮件的API
graph LR session1["Session对象:
定义整个程序所需环境信息,
比如主机名,端口号采用的邮件发送和接收的协议"] session1--创建-->transport transport["Transport对象:
用来发送邮件"] message1["Message对象:
表示一份电子邮件"] message1-.引用.->transport transport==>server server(("邮件服务器")) server==>store store["Store对象:
用来接收邮件"] session2["Session对象:
定义整个程序所需环境信息,
比如主机名,端口号采用的邮件发送和接收的协议"] session2--创建-->store store--创建-->message2 message2["Message对象:
表示一份电子邮件"]
以上三种类型的API由多个类组成,其中核心的由四个类:
Message类
:javax.mail.Message类
是创建和解析邮件的核心API,这是一个抽象类,通常使用它的子类javax.mail.internet.MimeMessage类
.它的实例对象表示一份电子邮件.客户端程序发送邮件时,首先使用创建邮件的JavaMail API创建出封装了邮件数据的Message对象
,然后把这个对象传递给邮件发送APITransport 类
发送.客户端程序接收邮件时,邮件接收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对象
时提供信息支持.
相关jar包
1 |
|
在引入javaMailAPI的同时还需要引入他的实现
使用JavaMailAPI实现发送和接收邮件
1 | package util; |
本文章参考[YSOcean博客][YSOcean博客]
https://www.cnblogs.com/ysocean/p/7652934.html
https://www.cnblogs.com/ysocean/p/7653252.html