## 电子邮件系统
电子邮件系统应该如何设计?
可以在电脑上写一个程序,存储每个人的邮件,然后把服务器当做邮局
但是如果通过服务器进行中转的话,服务器怎么才能发到个人邮箱呢?
如果让服务器主动去连个人电脑,问题是个人电脑可能处于关机状态,而且IP地址会改变。所以服务器不能主动去连接。
也就是说可以在服务器上为每个人开辟一块空间,空间课程叫“用户名@服务器名
那么还需要开发一个客户端邮箱quickMail,可以向服务器上的邮箱发信,也可以从服务器上收信。
另外同样还需要服务器端的程序,用来接收邮件,存储起来,就叫QuickMailServer
电子邮件的格式为:发件人、收件人、抄送、密送、标题、正文
## 协议
那么client如何与服务器进行通信了?
最简单的协议是:
![](http://p8a6vmhkm.bkt.clouddn.com/img/20181029113850.png?imageslim)
这个协议考虑到了端口问题,而且还考虑到了DATA中以什么作为发送数据的结尾。
不过有个小问题,数据在网络上传输,中文是不行的,需要进行编码,把他们变成ASCII码
比如Base64,可以把二进制的数据变成小写字母a-z,A-Z,数字0-9,符号+、/、=等字符组成的数据。这只是一种编码方式,而不是加密
比如“为了庆祝产品发布, 今晚在海底捞聚餐” 经过 base 64 编码就会变成这个样子:
5Li65LqG5bqG56Wd5Lqn5ZOB5Y+R5biD77yMIOS7iuaZmuWcqOa1t+W6leaNnuiBmumkkA==
这完全是 ASCII 码了。
可以定义收信的协议如下
![](http://p8a6vmhkm.bkt.clouddn.com/img/20181029114547.png?imageslim)
这个协议考虑到了用户登录的问题,因为自己的邮箱应该是私密的。
我们可以为协议起一个名字:
- 发信:Simple Mail Transfer Protocol , SMTP
- 收信:Post Office Protocol ,POP协议
## 让邮件支持附件
怎么给邮件加上附件呢?邮件的正文是文本格式的,但是word是二进制的。完全不同。
我们做计算机的,遇到问题的方法通常有两个:
- 增加一个抽象层
- 分而治之
所以我们可以把原始问题划分成两个子问题:
- 如何让正文和邮件区分开来。
- 如何把二进制数据加入邮件中
那么如何把正文和邮件区分开呢?
可以定义一个邮件内容类型`Content-type=plain-text`,那么这个邮件就是纯文本的,如果是`Content-type=mixed`,那么就代表文本+附件
这样的话,主要问题在于扩展性不好。
可以分为主类型和子类型,
其中主类性和子类型都可以扩展。
现阶段,如果主类型是Text,那么子类型可以是plain,代表纯文本也可以是别的东西。
如果主类型是Multipart,代表文件有多个部分,那么子类型可以是mixed
比如
- Content-type=text/plain,这是纯文本的邮件
- Content-type=multipart/mixed,这是一个由正文和附件混合组成的邮件。
> text除了plain还支持HTML,Multiaprt还支持alternative,related
那么客户端如何告诉服务器文件与附件的分隔呢?
可以让客户端加一个分隔符的属性:
```
Content-type=multipart/mixed;
boundary="----=_NextPart_AEDGREGREWGREWGFDSFGSGFDSFTTRFSGGFD_001_0051_01A";
```
比如下面就是一封带附件的邮件:
```
// 定义这是一个混合的邮件, 每个部分的分隔符由 boundary 定义。 为了便于阅读, 我把这个 boundary 故意写的很简单, 实际复杂的多
Content-type=multipart/mixed;
boundary="--A001_0051_01A";
// 以分隔符来开始邮件正文
----A001_0051_01A
// 这是 “为了庆祝产品发布, 今晚在海底捞聚餐” 的 base64 编码的结果
5Li65LqG5bqG56Wd5Lqn5ZOB5Y+R5biD77yMIOS7iuaZmuWcqOa1t+W6leaNnuiBmumkkA==
----A001_0051_01A
Content-type:audio/wav
name:"fly.wav"
<这里是附件 1 的数据>
----A001_0051_01A
Content-type: image/jpg
name:"sky.jpg"
<这里是附件 2 的数据>
// 整个邮件结束的标记
----A001_0051_01A
```
那附件的编码怎么办?
这些附件无非就是二进制的数据, 完全可以像处理汉字那样用 base64 来编码啊! 扩展性, 我们可以给每一个部分加一个编码类型的属性? 例如:
```
Content-type: image/jpg
name:"sky.jpg"
encoding: base64
```
## 多个邮件服务器
现在邮箱的基本功能有了,但是Email只能在公司内部留转,如何在两个公司之间发邮件呢?
假设, 有两个公司, 他们的邮件服务器分别是 mailA.com 和 mailB.com , 当 userA@mailA.com 给 userB@mailB.com 发信的时候, 我们可以这么处理:
1. 用户 userA 通过 SMTP 把邮件发给 mailA.com 这个邮件服务器
2. mailA.com 发现目标用户 userB@mailB.com 并不在 自己的服务器上, 它就把信件暂时放到队列里。
3. mailA.com 从**队列**中取出邮件, 然后尝试向 mailB.com 投递 ,也是通过 SMTP, 如果发送失败, 就给 userA 发一个投递失败的消息。
4. mailB.com 接收到以后, 存到 userB 的邮箱里, userB 就可以通过 POP3 协议进行收取了
这里唯一做的变化就是让邮件服务器可以暂存邮件, 转发邮件。