# 電子郵件
Email的歷史比Web還要久遠,直到現在,Email也是互聯網上應用非常廣泛的服務。
幾乎所有的編程語言都支持發送和接收電子郵件,但是,先等等,在我們開始編寫代碼之前,有必要搞清楚電子郵件是如何在互聯網上運作的。
我們來看看傳統郵件是如何運作的。假設你現在在北京,要給一個香港的朋友發一封信,怎么做呢?
首先你得寫好信,裝進信封,寫上地址,貼上郵票,然后就近找個郵局,把信仍進去。
信件會從就近的小郵局轉運到大郵局,再從大郵局往別的城市發,比如先發到天津,再走海運到達香港,也可能走京九線到香港,但是你不用關心具體路線,你只需要知道一件事,就是信件走得很慢,至少要幾天時間。
信件到達香港的某個郵局,也不會直接送到朋友的家里,因為郵局的叔叔是很聰明的,他怕你的朋友不在家,一趟一趟地白跑,所以,信件會投遞到你的朋友的郵箱里,郵箱可能在公寓的一層,或者家門口,直到你的朋友回家的時候檢查郵箱,發現信件后,就可以取到郵件了。
電子郵件的流程基本上也是按上面的方式運作的,只不過速度不是按天算,而是按秒算。
現在我們回到電子郵件,假設我們自己的電子郵件地址是`me@163.com`,對方的電子郵件地址是`friend@sina.com`(注意地址都是虛構的哈),現在我們用`Outlook`或者`Foxmail`之類的軟件寫好郵件,填上對方的Email地址,點“發送”,電子郵件就發出去了。這些電子郵件軟件被稱為**MUA**:Mail User Agent——郵件用戶代理。
Email從MUA發出去,不是直接到達對方電腦,而是發到**MTA**:Mail Transfer Agent——郵件傳輸代理,就是那些Email服務提供商,比如網易、新浪等等。由于我們自己的電子郵件是`163.com`,所以,Email首先被投遞到網易提供的MTA,再由網易的MTA發到對方服務商,也就是新浪的MTA。這個過程中間可能還會經過別的MTA,但是我們不關心具體路線,我們只關心速度。
Email到達新浪的MTA后,由于對方使用的是`@sina.com`的郵箱,因此,新浪的MTA會把Email投遞到郵件的最終目的地**MDA**:Mail Delivery Agent——郵件投遞代理。Email到達MDA后,就靜靜地躺在新浪的某個服務器上,存放在某個文件或特殊的數據庫里,我們將這個長期保存郵件的地方稱之為電子郵箱。
同普通郵件類似,Email不會直接到達對方的電腦,因為對方電腦不一定開機,開機也不一定聯網。對方要取到郵件,必須通過MUA從MDA上把郵件取到自己的電腦上。
所以,一封電子郵件的旅程就是:
```
發件人 -> MUA -> MTA -> MTA -> 若干個MTA -> MDA <- MUA <- 收件人
```
有了上述基本概念,要編寫程序來發送和接收郵件,本質上就是:
1. 編寫MUA把郵件發到MTA;
2. 編寫MUA從MDA上收郵件。
發郵件時,MUA和MTA使用的協議就是SMTP:Simple Mail Transfer Protocol,后面的MTA到另一個MTA也是用SMTP協議。
收郵件時,MUA和MDA使用的協議有兩種:POP:Post Office Protocol,目前版本是3,俗稱POP3;IMAP:Internet Message Access Protocol,目前版本是4,優點是不但能取郵件,還可以直接操作MDA上存儲的郵件,比如從收件箱移到垃圾箱,等等。
郵件客戶端軟件在發郵件時,會讓你先配置SMTP服務器,也就是你要發到哪個MTA上。假設你正在使用163的郵箱,你就不能直接發到新浪的MTA上,因為它只服務新浪的用戶,所以,你得填163提供的SMTP服務器地址:`smtp.163.com`,為了證明你是163的用戶,SMTP服務器還要求你填寫郵箱地址和郵箱口令,這樣,MUA才能正常地把Email通過SMTP協議發送到MTA。
類似的,從MDA收郵件時,MDA服務器也要求驗證你的郵箱口令,確保不會有人冒充你收取你的郵件,所以,Outlook之類的郵件客戶端會要求你填寫POP3或IMAP服務器地址、郵箱地址和口令,這樣,MUA才能順利地通過POP或IMAP協議從MDA取到郵件。
在使用Python收發郵件前,請先準備好至少兩個電子郵件,如`xxx@163.com`,`xxx@sina.com`,`xxx@qq.com`等,注意兩個郵箱不要用同一家郵件服務商。
- JavaScript教程
- JavaScript簡介
- 快速入門
- 基本語法
- 數據類型和變量
- 字符串
- 數組
- 對象
- 條件判斷
- 循環
- Map和Set
- iterable
- 函數
- 函數定義和調用
- 變量作用域
- 方法
- 高階函數
- map/reduce
- filter
- sort
- 閉包
- 箭頭函數
- generator
- 標準對象
- Date
- RegExp
- JSON
- 面向對象編程
- 創建對象
- 原型繼承
- 瀏覽器
- 瀏覽器對象
- 操作DOM
- 更新DOM
- 插入DOM
- 刪除DOM
- 操作表單
- 操作文件
- AJAX
- Promise
- Canvas
- jQuery
- 選擇器
- 層級選擇器
- 查找和過濾
- 操作DOM
- 修改DOM結構
- 事件
- 動畫
- 擴展
- underscore
- Collections
- Arrays
- Functions
- Objects
- Chaining
- Node.js
- 安裝Node.js和npm
- 第一個Node程序
- 模塊
- 基本模塊
- fs
- stream
- http
- buffer
- Web開發
- koa
- mysql
- swig
- 自動化工具
- 期末總結
- Python 2.7教程
- Python簡介
- 安裝Python
- Python解釋器
- 第一個Python程序
- 使用文本編輯器
- 輸入和輸出
- Python基礎
- 數據類型和變量
- 字符串和編碼
- 使用list和tuple
- 條件判斷和循環
- 使用dict和set
- 函數
- 調用函數
- 定義函數
- 函數的參數
- 遞歸函數
- 高級特性
- 切片
- 迭代
- 列表生成式
- 生成器
- 函數式編程
- 高階函數
- map/reduce
- filter
- sorted
- 返回函數
- 匿名函數
- 裝飾器
- 偏函數
- 模塊
- 使用模塊
- 安裝第三方模塊
- 使用__future__
- 面向對象編程
- 類和實例
- 訪問限制
- 繼承和多態
- 獲取對象信息
- 面向對象高級編程
- 使用__slots__
- 使用@property
- 多重繼承
- 定制類
- 使用元類
- 錯誤、調試和測試
- 錯誤處理
- 調試
- 單元測試
- 文檔測試
- IO編程
- 文件讀寫
- 操作文件和目錄
- 序列化
- 進程和線程
- 多進程
- 多線程
- ThreadLocal
- 進程 vs. 線程
- 分布式進程
- 正則表達式
- 常用內建模塊
- collections
- base64
- struct
- hashlib
- itertools
- XML
- HTMLParser
- 常用第三方模塊
- PIL
- 圖形界面
- 網絡編程
- TCP/IP簡介
- TCP編程
- UDP編程
- 電子郵件
- SMTP發送郵件
- POP3收取郵件
- 訪問數據庫
- 使用SQLite
- 使用MySQL
- 使用SQLAlchemy
- Web開發
- HTTP協議簡介
- HTML簡介
- WSGI接口
- 使用Web框架
- 使用模板
- 協程
- gevent
- 實戰
- Day 1 - 搭建開發環境
- Day 2 - 編寫數據庫模塊
- Day 3 - 編寫ORM
- Day 4 - 編寫Model
- Day 5 - 編寫Web框架
- Day 6 - 添加配置文件
- Day 7 - 編寫MVC
- Day 8 - 構建前端
- Day 9 - 編寫API
- Day 10 - 用戶注冊和登錄
- Day 11 - 編寫日志創建頁
- Day 12 - 編寫日志列表頁
- Day 13 - 提升開發效率
- Day 14 - 完成Web App
- Day 15 - 部署Web App
- Day 16 - 編寫移動App
- 期末總結
- Python3教程
- Python簡介
- 安裝Python
- Python解釋器
- 第一個Python程序
- 使用文本編輯器
- Python代碼運行助手
- 輸入和輸出
- Python基礎
- 數據類型和變量
- 字符串和編碼
- 使用list和tuple
- 條件判斷
- 循環
- 使用dict和set
- 函數
- 調用函數
- 定義函數
- 函數的參數
- 遞歸函數
- 高級特性
- 切片
- 迭代
- 列表生成式
- 生成器
- 迭代器
- 函數式編程
- 高階函數
- map/reduce
- filter
- sorted
- 返回函數
- 匿名函數
- 裝飾器
- 偏函數
- 模塊
- 使用模塊
- 安裝第三方模塊
- 面向對象編程
- 類和實例
- 訪問限制
- 繼承和多態
- 獲取對象信息
- 實例屬性和類屬性
- 面向對象高級編程
- 使用__slots__
- 使用@property
- 多重繼承
- 定制類
- 使用枚舉類
- 使用元類
- 錯誤、調試和測試
- 錯誤處理
- 調試
- 單元測試
- 文檔測試
- IO編程
- 文件讀寫
- StringIO和BytesIO
- 操作文件和目錄
- 序列化
- 進程和線程
- 多進程
- 多線程
- ThreadLocal
- 進程 vs. 線程
- 分布式進程
- 正則表達式
- 常用內建模塊
- datetime
- collections
- base64
- struct
- hashlib
- itertools
- XML
- HTMLParser
- urllib
- 常用第三方模塊
- PIL
- virtualenv
- 圖形界面
- 網絡編程
- TCP/IP簡介
- TCP編程
- UDP編程
- 電子郵件
- SMTP發送郵件
- POP3收取郵件
- 訪問數據庫
- 使用SQLite
- 使用MySQL
- 使用SQLAlchemy
- Web開發
- HTTP協議簡介
- HTML簡介
- WSGI接口
- 使用Web框架
- 使用模板
- 異步IO
- 協程
- asyncio
- async/await
- aiohttp
- 實戰
- Day 1 - 搭建開發環境
- Day 2 - 編寫Web App骨架
- Day 3 - 編寫ORM
- Day 4 - 編寫Model
- Day 5 - 編寫Web框架
- Day 6 - 編寫配置文件
- Day 7 - 編寫MVC
- Day 8 - 構建前端
- Day 9 - 編寫API
- Day 10 - 用戶注冊和登錄
- Day 11 - 編寫日志創建頁
- Day 12 - 編寫日志列表頁
- Day 13 - 提升開發效率
- Day 14 - 完成Web App
- Day 15 - 部署Web App
- Day 16 - 編寫移動App
- FAQ
- 期末總結
- Git教程
- Git簡介
- Git的誕生
- 集中式vs分布式
- 安裝Git
- 創建版本庫
- 時光機穿梭
- 版本回退
- 工作區和暫存區
- 管理修改
- 撤銷修改
- 刪除文件
- 遠程倉庫
- 添加遠程庫
- 從遠程庫克隆
- 分支管理
- 創建與合并分支
- 解決沖突
- 分支管理策略
- Bug分支
- Feature分支
- 多人協作
- 標簽管理
- 創建標簽
- 操作標簽
- 使用GitHub
- 自定義Git
- 忽略特殊文件
- 配置別名
- 搭建Git服務器
- 期末總結