在 Zeabur 上為 Ghost CMS 設定 Email 發信功能(Brevo SMTP)
Ghost 預設的 Direct 發信在雲端環境幾乎不可靠。記錄我把 Ghost 改成 Brevo SMTP 的完整過程,以及如何找出容器真實的出站 IP 解決白名單問題。
在把 Ghost CMS 部署到 Zeabur 之後,我一直沒有特別在意 Email 發信的問題——直到有一天想測試會員訂閱流程,才發現根本收不到任何確認信。翻了一下 Ghost 的設定,才知道預設的發信方式問題很大。這篇文章記錄我把 Ghost 的 Email 改成用 Brevo SMTP 發信的完整過程,以及中間踩到的一個讓我卡很久的坑。
為什麼 Ghost 預設的 Direct 發信不可靠
Ghost 預設的 mail__transport 是 Direct,意思是 Ghost 會直接從伺服器連線到收件方的 Mail Server 送出信件,中間不經過任何 SMTP relay。這在本地開發環境偶爾能用,但在正式環境幾乎可以確定會失敗,原因有幾個:
- 大多數雲端服務商(包含 Zeabur)的出站 IP 不在主流郵件服務商的信任名單內
- 沒有 DKIM 簽章,信件會被 Gmail、Outlook 等判定為可疑
- 容易被直接丟進垃圾信匣,甚至被拒收
結論是:只要是正式環境,一定要換成 SMTP relay。
為什麼選擇 Brevo
市面上的 SMTP 服務很多,我選 Brevo(前身是 Sendinblue)有幾個理由:
- 免費方案提供每天 300 封,對個人部落格完全夠用
- 支援自訂寄件網域,搭配 DKIM/SPF/DMARC 設定後信件不容易進垃圾信
- SMTP 設定簡單,不需要特殊設定就能用
設定寄件網域:透過 Cloudflare 自動驗證 DNS
在取得 SMTP 憑證之前,有一個步驟我覺得很值得特別說:設定寄件網域(Sender Domain)。
這步驟不是必要的,跳過也能發信——但如果沒有正確設定 DKIM 和 SPF,信件仍然容易被判定為可疑。既然都花時間設定了,順手做完才值得。
流程是這樣的:
- 進入 Brevo 後台,點選左側 Settings → Senders & IPs → Domains
- 點 Add a domain,輸入你的網域(例如
yourdomain.com) - Brevo 會列出幾筆需要新增的 DNS 記錄(DKIM、SPF、DMARC)
這裡有個讓我很驚喜的功能:因為我的網域是在 Cloudflare 購買和管理的,Brevo 提供了 直接登入 Cloudflare 自動設定 的選項。
點下 Connect to Cloudflare 後,頁面會跳轉到 Cloudflare 的 OAuth 授權頁面。登入 Cloudflare 帳號並授權之後,Brevo 會自動把所需的 DNS 記錄(包含 DKIM CNAME、SPF TXT、DMARC TXT)全部寫進 Cloudflare DNS,完全不用手動貼記錄。
授權完成後回到 Brevo,等幾分鐘讓 DNS 生效,再點 Verify 確認即可。驗證通過後,這個網域就可以作為合法的寄件來源。
注意:Cloudflare 的 DNS API 授權是 per-account 的,確認你用的 Cloudflare 帳號有該網域的管理權限。
申請帳號並取得 SMTP 憑證
到 brevo.com 註冊免費帳號,完成後進入後台:
- 點選左側選單的 Settings
- 找到 SMTP & API 頁面
- 在 SMTP 區塊可以看到 Server、Port、Login 等資訊
- 點 Generate a new SMTP key 產生密碼(只會顯示一次,要立刻儲存)

Brevo 後台的 SMTP 設定頁,記下 Server、Port、Login 和新產生的 SMTP Key
取得的資訊大致如下:
- SMTP Server:
smtp-relay.brevo.com - Port:
587 - Login:你在 Brevo 申請的帳號 Email
- SMTP Key:剛才產生的密碼
在 Zeabur 設定 Ghost 的環境變數
有了 SMTP 憑證之後,到 Zeabur Dashboard 的 Ghost 服務,切換到 Variables 標籤,新增或更新以下幾個變數:
| 變數名稱 | 值 |
|---|---|
mail__transport |
SMTP |
mail__options__host |
smtp-relay.brevo.com |
mail__options__port |
587 |
mail__options__auth__user |
Brevo 帳號 Email |
mail__options__auth__pass |
Brevo SMTP Key |
mail__from |
你希望寄件人顯示的 Email(需在 Brevo 驗證過的網域) |
設定完記得重啟 Ghost 服務讓變數生效。
關鍵:IP 白名單要填對 IP
Brevo 的免費方案需要設定 IP 白名單,只有被允許的 IP 才能透過你的帳號發信。這裡我卡了一段時間,原因是我一開始填的 IP 填錯了。
直覺上,我用 dig 查了 Ghost 網域的 A 記錄,拿到一個 IP 填進去,結果測試寄信時仍然收到 525 5.7.1 Unauthorized IP address 的錯誤。
問題在於:DNS 查到的 IP 是入站流量的 IP(通常是 Load Balancer),但 Ghost 發 SMTP 請求時走的是容器自己的出站 IP,兩個不一定相同。
正確的做法是直接在容器內部查詢出站 IP:
npx zeabur@latest service exec --id <ghost-service-id> -- sh -c "wget -qO- https://api.ipify.org"
這樣得到的才是 Ghost 連線到 Brevo SMTP 時實際使用的 IP。把這個 IP 填到 Brevo 的 Settings → Authorized IPs:

Brevo 的 IP 白名單設定,要填容器的出站 IP 而不是 DNS 查到的入站 IP
測試成功
IP 白名單設定完成後,到 Ghost Admin 的 Posts,開啟任意一篇文章進入發布流程,在 Newsletter 選項下方會看到 Send a test email to yourself 按鈕,點下去應該就能收到測試信了。

Brevo 後台確認信件成功發出
FAQ
設定之後重啟,IP 會不會變?不一定,Zeabur 有時候重啟後 IP 不變,但不保證永遠如此。如果之後又出現 Unauthorized IP,用同樣的方式重新查一次容器出站 IP,更新白名單即可。免費方案每天 300 封夠用嗎?對個人部落格來說完全夠用。Ghost 的 Email 主要用在會員訂閱確認、登入 magic link、Newsletter 發送等,一般流量下每天 300 封綽綽有餘。Zeabur Email(ZSend)和 Brevo 有什麼差別?Zeabur Email 是 HTTP API 形式的發信服務(類似 Resend),適合透過程式碼呼叫 API 發信。Ghost 使用的是 SMTP 協定,兩者無法直接相容,所以需要另外搭配支援 SMTP 的服務。
結語
整個設定流程不算複雜,但「入站 IP 和出站 IP 不同」這個細節確實容易踩坑。如果你也在 Zeabur 上跑 Ghost,遇到 Unauthorized IP 的錯誤,記得用 service exec 查容器內部的出站 IP 再填白名單。