SMTP 的全名是:Simple Mail Transfer Protocol
SMTP 是 string stream 組成的協議,因此即便用 telnet 也可以送出信件。
以最常見的 SMTP 舉例,假設今天有以下情景
rance_jen@outlook.com 想要寄信給 daniel_Yu@outlook.com,同時副本給 xu_hsin_liu@outlook.com。
S 指 Server, C 指 Client
參考這裏
這裡的一切資訊都是不可信的,SMTP 沒有驗證機制,因此 Client 可以聲稱自己來自任何 Domain。
以下一一解讀各個 command,以及可以檢驗的機制
參考這裏
Following commands are not case sensitive
HELO {HELO_DOMAIN}
Client 連線後第一個指令,用以告訴對方自己的 Domain。
MAIL FROM:<{SMPT_FROM}>
用來告訴對方這封 mail 是來自什麼 Domain
SMPT_FROM 不是信件上面顯示的 From Address,這個資訊通常只有 Mail Server 知道。
SMPT_FROM
不是信件上面顯示的 to Address,這個是伺服器真正用來決定要把信寄到哪個 address 的欄位。
SMTP_TO
和 eml 內的收件人(To)是可以不一樣的,所以即便收到一個收件人看起來不是自己的信也是正常的。
DATA
代表接下來開始傳輸信件內容,就是以下的 EML 格式
QUIT
結束傳輸。
由於 SMTP 是基於 TCP 的協定,Mail Server 在收到 TCP 連線時會取得 Client 的 IP,此資訊通常稱 Sender IP
,由於是在 SMTP 通訊中少數較難偽造的資訊,因此常用於驗證信件合法性,下面會再提到。
詳細 spec 可以參考這裡
以下是一個 eml
我們可以從上往下一點一點來解讀這封 Mail
這邊屬於 eml header,郵箱顯示的 寄件人/收件人/副本/主旨
一般都是由這裡產生的。
雖然這裡的收件人可以亂填,但大多數郵件系統都會比對 SMTP_FROM
和 EML 內的 From
是否來自相同 Domain,以及 Domain 對應的 SPF 和 Sender IP
是否符合。
SPF 是一種特定格式的 DNS Record,詳細請見下方章節。
以下只列出比較常顯示的 Header
再強調一次,這裡的資訊都是「顯示用」的,郵件信箱實際要把信件寄給誰是按照
SMTP_TO
是判斷的。
這也是為何按下回覆信件時,我們甚至可以去修改下面顯示的過往信件內容/時間/寄件者,就是因為這些顯示的真的都只是純文字而已。
MIME 將信件內文分割成多個 boundary,並且一個 boundary 可以有多個表示形式,需連在一起表示並用 --{BOUNDARY_NAME}--
作為結尾
上敘是 B_3692947709_2010432344
的 text/plain
類型表示方式。
上敘是 B_3692947709_2010432344
的 text/html
類型表示方式。
由於現在的信箱大多支援 html email,因此寄件者通常會提供一種以上的顯示方式讓郵件顯示器來選擇。
通常提供了 text/plain
的正規郵件(指非詐騙/釣魚/垃圾等信件) 被封鎖的機率較低,因為針對 text/plain
的掃描遠比 text/html
容易也更成熟,並且也可以透過比對 text/html
。
以 Tiktok 的驗證碼信件來說
Nope, 沒有 text/plain
的部分,根據目前遇到的問題不同,建議可以在這方面再多做研究及測試。
根據目的為「避免被分類為垃圾信件」或「希望被分到主要信件」,這兩種需求的不同,參考方向也會不同。
不過以個人信箱,以下幾種創作平台的通知信件為例子。
同樣是訊息的創作推送,同樣是非中文,僅有包含 ontent-Type: text/plain; charset=UTF-8
的 pixivFanbox 會自動被分類到「主要信件」,其他被分到了次要顯示的「最新快訊」去,以個人經驗來說確實有測試的價值。
以下三種檢驗機制都是基於 DNS 來實作的。
參考這裡
驗證發送方的可靠性
當 Google.com(Receiver) 收到宣稱來自 outlook.com(Sender) 的信件時,Receiver 會做去查詢對方的 txt record
其中這段 ip4:157.55.9.128/25
直接說明了 outlook.com 的合法 Sender IP,也可以透過 include:spf-a.hotmail.com
這種字串來指向其他 domain 的 txt record
example:
當我今天想打開 Tiktok 收到的驗證信
為什麼通過 SPF 呢? 因為
然後取 mailgun.org
的 spf 來看
再取對應的 spf2.mailgun.org
的 spf 來看
而 69.72.44.186 確實在 69.72.32.0/20 的 cidr range 之內,故 spf 認證通過。
參考這裡
驗證內文的可靠性,完整性
DKIM 的格式參考 RFC 4871
具體可從 eml header 直接組出來,具體如下
對應查詢指令為 dig {s}._domainkey.{d} txt
也就是 dig krs._domainkey.register.account.tiktok.com txt
就會拿到對應的 public key "k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwLL5RYgbmUEqP7mz40wLuYuiNZfuFqrEJIwNr7LpcszmY2+zF1Pa8XBgDyoVKoAMC+IcKmRUR6pso4MhR3fuwJmXCZXHMezXi0WyRdmPsGAqG++1z3Y6hxafm0LYIJaaXRQ0iZQEdZkKwn5OWmTQGpSIEi6TF4rW6H37EUar1twIDAQAB"
並用此 public key 去驗證 b=
和 bh=
欄位的簽名即可。
參考這裡
針對上敘 SPF/DKIM 驗證失敗信件的處理方式。
格式一樣參考 RFC 7489
一樣用案例出發
就代表了上面的 SPF 跟 DKIM 若是沒通過建議發到垃圾信箱去,處理的比例為 100%,並且同時把信件資料回報到 mailauth-reports@bytedance.com
全名是:Extended SMTP
SMTP 的擴充協議,增加了以下幾種指令。
STARTTLS
尤其重要,如果沒有在連線後首先進行 TLS 交握,後續信件內容及認證內容都會以明文傳遞的。
SMTP
現在常見的手法,藉由是否拉下特定圖片為 tracking 的標的
以 tiktok 驗證信為例,在整個 html mail 的最後面有
這目的就明顯啦,或是像 shopback 也有
特別顯示的超小,這意圖我覺得就很明顯 la
見 TL;DR