## 電子郵件系統
電子郵件系統應該如何設計?
可以在電腦上寫一個程序,存儲每個人的郵件,然后把服務器當做郵局
但是如果通過服務器進行中轉的話,服務器怎么才能發到個人郵箱呢?
如果讓服務器主動去連個人電腦,問題是個人電腦可能處于關機狀態,而且IP地址會改變。所以服務器不能主動去連接。
也就是說可以在服務器上為每個人開辟一塊空間,空間課程叫“用戶名@服務器名
那么還需要開發一個客戶端郵箱quickMail,可以向服務器上的郵箱發信,也可以從服務器上收信。
另外同樣還需要服務器端的程序,用來接收郵件,存儲起來,就叫QuickMailServer
電子郵件的格式為:發件人、收件人、抄送、密送、標題、正文
## 協議
那么client如何與服務器進行通信了?
最簡單的協議是:

這個協議考慮到了端口問題,而且還考慮到了DATA中以什么作為發送數據的結尾。
不過有個小問題,數據在網絡上傳輸,中文是不行的,需要進行編碼,把他們變成ASCII碼
比如Base64,可以把二進制的數據變成小寫字母a-z,A-Z,數字0-9,符號+、/、=等字符組成的數據。這只是一種編碼方式,而不是加密
比如“為了慶祝產品發布, 今晚在海底撈聚餐” 經過 base 64 編碼就會變成這個樣子:
5Li65LqG5bqG56Wd5Lqn5ZOB5Y+R5biD77yMIOS7iuaZmuWcqOa1t+W6leaNnuiBmumkkA==
這完全是 ASCII 碼了。
可以定義收信的協議如下

這個協議考慮到了用戶登錄的問題,因為自己的郵箱應該是私密的。
我們可以為協議起一個名字:
- 發信: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 協議進行收取了
這里唯一做的變化就是讓郵件服務器可以暫存郵件, 轉發郵件。