JOVANA
Explore Library Glossary Getting Started Three Levels Fields How it works Mission
Join the mission
All guides

電子郵件與檔案傳輸:SMTP、IMAP 與 FTP

電子郵件比全球資訊網還老,建立在一個迷人而不同的想法上:用推送而非拉取,用一連串郵局而非單一大商店。本篇打開郵件系統與最初的檔案傳輸協定,並說明為何它們的設計選擇至今仍有迴響。

一個不同於全球資訊網的形狀

前幾篇你一直住在 HTTP 裡,那裡的節奏始終如一:用戶端拉取。你的瀏覽器索取一個頁面,伺服器把它交回來;在你開口之前,什麼都不會抵達。比全球資訊網還老的電子郵件,卻建立在相反的直覺上。寄件者推送:你寫一封訊息,你的軟體就把它朝收件者推出去,遠端那一頭根本沒人開口要過它。把這兩種形狀並排來看——全球資訊網用拉取、郵件用推送——是理解「為何電子郵件長成這副模樣」最快的辦法。

但推送帶來一個全球資訊網從不必面對的問題。當你的瀏覽器抓取一個頁面時,伺服器此刻是醒著的、聆聽中、隨時可答。當你寄信時,收件者可能正在睡覺、離線,或在隧道裡用手機。你無法要求對方恰好在你按下傳送的那一刻在線上。於是郵件系統圍繞著「能存放訊息並等待的儲存區」來打造。這正是為何電子郵件不是一場對話,而是一段接力:你的訊息從你的機器跳到一台伺服器,也許再經過更多伺服器,最後停在一個信箱裡,直到收件者前來領取。整個安排裡那位無名英雄,就是耐心。

SMTP:推送郵件的接力

把一封訊息從寄件者送往收件者的協定,是 SMTP,簡單郵件傳輸協定。和 HTTP 一樣,它是一個你幾乎能徒手打字打出來的文字式協定:用戶端開啟一條 TCP 連線,與伺服器交換一串短而可讀的命令——HELO 用來自我介紹、MAIL FROM 用來指名寄件者、RCPT TO 用來指名每一位收件者、DATA 用來開始信件本體,而一個單獨佔一行的點號,用來標記結束。伺服器以一個數字回覆碼來回應每一個命令,正如 HTTP 伺服器以狀態碼回應。如果你讀過郵件標頭,你就見過 SMTP 的指紋。

但你的訊息一開始究竟如何找到收件者的伺服器?假設你寄給 [email protected]。你的寄件伺服器在 @ 符號處把位址切開:它後面的部分 example.com 是一個網域名稱,於是伺服器去問 網域名稱系統,問的不是一個網頁位址,而是一筆叫做 MX(郵件交換)的特殊記錄,這筆記錄指名了「替那個網域接收郵件的主機」。這正是你曾從根伺服器一路追到權威伺服器的同一本電話簿,只是問了一個不同的問題。拿到答案後,你的伺服器便對那台郵件主機開啟一條 SMTP 連線、開始對話。SMTP 骨子裡是郵件伺服器之間的接力,而不是讓你直接對著一個陌生人的收件匣說話。

  1. 你的郵件用戶端用 SMTP 把訊息交給你的外送郵件伺服器(這一段通常要驗證且加密,好讓只有你能以你的身分寄信)。
  2. 那台伺服器讀取 @ 之後的收件網域,向 DNS 詢問該網域的 MX 記錄,得知哪一台主機接收這個網域的郵件。
  3. 你的伺服器對那台主機開啟一條 SMTP 連線,並以 MAIL FROM、RCPT TO、DATA 把訊息接力過去。接收伺服器以一個 250 OK 的回覆收下它。
  4. 接收伺服器把訊息投進 Alice 的信箱,它就在那裡單純地等待。SMTP 的工作至此完成;它從不必把 Alice 叫醒。

MIME:教純文字攜帶任何東西

這個整潔的故事裡有一道皺褶。SMTP 生來是要攜帶純英文文字的——最簡單的、由可讀字元組成的串流。然而你的收件匣裡塞滿了照片、PDF、影片片段、帶重音的字母,還有中文字。一個為純 ASCII 文字打造的協定,如何攜帶一張二進位影像?答案是 MIME,多用途網際網路郵件擴充,它是一段美麗、向後相容的巧思。MIME 完全不更動 SMTP。它反而定義了一種方法,把豐富的內容描述並編碼進「SMTP 早已懂得如何接力的那同一個純文字本體」裡。

MIME 靠兩步運作。第一步,標頭描述「內容是什麼」:一個 Content-Type 標頭宣告 text/plain、image/jpeg、application/pdf 等等——和你在 HTTP 裡見過的同一套媒體型別詞彙,因為它們共用這個想法。第二步,當內容是二進位時,一種像 Base64 的編碼會把那些原始位元組改寫成普通的可列印字母,於是一張 JPEG 變成一大塊冗長、看起來無趣的文字,能毫髮無傷地通過任何純文字的通道;接收端再把它解碼回原始位元組。一封訊息甚至能同時容納好幾個部分——一個純文字版本、一個 HTML 版本,外加兩個附件——每一個都標上自己的型別。樸實的一條文字串流,就是這樣悄悄地攜帶起整個現代網際網路。

IMAP 與 POP3:伸手進你的信箱

SMTP 把訊息送進了 Alice 的信箱,但那個信箱住在她的郵件伺服器上,不在她的手機上。要真正讀到它,她需要第二個、分開的協定——一個拉取協定,讓她的用戶端伸手進那個遠端信箱、取出裡頭的東西。現代的選擇是 IMAP,網際網路訊息存取協定。較老的替代品是 POP3,郵局協定。它們以兩種非常不同的哲學解決同一個問題,而這份差異值得理解,因為它形塑了今天的電子郵件給人的感受。

POP3 的直覺是「下載後刪除」:它把訊息拉到一台裝置上,傳統上還從伺服器移除它們,把伺服器當成一個暫時的投遞箱。在你只用單一桌機讀信的年代,這樣沒問題。IMAP 的直覺正相反:伺服器才是那份主副本,而你的各個裝置只是望向它的、彼此同步的視窗。用 IMAP,你的資料夾、你的已讀/未讀標記、你的訊息都住在伺服器上,所以你的手機、筆電、平板看見的,是同一個信箱、同一種狀態。在手機上把某封標為已讀,片刻之後它在筆電上也顯示為已讀。這正是為何 IMAP 在多裝置的世界裡勝出:它把真相保存在一個共享的地方,由每一個用戶端去映照。

FTP:搬檔者與它古怪的雙通道

這一級最後一個經典協定是 FTP,檔案傳輸協定,它幾乎比這裡其他所有東西都更早出現。它的工作說起來很簡單:在用戶端與伺服器之間搬移檔案,並讓你遠端瀏覽、改名、刪除它們。FTP 值得研究的地方,在於一個不尋常的設計決定,它悄悄地教了一堂真實的課。SMTP 與 HTTP 把所有事都在單一連線上完成,FTP 卻把它的工作拆到兩條分開的 TCP 連線上:一條控制連線,整個工作階段都開著、攜帶你的命令(列出這個目錄、取得那個檔案),以及一條資料連線,每一次真正的檔案傳輸都新開一條。

何必搞兩條通道?把控制與資料分開,意味著命令與回覆能在控制線上持續流動,即使一個巨大的檔案正沿著資料線傾瀉而下——你能在傳輸途中中止它,因為控制連線從不會被檔案本身塞住。這是個乾淨的想法。但它有一個變得很出名的尷尬後果:在最初的「主動」模式裡,是伺服器朝用戶端反向開啟資料連線,而一旦防火牆與 網路位址轉換 變得普遍,一台試圖反向伸進家用網路的伺服器,通常就被擋下了。解法是「被動」模式,由用戶端朝外開啟兩條連線。這生動地教了一課:一個協定的設計,是死是活取決於它周遭的網路現實,而不只是它自身的優雅。

和 SMTP 與純 HTTP 一樣,經典 FTP 把一切——包括你的密碼與你的檔案——都以明文送出,完全不加密。正因如此,它大致已退役,讓位給加了安全防護的替代品:FTPS 把 FTP 包進 TLS 裡,而 SFTP(儘管名字相似)則是一種完全不同的檔案傳輸,騎在一段 SSH 工作階段裡。純 FTP 大多只殘存在老舊系統的角落。它如今對你真正的價值是觀念上的:它顯示,即使一個唯一工作就是搬檔的協定,也對連線、通道、信任做出了深刻的選擇——和這一級裡每一個協定都得做的,是同一類選擇。

貫穿每個應用層協定的那條線

退一步,看看這一整級向你展示了什麼。你遇見的每一個協定——HTTP、SMTP、IMAP、FTP——都只是一份約定,疊在應用層之上,講的是「兩個程式該透過一個通訊端送出哪些位元組、以什麼順序送」。一旦你把它們看成對話而非魔法,它們的家族相似性便躍然而出:多半是帶著命令與數字回覆碼的可讀文字;多半開啟一條 TCP 連線,因為它們需要每個位元組都抵達;而每一個都對狀態、通道、編碼,以及它如何找到自己的對等端,做了刻意的選擇。

而那些選擇並非任意的瑣事——它們正是這門手藝的核心。拉取還是推送?HTTP 拉、SMTP 推。無狀態還是有狀態?HTTP 遺忘、IMAP 記得。一條連線還是兩條?FTP 出了名地把它們拆開。純文字還是二進位,又該如何在一個文字通道上攜帶豐富內容?MIME 替郵件回答了這題,而 HTTP 沿用了同一套媒體型別。當你設計或除錯一個連網應用時,你會去轉的,正是這些旋鈕,因為它們是網際網路上每一個協定都早已以自己的方式回答過的問題。

你現在站在協定堆疊的頂端,手裡握著一張可用的地圖,標示著應用程式究竟如何交談:誰發起、狀態住哪、豐富資料如何編碼,以及每個協定如何透過 DNS 找到自己的夥伴。在你底下,坐著讓這一切成為可能的各個層次——可靠傳輸、全球路由、加上訊框的鏈路、原始位元——而你已經爬過了其中每一層。從這裡開始,這道梯子轉向那些同時包覆所有這些協定的橫切議題:它們預設都不具備的安全性,以及讓整件事變快又找得到的命名、快取與傳遞系統。