原文:http://yinqingsong520.blog.163.com/blog/static/392100201012311275477/
里面有个关键内容,英文参考文档: http://en.wikipedia.org/wiki/Email
1.Email
=====================================
(1)email 的明文结构
首先认识一封相对完整的email的结构。以下是网页上得到的内容:
*---------------------------------------------------------
日 期: 2008-10-10 18:14:12
发件人: zengbenyuan <[email protected]>
收件人: "[email protected]" <[email protected]>
抄送人: (无)
主 题: Helloworld
附 件: Debian Package.txt(8.19K)
(正文)
Hi Tommy,
This is a mail for testing.
---------------------------------------------------------*
一封邮件主要分为头部(Header fields)和 主体(Body),头部主要包含邮件的附属信息,如时间、发件人、收件人、主题,主体主要包含正文、正文格式、以及附件信息
(2)email的源码分析
该邮件的源码包含以下部分:(完整源码参看附件一)
Received: (由邮件服务器自动添加的,与邮件服务器、日期相关的信息)
Date:(邮件发送者发送时的时间信息,格式通常为:Fri, 10 Oct 2008 18:14:12 +0800 (CST))
From:(邮件来自于哪个发送者,格式通常为:"zengbenyuan" <[email protected]>)
To:(邮件接收者,格式于发送者相同)
Subject:(邮件主题,部分邮件会将主题以64位编码形式加密,形式如=?gbk?B?z8TMzg==?= , 以=?开头,以?=结束)
Content-Type:内容类型,用于指定消息的类型(常用类型见 参考文档 Reference/MIME TYPE.html)
boundary=“”:划分多部分邮件的边界,通常有无边界、一种边界、两种边界三种情况。
Message-ID:(自动生成,由邮件服务器提供的该邮件的ID号。注意与常说的邮件的UID不是同一ID)
MIME-Version:(MIME的使用版本,现在通常为1.0)
(信头中以X开头的部分是邮件服务器自定义的信息段)
X-Originating-IP:(邮件发送者原始的IP地址)
X-Priority:(邮件的优先级)
X-Mailer:(邮件服务器信息)
X-Coremail-Antispam:(经过coremail邮件系统MTA投递时自动生成的反垃圾邮件信息)
------=_Part_367655_28062751.1223633652250 |
Content-Type: multipart/alternative; |----> 这一部分表明如果邮件是
| 多重部分的,定义两个边
界,一个区分文本,一个区
分附件
boundary="----=_Part_367657_22083146.1223633652250" |
------=_Part_367657_22083146.1223633652250 |
Content-Type: text/plain; charset=gbk |
Content-Transfer-Encoding: 7bit |----> 这一部分是正文的内容,
| 它表明正文是text/plain类
|型,gbk字符集,用7bit编码方式
Hi Tommy,
This is a mail for testing.
------=_Part_367657_22083146.1223633652250
Content-Type: text/html; charset=gbk
Content-Transfer-Encoding: 7bit
|------>这一部分表明是html内
|容,类型为text/html,gbk字符
|集,7bit编码
<div>Hi Tommy,<br><br> This is a mail for testing.<br></div><div> </div> |
------=_Part_367657_22083146.1223633652250-- |--->文本内容结束
------=_Part_367655_28062751.1223633652250 |------>这里的边界和上面文本内
|容的边界是不一样的,注意区分
|第一次以“--”开头出现这个边界表
|示附件
Content-Type: image/jpeg; name="plenware.jpg" | 内容从此开始
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="plenware.jpg" |
|-------->这一部分表明是附件
|从Content-Disposition:
|attahment 看出 附件名称是
|plenware.jpg, 采用64位编码,
|正文是一段编码后的内容
/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAkGBwgHBgkIBwgKCgkLDRYPDQwMDRsUFRAWIB0iIiAd
Hx8kKDQsJCYxJx8fLT0tMTU3Ojo6Iys/RD84QzQ5Ojf/2wBDAQoKCg0MDRoPDxo3JR8lNzc3Nzc3
Nzc3Nzc3Nzc3N......==
------=_Part_367655_28062751.1223633652250-- |------->以“--”结束,表示附件部
|分结束,整个源码也结束于此
从源码开头到X-Coremail-Antispam段结束为头部信息,其余以--开始 所囊括的部分都是主体信息。
大家可以从源码看到头部信息中大部分的信息。body部分由于是进行了编码,所以直接阅读通常是不行的。
更多的关于mail的信息可参看 http://en.wikipedia.org/wiki/Email
2.POP3协议
=====================================
POP3,全名为“Post Office Protocol - Version 3”,即“邮局协议版本3”。是TCP/IP协议族中的一员,由RFC 1939 定义(见 Reference/rfc1939 pop3.html)。本协议主要用于支持使用客户端远程管理在服务器上的电子邮件。提供了SSL加密的POP3协议被称为POP3S。
(1)使用telnet 连接pop3
最直观的了解什么是POP3,我觉得采用telnet的方式用pop3连接到邮件服务器,进行邮件的接收是最有效的。
打开终端,(C:client, S:Server)
*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
C: telnet pop.163.com 110 (用telnet方式连接163的pop3服务器,pop3协定端口为110)
S: Trying 202.108.5.100...
Connected to pop3.163.split.netease.com.
Escape character is '^]'.
+OK Welcome to coremail Mail Pop3 Server (163coms[3d8c1fa079729fb6acc588e66d30360es]) (服务器通常开头返回+OK表示正确的回应,+ERR表示所发命令有误)
C: USER ***** (***处输入你的邮件用户名)
S: +OK core mail (表示接受)
C: PASS ***** (***处输入密码,这里都是明文显示)
S: +OK 5 message(s) [9782 byte(s)] (这里表示服务器接受该帐户,服务器上对应有5封邮件,总大小9782个字节)
C:LIST (LIST 命令列出每一封邮件的信息,己每封邮件对应的ID号和大小)
S: +OK 5 9782
1 1298
2 1311
3 1224
4 1312
5 4637
.
C: TOP 1 0 (格式 TOP num 0, num代表邮件ID号,返回该邮件的头部信息)
S:+OK 1298 octets (服务器接受)
Received: from smtp.163.com (unknown [221.10.25.6]) (返回的相关内容)
by smtp1 (Coremail) with SMTP id C9GowLCLsyoRy_JI5Ci2Mg==.42306S2;
Mon, 13 Oct 2008 12:14:10 +0800 (CST)
Date: Mon, 13 Oct 08 12:14:09 +0800 (CST)
From: [email protected]
To: tommy_mail<[email protected]>
Subject: @@!$$%^&
MIME-Version: 1.0
Content-Type: multipart/alternative; boundary="=-plenware_alt_"
X-Coremail-Antispam: 1Uf129KBjDUn29KB7ZKAUJUUUUUYxn0WfASr-VFAUDa7-sFnT
9fnUUIcSsGvfJTRUUUjlxYjsxI4VWxJwAYFVCjjxCrM7AC8VAFwI0_Jr0_Gr1l1I0E4x80
FVCIwcAKzIAtM7C26IkvcIIF6IxKo4kEV4yl1IIY67AEw4v_Jr0_Jr4l5I8CrVACY4xI64
kE6c02F40Ex7xfMcIj6xIIjxv20xvE14v26r1Y6r17McIj6I8E87Iv67AKxVW8JVWxJwAC
Y4xI67k04243AVAKzVAKj4xxM4xvF2IEb7IF0Fy26I8I3I1lFVAaXTZC67ZELSn0mTvEwa
V2v3VFvVW8M4IE42xK82IY64kIx2x0424lw4CEF2IF47xS0VAv8wAKzVCY07xG64k0F24l
7I0Y64k_MxkFs20EY4vE77kJMxkIecxEwVAFwVW8XwCY0x0Ix7I2Y4AK64vIr41l4x8a6c
8ajcxJMI8E67AF67kF1VAFwI0_Jr0_JrylIxAIcVC0I7IYx2IY67AKxVWUJVWUCwCI42IY
6xIIjxv20xvEc7CjxVAFwI0_Jr0_Gr1lIxAIcVC2z280aVAFwI0_Gr0_Cr1lIxAIcVC2z2
80aVCY1x0267AKxVW8JVW8Jr1l6VACY4xI67k04243AbIYCTnIWIevJa73UjIFyTuYvjxU
yYZXDUUUU
Message-Id: <[email protected]>
.
C: RETR 2 (格式 RETR num, num为邮件ID号,返回邮件全部源码)
S: +OK 1311 octets
Received: from smtp.163.com (unknown [221.10.25.6])
by smtp4 (Coremail) with SMTP id DtGowLCrK4xUyvJIJeKfLg==.58545S2;
Mon, 13 Oct 2008 12:11:00 +0800 (CST)
.
.
.
.
.
.
--=-plenware_alt_--
.
C: NOOP (空操作,起延时作用,服务器会在一定时间内无操作的话自动退出)
S: +OK core mail
C: UIDL (邮件的唯一ID,通常称“独立-ID表”,用于唯一确定一封邮件,通常用于客户端判别已读未读)
S: +OK 5 9782
1 1tbiYAaMeEJw1XtwEgAAss (由服务器产生的邮件唯一ID,RFC文档上说是服务器内唯一,但估计说成全球唯一也不为过)
2 1tbiYAeMeEJw1XtoyQAAsu
3 1tbiYRaMeEJw2LVItgAAsi
4 1tbiwQqMeEij15ERZQAAsm
5 1tbiwReMeEij15EzUgAAsu
.
C: QUIT (退出命令)
S: +OK core mail
Connection closed by foreign host.
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*
更加详细的关于telnet的描述可参看 Reference/telnet 操作 smtp pop.html
(2)POP3协议的状态和相关命令
POP3有三种状态:
a) The AUTHORIZATION State
当一个TCP连接从客户端连接到服务器以后,就进入了这个状态。通过常服务器会返回以下类似的信息:
S: +OK POP3 server ready
退出这个状态使用命令
[QUIT] Command .....................退出与POP3服务器的连接
b) The TRANSACTION State
当用户成功连接并登录到邮件服务器后,就进入了TRANSACTION状态。这个状态下可以使用的命令有:
[STAT] Command .....................查看当前服务器邮件的总数和总大小
[LIST] Command .....................列出每封邮件对应的ID号和单个邮件大小
[RETR num] Command .....................返回对应ID邮件的全部内容
[DELE num] Command .....................删除对应ID邮件
[NOOP] Command .....................延迟命令,执行空操作,以延迟系统退出时间
[RSET] Command .....................当执行完删除命令后,要执行RESET命令才能在当前立即返回删除的效果
c) The UPDATE State
如果在TRANSACTION状态下发出QUIT命令,在退出POP3连接后会自动发出UPDATE状态。(如果在AUTHORIZATION状态下发出QUIT命令,则不会有UPDATE状态,这涉及到DELETE命令的效果)
其他的 Optional POP3 Commands
[TOP num] Command .....................列出对应ID邮件的邮件头信息
[UIDL num or UIDL] Command .....................列出全部或对应ID邮件的UIDL
[USER name] Command .....................输入用户名
[PASS password] Command .....................输入密码
[APOP name digest] Command .....................用于防护USER/PASS存在泄密的可能性。name digest指定邮箱的字串和MD5算法生成的密码串。
(3) POP3协议的解析
对于自己开发pop3客户端程序,如何解析pop3所收到的源码信息是工作量很大而且极为关键的部分。
本人认为,解析pop3协议需要注意以下问题:
a)如何收取定位关键字段,并读取相应信息。 如Subject,boundary字段的寻找,和相应内容的存放
b)理解源码的基本格式。邮件的基本格式由MIME协议规定,可参看http://zh.wikipedia.org/wiki/MIME,或者Referrence/RFC2045.html。
c)如何设计数据结构存放相应信息。本人推荐将文本信息和附件信息统一成一种数据结构,按照类型来进行区分。
d)学习字符集和网络编码方式,邮件中相当多地方设计到
e)CRLF的理解。通常CRLF代表/r/n,在编程时每一个命令也是由此结束,但windows平台和linux平台中对CRLFx的定义不一样。
g)附件的接收和保存。特别是识别多附件时。
h)扩展性:为以后增加字符集和编码方式,以及html文档的支持等提供接口。
i)适应不同邮件服务器略有差别的邮件源码格式。相信这一点在解析时会让你爆血滴。关键还是在一个标准问题,可惜的是并没有一个标准规定了每一个字段的细到空格分号等的格式。
3.SMTP协议
=====================================
简单邮件传输协议 (Simple Mail Transfer Protocol, SMTP) 是事实上的在Internet传输email的标准。SMTP是一个相对简单的基于文本的协议。在其之上指定了一条消息的一个或多个接收者(在大多数情况下被确认是存在的),然后消息文本会被传输。
(1)用telnet 连接SMTP服务器
最直观的方式是用telnet连接到SMTP的服务器,看如何利用命令操作SMTP。
打开终端:(C:client, S:Server)
*-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
C: telnet smtp.163.com 25 (连接到163的SMTP服务器,协议规定SMTP服务器的端口号为25)
S: Trying 202.108.5.83...
Connected to smtp.163.split.netease.com.
Escape character is '^]'.
220 163.com Anti-spam GT for Coremail System (163com[071018]) (220 表示连接成功)
C: HELO smtp.163.com (协议规定的握手过程,格式为HELO + 服务器名称)
S: 250 OK (250 表示握手成功)
C: AUTH LOGIN (AUTH LOGIN 是用户登录命令)
S: 334 dXNlcm5hbWU6 (334表示服务器接受)
C: tommy_mail (输入明文用户名)
S: 535 Error: authentication failed (服务器拒绝,因为SMTP要求用户名和密码都通过64位编码后再发送)
C: AUTH LOGIN (重新要求SMTP登录)
S: 334 dXNlcm5hbWU6
C: dG9tb*****FpbA== (用编码后的内容发送)
S: 334 UGFzc3dvcmQ6 (334表示接受)
C: ********aXZldXA= (编码后的密码)
S: 235 Authentication successful (235 登录成功)
C: MAIL FROM:<[email protected]> (MAIL FROM:<>格式,用来记录发送者,这里要求必须是完全正确的发送者邮箱,不可作假,否则通过不了)
S: 250 Mail OK (250 系统常用确认信息)
C: RCPT TO:<[email protected]> (接收者邮箱,可多次使用以实现发送给多个人)
S: 250 Mail OK
C: DATA (DATA明令表示以下为邮件正文)
S: 354 End data with <CR><LF>.<CR><LF>
C: TO:11@11 (发送给谁,这里可自由撰写,也是伪造邮件的一个入口,欺骗一般人可以,但会读源码的人欺骗不了)
FROM:22@22 (发送者是谁,可串改)
SUBJECT:TEST MAIL SMTP (邮件主题)
helloworld (空一行写邮件正文)
. (正文以.结束)
S: 250 Mail OK queued as smtp3,DdGowLBLAjqD6_JIg1hfBA==.63235S2 1223879684 (服务器接受)
C: noop (空操作,延迟退出时间)
S: 250 OK
C: quit (退出SMTP服务器连接)
S: 221 Bye
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*
更加详细的关于telnet的描述可参看 Reference/telnet 操作 smtp pop.html
(2)SMTP基本发送流程和相关命令
相对于POP3,SMTP的流程和命令更加固定。
与SMTP服务器建立TCP连接....................................服务器地址通常为 smtp.**.com/net 端口25 (记住所有命令以一个CRLF结束)
于服务器握手................................................HELO + 服务器地址名称 + CRLF
AUTH LOGIN........................................请求登录
用户名.....................................................base64编码的用户名
密码.......................................................base64编码的密码
MAIL FROM:<>......................................输入帐户的正确的邮件地址,这里于这帐户信息不一致会导致服务器拒绝
RCPT TO:<>........................................接收者,多个接收者多次调用该命令
DATA..............................................即将输入邮件正文
依次输入TO: ; FROM: ;SUBJECT: ;空一行 正文; 隔行以.结束
QUIT..............................................退出连接状态
(3)SMTP客户端的编写
在写SMTP服务端的程序时,完成一个简单的成功发送程序并不困难。按照固定的流程可以很快开发出一个SMTP的客户端程序。但编写一个完全符合标准的邮件也不是那么容易的
我认为难点有以下一些:
a)发送的头部是否支持全部的邮件格式要求的字段。通常不包含送有的字段也能成功,但毕竟不规范。
b)boundary的确定。不同服务器会用某种方式自动生成boundary,我们在开发之初可以只固定两类边界,所有邮件都使用,但以后肯定需要改进,他的算法是什么,现在未知。
c)确定SMTP客户端在发送邮件时不同部分采用什么样的编码,编码方式需要自己完成和确定,那么确定编码方式的标准是什么,现在未知。
d)如何确定发送邮件的数据结构。
4.结束语
=====================================
我接触POP3和SMTP的时间并不长,了解的知识也仅局限在基础只上。希望我对这两个协议的理解有助于大家对email的学习和以后的程序开发。事实上,现在IMAP协议的采用是一个趋势,他比起POP3协议有更好的功能和更加简洁的命令。但是现在
支持IMAP协议并且免费的邮件服务商并不多,而GMAIL可以是一个很好的研究对象。但是连接到GMAIL需要SSL加密协议,开发有一定难度。
以上言论有纰漏之处,希望指出。任何COPY和转载请保留作者原始信息,尊重智力劳动和书写疲累。谢谢。
附件一: 邮件源码(摘自网易163.com)
*------------------------------------------------------------------------------------------------------------------
Received: from m15-66.126.com (unknown [220.181.15.66])
by mx27 (Coremail) with SMTP id TcCowLD7EwbzKu9IHYvkEA==.4008S2;
Fri, 10 Oct 2008 18:14:11 +0800 (CST)
Received: from 221.10.25.6 ( 221.10.25.6 [221.10.25.6] ) by
ajax-webmail-wmsvr66 (Coremail) ; Fri, 10 Oct 2008 18:14:12 +0800 (CST)
Date: Fri, 10 Oct 2008 18:14:12 +0800 (CST)
From: zengbenyuan <[email protected]>
To: "[email protected]" <[email protected]>
Message-ID: <[email protected]>
Subject: Helloworld
MIME-Version: 1.0
Content-Type: multipart/mixed;
boundary="----=_Part_367655_28062751.1223633652250"
X-Originating-IP: [221.10.25.6]
X-Priority: 3
X-Mailer: Coremail Webmail Server Version XT_Ux_snapshot build
080919(6068.1917.1874) Copyright (c) 2002-2008 www.mailtech.cn 126com
X-Coremail-Antispam: 1Uf129KBjDUn29KB7ZKAUJUUUUUYxn0WfASr-VFAUDa7-sFnT
9fnUUIcSsGvfJTRUUUjckFxVCF77xC6IxKo4kEV4yl1I0EscIYIxCEI4klw4CSwwAawVAC
jsI_Ar4v6c8GOVW06r1DJrWUAwASzI0EjI02j7AqF2xKxwAqx4xG64xvF2IEw4CE5I8CrV
C2j2Wl5I8CrVCF54CYxVAG04kSxc1lYx0E74AGY7Cv6cx26rWlYx0Ec7CjxVAajcxG14v2
6r4j6F4UM4x0x7Aq67IIx4CEVc8vx2IErcIFxwACY4xI67k04243AVC20s07M4IEnf9ElV
AFpTB2q-sK649IAas0WaI_GwAC6xAIw28IcVAK0I8IjxAxMx02cVCv0xWlc2xSY4AK67AK
6r4DMxkI7II2jI8vz4v_Kr0_Gr1UMxCjnVCjjxCrMI8E67x28xkI4xCE0xIEc2x0rwC2zV
AF1VAY17CE14v26r1j6r15MVCEFcxC0VAYjxAxZFUvcSsGvfC2KfnxnUUI43ZEXa7VUeHl
k3UUUUU==
------=_Part_367655_28062751.1223633652250
Content-Type: multipart/alternative;
boundary="----=_Part_367657_22083146.1223633652250"
------=_Part_367657_22083146.1223633652250
Content-Type: text/plain; charset=gbk
Content-Transfer-Encoding: 7bit
Hi Tommy,
This is a mail for testing.
------=_Part_367657_22083146.1223633652250
Content-Type: text/html; charset=gbk
Content-Transfer-Encoding: 7bit
<div>Hi Tommy,<br><br> This is a mail for testing.<br></div><div> </div>
------=_Part_367657_22083146.1223633652250--
------=_Part_367655_28062751.1223633652250
Content-Type: text/plain; name="Debian Package.txt"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="Debian Package.txt"
RGViaWFuIFBhY2thZ2U=
------=_Part_367655_28062751.1223633652250--