
本篇主題同詩意副標 — 我寫的信不是被忽視,是根本沒被讀過。contact form 寫好了,我寄信給自己測試,Gmail 收到 ✅,Outlook 沒收到 ❌,信不在垃圾信件夾,不在主收件匣,直接消失。從這一刻起我跌進 Email 認證地獄,前後 8 次踩坑、4 條 DNS records、一場 Brevo 文件馬拉松,才把 SPF / DKIM / DMARC 弄齊。這篇是給未來的我、給跟我一樣以為「裝 WP Mail SMTP 就能寄信」的工程師,以及想理解「為什麼客戶說沒收到我的報價單」的所有 freelancer。
自架站的寄信路徑不只一條 — contact form、WP 通知信、訂閱者 confirmation、新文章推播、評論回覆通知。每一條都會打到收件方的 mail server,而每一台收件方 mail server 都在問同一個問題:「這封信真的是這個網域寄的嗎?」
這個問題在 1990 年代沒人在問,因為那時候 SMTP 是個無認證協定,任何人都可以假裝任何人寄信(這也是為什麼 spam 一度泛濫到不可收拾)。21 世紀後 SPF / DKIM / DMARC 三個標準陸續成形,變成現代 mail server 判斷信件「可不可信」的三件套。
對自架站站長來說,這三件套不是 nice-to-have,是 must-have。沒做齊的後果是 — 你的信進垃圾信件夾,或更慘,直接被丟掉,寄信方完全不知道。
至於為什麼選 Brevo(原 Sendinblue)— 免費版 300 封/天、SMTP relay 跟 Transactional API 都有、總部在法國 GDPR 合規、最重要是它的 Domain Authentication 介面對新手友善,DNS records 一條一條告訴你怎麼填。
Brevo SMTP relay:smtp-relay.brevo.com:587,WP Mail SMTP plugin 的後端,用我的 brevo 帳號 API key 認證。
SPF (Sender Policy Framework):DNS TXT record。內容像 v=spf1 include:spf.brevo.com ~all,白話說「這個網域的信只能從 spf.brevo.com 列出來的那些 IP 發,其他來源請小心對待」。
DKIM (DomainKeys Identified Mail):DNS CNAME record(Brevo 模式 ×2)。Brevo 用一把私鑰簽信,公鑰放在 DNS,收件方用公鑰驗證簽名。
DMARC (Domain-based Message Authentication):DNS TXT record。內容像 v=DMARC1; p=none; rua=mailto:report@xxx.com,告訴收件方「上面 SPF/DKIM 都不過時你想怎麼處理」。我用 p=none 觀察一段時間再決定要不要 quarantine 或 reject。
Cloudflare DNS 介面:加上面那 4 條 records 的工具。我的 dpdns.org 子網域已經委派給 Cloudflare(見上一篇),所以 records 加在 Cloudflare 後台。
心得分三條,因為這 8 次踩坑可以歸成三個關卡。
第一條:Gmail 通了 Outlook 沒通
第一次測試,我用 contact form 寄信給自己的 Gmail 跟 Outlook 帳號各一封。Gmail 收到了,進主收件匣,內文正常,簽名正常,完美。Outlook — 沒收到。垃圾信件夾找不到,quarantine 也找不到。直接憑空消失。
我去 Brevo dashboard 看寄信 log,看到那封信的狀態:
Hard Bounce
550-5.7.1 [77.32.148.28] Gmail has detected that this message
is likely unsolicited mail. To reduce the amount of spam sent to Gmail,
this message has been blocked.
(對,log 寫 Gmail 但實際上是 Outlook 用了類似的引擎判斷邏輯,訊息文字確實長這樣。)
第一次看到 550-5.7.1 我以為是我的內文寫得太像 spam — 內文就一句「測試訊息」,能多 spam?後來才知道 5.7.1 是「policy reason」家族的錯誤碼,跟內文無關,是 sender authentication 不過。簡單講:收件方根本不相信我是我。
第二條:漏 SPF 是新手最常犯的錯
我回去 Brevo Domain Authentication 介面,看到上面寫「4 條 DNS records 全部驗證通過」,brevo-code TXT ✅、brevo1._domainkey CNAME ✅、brevo2._domainkey CNAME ✅、_dmarc TXT ✅。四個綠勾我看了 30 秒,以為大功告成。
然後在 Brevo 文件第 N 段才看到:
⚠️ SPF record is not part of our default Domain Authentication.
You must add it manually if you don't already have one.
Brevo 的 Domain Authentication 預設只給你 brevo-code(domain ownership 驗證)+ DKIM ×2 + DMARC,SPF 要自己加。原因是 Brevo 不知道你網域有沒有其他寄信來源(Mailgun? Gmail Workspace? Postmark?),不能直接幫你寫 SPF。
但對只用 Brevo 的我來說,SPF 就是一條:
v=spf1 include:spf.brevo.com ~all
加進 Cloudflare TXT record 之後,等 5-10 分鐘 propagation,Outlook 就收到了。
Plugin / Service 的「全部驗證通過」
不一定是 全部
它只是「我們會檢查的部分都過了」
第三條:Outlook 暖機期是個社會學問題
SPF 加完之後,我以為終於沒事了。但接下來一週,Outlook 還是時靈時不靈 — 同樣的測試信,有時收到、有時消失。Gmail 完全穩定,Outlook 像在抽籤。
這時候我才理解到一件事 — DNS 上面寫「我相信誰」是技術問題,但 Outlook(或者說 Microsoft / Hotmail / Live)實際上「願不願意相信你」是社會問題。新註冊的網域,即使 SPF / DKIM / DMARC 全綠,Microsoft 還是會把你當成「半信任」狀態,觀察 1-2 週,看你的寄信頻率、退信率、被標記為 spam 的比例,再決定要不要把你的信送進主收件匣。
這個觀察期沒有 API、沒有 portal、沒有「申請信任」按鈕,只有時間。
DNS 上的信任
不是技術問題
是社會學問題 ──
我相信你說你是你
但我還是要看你做了什麼
那一週我每天寄一封測試信給 Outlook,大概第 10 天開始穩定收到。Brevo 文件後來才看到一段不起眼的提示:「For new domains, expect 1-2 weeks of warming period for major providers, especially Microsoft.」
我盯著這句話看了很久。沒辦法,新人不被信任,這在哪個世界都一樣。
「我寫的信不是被忽視,是根本沒被讀過」這句副標的重量,在你被退過幾次信之後才會懂。寄信不是技術問題就能解的事,它是技術 × 社會學 × 時間的乘積。
對工程師讀者 — DNS 4 條 records 全綠 + SPF 千萬不要漏。完整 records 內容放在文末彩蛋。對客戶讀者 — 你的網站 contact form 對方收不到信,八成是這篇講的問題。我能幫你 audit + 修。
| Type | Name | Content / Value |
|---|---|---|
| TXT | @ | brevo-code:xxxxxxxxxxxxxx (從 Brevo dashboard 取得) |
| CNAME | brevo1._domainkey | b.xxxxxxx.brevo-code.net |
| CNAME | brevo2._domainkey | b2.xxxxxxx.brevo-code.net |
| TXT | _dmarc | v=DMARC1; p=none; rua=mailto:你的@email.com |
| TXT | @ | v=spf1 include:spf.brevo.com ~all (← 別忘了這條) |
5 條,不是 4 條。Brevo 介面只顯示前 4 條,SPF 是隱藏關卡。
驗證工具我推薦 https://mxtoolbox.com/SuperTool.aspx,SPF / DKIM / DMARC 三個 lookup 都跑一次,看到三個綠勾才能放心。
真的累 寄信怎麼會這麼難 _(┐ ◟;゚д゚)ノ