特殊事件處理篇

mail server (MTA) 加上 SPF, DKIM, DMARC

寄信到 gmail 一直被檔!說是垃圾信!好垃圾...原來是需要修改 DNS 呢!

最近更新時間: 2022/06/03

前陣子鳥嫂一直說,我們 mail server 的信件一直被 gmail 退信!鳥哥想說,這怎麼可能!我們又不是垃圾發送站! mail server 裡面似乎也沒有什麼怪異的用戶。不過,既然有要求,那當然要設法解決!於是就發現了... 老天爺啊~ mail server 竟然真的被擋住了!而且,問題還不是 mail server!問題在 DNS 設定上! 這也太有趣了!

問題發生的狀況說明

鳥哥之前待的實驗室,因為信件容量的關係,所以不想要使用 gmail,而是自行搭建 mail server 來收發信件。 之前使用上都沒有問題。不過,似乎從前幾周開始,實驗室夥伴寄信到 gmail 時,該信件會被踢回來! 這讓鳥哥覺得怪!因為,沒道理我們會被列為黑名單!真是太怪了!於是,跑去找 /var/log/maillog 的內容, 發現到底下的紀錄:

to=<xxxx@gmail.com>, relay=gmail-smtp-in.l.google.com[142.250.157.26]:25, delay=4, 
delays=0.25/0.01/0.77/2.9, dsn=5.7.1, status=bounced (host gmail-smtp-in.l.google.com[142.250.157.26] 
said: 550-5.7.1 Our system has detected that this message is 
550-5.7.1 likely unsolicited mail. To reduce the amount of spam sent to Gmail, 550-5.7.1 
this message has been blocked. Please visit 550-5.7.1  
https://support.google.com/mail/?p=UnsolicitedMessageError 550 5.7.1  for more information.
f23-20020a631017000000b003f5e581cd89si1174487pgl.833 - gsmtp (in reply to end of DATA command))

看看關鍵字,還真的被當成垃圾郵件發送網站!這讓我很不能接受!於是開始搜尋 gmail 擋信的原因。 看起來,網際網路上這個問題真的很嚴重!大家都發生過這個狀況!鳥哥想說, gmail 是在大頭症嘛?幹麻擋人家? 後來查了查~似乎也不能怪人家!畢竟垃圾信件真的很多!如果不是很合法的郵件主機,那麼抵擋住, 似乎也不是什麼錯誤的事情。好吧!不怪你!怪我啦!

查詢處理方案的過程

後來查到幾篇寫的挺清楚的文件,請到底下的參考資料查詢相關網址。總的來說,就是目前的 gmail 以及主要的 mail server 群,為了擔心系統被垃圾信件衝爆,所以設定了幾個重要的查核點,可以幫助 gmail 驗證發信站是否為合法的 mail server 這樣。以前的檢查很簡單,只要有 MX 的 DNS 紀錄,那就算是合法的 mail server 了。 但是 DNS 的 MX 設定也太簡單!所以,後來就又衍生出許多的機制。大致上如下:(我們以 gmail 為收信站做例子)

  • SPF (Sender Policy Framework):寄件者政策框架

    當 gmail 收到一封信件後,他會檢查這封信件的發送者。 然後找到這信件的發信站。SPF 就由 email (例如 userpig@example.com) 找到 example.com 這個 mail server 的來源,然後透過找尋 DNS 當中的 example.com 裡面的 TXT 紀錄, 當有 spf 的紀錄值,而且這封信件是來自 spf 記載的合法的 mail server 寄出的,那就通過驗證。

    因為我們經常會收到 email 是 userpig@example.com 的郵件,但是該郵件卻是偽裝的! 實際可能來自於 somewhere.com 的 mail server!這種情況下,透過 spf 就可以擋掉這種錯誤的信件問題。

  • DKIM (DomainKeys Identified Mail):網域驗證郵件功能

    基本上,如同 ssh 的金鑰系統一般,如果發信者/收件者之間,能夠透過金鑰系統進行加解密, 這樣不是讓郵件更安全!郵件資料更不容易被竊取與竄改!所以就有了這個 DKIM 的機制。 說穿了,基本上就是,先建立一對金鑰,然後,透過 DNS 的設定,將公鑰公開出去, 然後,寄件者寄出信件時,需要主動告知收信端的 mail server,要怎麼用那一把公鑰解密! 然後收信端才有辦法用正確的公鑰來解密。

    老實說,雖然這樣信件的機密性比較好,不過,並非所有的 mail server 都知道怎麼應用 DKIM 機制解密, 當然也就可能造成收件者只會看到一堆亂碼的情境吧!同時,發信者也要在 MTA 上面設定好自動加密, 否則,發信也是挺麻煩的!除非是 gmail 的信箱寄到 gmail 的信箱,因為某些公司與 gmail 合作啊! 這樣用他們家提供的成對金鑰,就沒啥大問題!不過,這部份你確實可以先略過!

  • DMARC (Domain-based Message Authentication, Reporting & Conformance):以領域名稱為主的訊息驗證、報告與確認機制

    讓接收端的郵件主機進行一些政策處理,主要在處理當一封郵件在 SPF 或 DKIM 處理失敗後,應該如何應對的處理方式。

最需要知道的其實是 DMARC 這個機制!由 https://dmarc.org 官網的介紹,裡面最重要的一張圖如下所示,先看看下圖,底下我們依序稍微解釋一下:

DMARC 流程
DMARC 的運作流程
  • 第一橫列與發信端 mail server 有關,使用者先製作信件,然後發信時塞入 DKIM 的表頭資料 (向收件端告知需要解密), 之後才送到郵件接收端的 mail server 上。
  • 第二橫列主要跟收件端 mail server 有關,包括:發現使用 DKIM 的表頭,就進行驗證 DKIM 的金鑰一致性,同時予以解密。 然後透過 SPF 的設定,確認發信端的來源 (一般指 IP) 是正確的,然後就開始帶入 DMARC 的規則去處理這封郵件, 包括通過、隔離與退信等。
  • 以上任務確認完畢後,再帶入後續的病毒分析、郵件過濾等流程。
  • 關於 DNS 的 TXT 設定

上述的動作幾乎都與 MTA 設定無關,只與 DNS 紀錄資料有關!相當有趣吧!mail server 的驗證竟然是透過 DNS 呢! 而且還是當初我們覺得不是太重要的 TXT 純文字資訊哩!我們先來看一下 gmail.com 與 _dmarc.gmail.com 對於 TXT 的設定是什麼在說:

[root@email ~]# dig -t txt gmail.com
;; QUESTION SECTION:
;gmail.com.      IN  TXT

;; ANSWER SECTION:
gmail.com.  300  IN  TXT  "v=spf1 redirect=_spf.google.com"

[root@email ~]# dig -t txt _dmarc.gmail.com
;; QUESTION SECTION:
;_dmarc.gmail.com.      IN  TXT

;; ANSWER SECTION:
_dmarc.gmail.com.  600  IN  TXT  "v=DMARC1; p=none; sp=quarantine; rua=mailto:mailauth-reports@google.com"

[root@email ~]# dig -t txt arc-20160816._domainkey.google.com
;; QUESTION SECTION:
;arc-20160816._domainkey.google.com. IN TXT

;; ANSWER SECTION:
arc-20160816._domainkey.google.com. 3600 IN TXT "k=rsa; p=MIIBI....."

基本上, spf 的設定與本身的郵件領域有關,至於 DMARC 則與『_dmarc.你的領域』有關!而 DKIM 設計比較難找~ 最簡單的方法是,到你的 gmail 裡面,隨便找一封也是 gmail 的信件,然後在更多資料的地方選擇『顯示原始郵件』的資料, 整個畫面流程有點像底下這樣:

看 gmail 的原始郵件
看 gmail 的原始郵件
看 gmail 的原始郵件去找出 DKIM 的 selector 與 domain
裡面就有可能會有類似底下的字樣:

ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816;
        h=content-transfer-encoding:subject:date:importance:priority:to:from
         :mime-version:message-id;
        bh=tVI7M4hfPvo9bxH8oeJRhV5eTOcWtI6XVBVBDR9/HsE=;
        b=rcrYB6V7ELMApaI14jcsiwISIok/Ao3DabJ0upjQRzePXyDGYPMmJwYSsLFwBthYFq
         7yZiEjjy922ppaIwaVxg17YvyoYHT97U2XzHQ2qMlQYLqzXr39BHzS25keTPmeVcN001

裡面那個 s=arc-20160816 指的是選擇器 (selector),搭配 d=google.com 的領域名稱,搭配 _domainkey 這個關鍵字, 最終就得到『 arc-20160816._domainkey.google.com 』這個領域名稱了!再透過 dig 去追蹤, 就可以得到 DKIM 的公鑰資料!所以總結一下,你需要設定的三個領域的 TXT 項目,大致有:

  • SFP: 如 gmail.com, mail server 本身的網域名稱
  • DMARC: 如 _dmarc.gmail.com, DMARC 搭配 mail server 網域的主機名稱
  • DKIM: 如 arc-20160816._domainkey.google.com, DKIM 使用 selector 與 _domainkyey 搭配 google server 網域的主機名稱

底下,就讓我們一個一個來設定!還是得要說明,DKIM 不見得要設定,但是 SFP 與 DMARC 應該要處理妥當才好喔!

SPF, DKIM, DMARC 的基礎設定

就讓我們一項一項工作來處理!

  • 先設定發信站的 mail server 信任 IP 設定: SPF

根據 google 的文件說明, SPF 的實際作法可以參考底下的連結:

要達成上述的功能,你先要找到:

  • 你的 mail server 所在的 IP 位址。假如你有兩部 mail server,分別在 192.168.0.1 以及 192.168.10.1 時, 那就可以簡單的填寫位址為:『 ip4:192.168.0.0/24 ip4:192.168.10.0/24 』這樣。
  • 通常建議開放 gooogle 的網域,所以新增『 include:_spf.google.com 』
  • 另外建議再加上 a 與 mx 這兩個參數,讓與 mail server 有關的 A 與 MX 設定支援的 IP 也放行。

所以,針對 SPF 這個信任的發信端 mail server IP 設定當中,請修改你的 bind 設定檔,以鳥哥來說, 假設整個 domain 就是 mail server 的 IP,那設定值可以是這樣的:

[root@email ~]# vim /var/named/dynamic/named.your.domain
@  IN  MX 10   @
@  IN  TXT     "v=spf1 ip4:192.168.0.0/24 ip4:192.168.10.0/24 include:_spf.google.com a mx ~all"

這樣就搞定了 SPF 了!其他更詳細的設定,請自行參考上面的連結!

  • 再來處理 DMARC 的信件處理規則

信件通過 SPF 之後的處理規則,可以參考底下的資料設計:

基本上,就是新增一個 _dmarc.your.domain 的 DNS 紀錄,我們不做任何設計...直接交給 mail server 去處理過濾即可! 你唯一要設計的,是將 DMARC 可能產生的報表資料管理員的 email address 填寫進去即可。簡單的設計可以是這樣的 (跟前面一樣,假設你的 mail server 就是整個網域!):

[root@email ~]# vim /var/named/dynamic/named.your.domain
_dmarc  IN   TXT   "v=DMARC1; p=none; sp=none, rua=mailto:dmarc-reports@your.mail.server"
  • DKIM 金鑰與選取器的設定

基本上,如果你寄出的 mail 表頭沒有額外指定,接收端的 mail server 並不會套用 DKIM 的項目。 但是,某些時刻,我們還是得要自製一下這個 public key 比較好!至少在進行某些測試時, 比較容易通過啦!呵呵!要自製金鑰,可以前往底下這個網站自己處理好:

dkim 金鑰系統
dkim 金鑰系統
由 dkimcore 網站自製的 selector 與 domain

如上所示,你會製作出一個 1654239065.example 的選取器,以及領域名稱為『 example.com 』的設定值。 然後,還會得到一組完整的 rsa 加密的雜湊碼,這樣就可以拿來設計你的 DNS 了!設計如下:

[root@email ~]# vim /var/named/dynamic/named.your.domain
1654239065.example._domainkey.example.com. IN TXT "v=DKIM1;k=rsa;t=s;p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNAD...."

特別注意,不要使用網頁上面的格式!我們的 rockylinux 8 應該是支援非常長的字串,所以,將全部的資料串在一起, 使用一對雙引號涵蓋即可。然後,特別加上 k=rsa 那一段!指定編碼為 rsa 的意思!這樣就搞定了全部的設定值了!

增加 gmail 的驗證碼

即使上面的 DNS 已經設定妥當,但是,某些 mail server 還是不買單的!例如 gmail 還是不買單... 其實不只 gmail 啦,比較大型的 mail server 供應商,基本上,都會要求寄信單位『驗證』其正確性! 再次去查看 google.com 的 TXT 值,有點像這樣:

[root@email ~]# dig -t txt google.com
;; ANSWER SECTION:
google.com.    3600    IN      TXT     "MS=E4A68B9AB2BB9670BCE15412F62916164C0B20BB"
google.com.    3600    IN      TXT     "docusign=1b0a6754-49b1-4db5-8540-d2c12664b289"
google.com.    3600    IN      TXT     "webexdomainverification.8YX6G=6e6922db-e3e6-4a36-904e-a805c28087fa"
google.com.    3600    IN      TXT     "docusign=05958488-4752-4ef2-95eb-aa7ba8a3bd0e"
google.com.    3600    IN      TXT     "globalsign-smime-dv=CDYX+XFHUw2wml6/Gb8+59BsH31KzUr6c1l2BPvqKX8="
google.com.    3600    IN      TXT     "v=spf1 include:_spf.google.com ~all"
google.com.    3600    IN      TXT     "facebook-domain-verification=22rm551cu4k0ab0bxsw536tlds4h95"
google.com.    3600    IN      TXT     "google-site-verification=wD8N7i1JTNTkezJ49swvWW48f8_9xveREV4oB-0Hf5o"
google.com.    3600    IN      TXT     "google-site-verification=TV9-DBe4R80X4v0M4U_bd_J9cpOJM0nikft0jAgjmsQ"
google.com.    3600    IN      TXT     "apple-domain-verification=30afIBcvSuDV2PLX"

即使是 google,也得要對 facebook, apple 買單的!所以啦!不要憤憤不平!大家都一樣 (這其實是對鳥哥自己說的...)。 好吧,想要讓 gmail 不要退我們的信件,也只能夠處理一下啦!請前往底下的網站 (你必須要擁有 gmail 的帳號), 然後準備入你的 mail server 吧!

在登入上述網頁之後,按下『Get Started』之後,會進入到您管理的網站資料。 在整個瀏覽器右下方有個加號 (+),按下它!然後就會出現如下的畫面:

gmail 驗證碼

輸入你的 mail server 網域,就按下『 NEXT 』按鈕。然後就會出現如下的畫面:

gmail 驗證碼

你會看到 TXT record 那個項目!現在,先不要繼續!先來搞定 DNS 的設定值:

[root@email ~]# vim /var/named/dynamic/named.your.domain
@ IN  TXT   "google-site-verification=UGFF_PfzUvg7WcJ8mhYlc3WNe8o0DKZNCqhSsHTQBbc"

[root@email ~]# systemctl restart named-chroot

修改你的 DNS 設定值,增加這一段設計在 TXT 的項目中,然後重新啟動 DNS。要注意喔,那個 SOA 的序號一定要長大! 而且,注意你的 TTL 設定,一定要在超過 TTL 設定的時間之後,才回去按下 VERIFY 按鈕! 否則,你剛剛的 DNS 設定,可能還沒有被啟用啊!要注意!要注意!

透過這樣的設計,你的 mail server 應該不至於被 gmail 擋住了!而如果你又被其他 mail server 擋住, 大概只要重複這個驗證碼的步驟來處理即可。只是,得要到對方的網站去取得你的驗證碼囉!

測試設定值

上述功能處理完畢之後,先來查閱看看,我們的 mail server 是否真的設定妥當了!要注意喔, 你的 DNS 伺服器重新啟動之後,要超過 ttl 設定值,再來測試,會比較準。所以囉,這次的 mail server 問題, 其實要解決的是 DNS 的設定!哈哈哈!先來看一下第一個測試網站的測試結果:

要注意的是,輸入的測試值應該是你的 domain name 才對!不過,如果你的設定主要是針對 mail server, 而且 mail server 並不是整體網域的話,那就輸入你的 mail server 主機名稱即可。基本上,會有個驚嘆號, 顯示『DMARC Policy Not Enabled』,那個應該是沒關係!不用理會!除非有遇到其他『X』的符號,否則, 應該就是順利過關!

另外一個檢測的方式,是 google 自己提供的!前往底下的網址測試看看:

去到上面的網站,在網域名稱填寫你的 mail server 主機名稱,然後在 DKIM 選取器填寫剛剛我們在 DKIMcore 網站上面指定到的 selector,然後按下『執行檢查』,最後就會出現一張報表, 報表裡面沒有出現重大錯誤即可!基本上,會有點像底下這樣:

gmail 驗證碼

鳥哥自己認為第一個警示可以不用理他!因為鳥哥自己的 mail server 並沒有跟 gmail 合作,所以出現第一個警告, 應該也是合理的!另外,那個 spf 的按鈕可以按一下,確認你的發信 IP 以及 google 的 IP 而已。這樣的整個流程, 你的 mail server 應該就不會被抵擋了!祝福各位!

參考資料

修改歷史:
  • 2022/06/03:最近遇到被 gmail 退信的問題,找了找,終於找到解決方案!怕忘記,趕緊寫一篇!
2022/06/03 以來統計人數
計數器
https://linux.vbird.org is designed by VBird during 2001~2022.