AWS SES 寄信設定踩坑實錄:IAM 權限、Cloudflare DNS 與 WordPress 沙盒測試

AWS SES 寄信設定踩坑實錄:IAM 權限、Cloudflare DNS 與 WordPress 沙盒測試

626 瀏覽
2026-09-13 更新
AWS SES 寄信設定實作:IAM 權限、DNS 與沙盒測試的封面示意圖

這次在串接 AWS SES 與 WordPress 時,我原本以為填好金鑰就能寄信,結果一路遇到寄件地址未授權、IAM 權限不足、收件人也要驗證,最後連「已排入佇列」都差點被當成寄送成功。

這篇把我實際卡住的地方整理出來。這次已確認測試信取得 AWS Message ID;正式寄送權限仍需另外申請,不能把沙盒內測試通過寫成已解除沙盒。以下信箱與帳號範例皆使用示意資料。

先看 AWS SES 寄信卡在哪一關

看到的結果代表什麼下一步查哪裡
金鑰無效或簽章錯誤AWS 尚未接受這次身分驗證IAM 金鑰狀態、配對、Region 與簽章
domain_not_allowed這次是自建 SES Server 拒絕寄件身分AWS 身分驗證與 Server 的網站授權
ses:SendRawEmail 權限不足金鑰能辨識,但不允許該操作IAM 已儲存並附加的政策
已排入 Server 佇列Server 收到工作,還未確認寄出工作列表、背景排程與錯誤原因
收件地址未驗證可能仍受沙盒限制同區域的帳戶狀態與收件身分
AWS 已接受/有 Message IDAWS 已接受這封郵件後續送達事件與實際信箱

我後來把排查順序固定成:網站授權 → 寄件身分 → 佇列處理 → AWS 回應 → 送達確認。先知道停在哪一段,才不會每次失敗都重新換金鑰。

第一關:API 金鑰在 IAM,權限改好還要儲存

在 SES 主控台找不到「API Key」很正常。我這次的外掛走 AWS API,使用的是 IAM 的 Access Key ID 與 Secret Access Key;SMTP 連線則使用 SMTP 憑證,兩者不能直接混填。AWS 的憑證類型說明有列出差異。

IAM 使用者的「安全憑證」可建立存取金鑰。這次實際遇到金鑰停用,以及網站儲存的金鑰與 AWS 啟用的那組不一致。檢查時要確認 ID 與 Secret 是同一組,不能拿新 ID 配舊 Secret。AWS 的 Secret 只會在建立時提供;外掛的「顯示原值」只能顯示自己已保存的值,不能向 AWS 找回遺失的 Secret。參考 IAM 金鑰管理

這次真正漏掉的是 ses:SendRawEmail

原本的政策包含 ses:GetEmailIdentityses:SendEmail,實際寄送仍被拒絕。錯誤明確指出沒有 ses:SendRawEmail 權限。我的外掛使用 Raw MIME 內容,因此依實際回應補上這個動作;不能只看到 SDK 或 API 方法叫 SendEmail,就認定 IAM 只需同名權限。

以下是這次新加坡區域的政策範例。GetEmailIdentity 是給外掛查詢身分用,並非每個單純寄信程式都需要。Resource: "*" 允許範圍較廣,正式環境應依實際使用的身分與資源再縮限。AWS 的 Unauthorized 排查文件也提醒要檢查實際使用的 IAM 身分與政策。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ses:GetEmailIdentity",
        "ses:SendEmail",
        "ses:SendRawEmail"
      ],
      "Resource": "*",
      "Condition": {
        "StringEquals": {
          "aws:RequestedRegion": "ap-southeast-1"
        }
      }
    }
  ]
}

另一個容易忽略的地方,是政策已在編輯畫面加入權限,卻還停在最後的檢閱頁。我這次就遇到這種情況。必須按下「儲存變更」,再回使用者的「許可」確認政策內容,測試才有意義。

第二關:用 API 寄信,也必須有合法的寄件者

我一開始的疑問是:「我是用 API 寄信,為什麼還要填完整寄件 Email?」因為 API 是傳送方式;收件人看到的 From 仍然要有地址,而且必須符合 SES 的寄件身分驗證。

  • 快速測試:在 SES「身分」建立單一 Email,收取驗證信並完成驗證。
  • 正式使用自有網域:建立網域身分,將 AWS 提供的 DKIM 記錄加到 DNS。
  • Region 要一致:這次使用 ap-southeast-1,身分也要在新加坡區域驗證。

驗證一個 Email,只代表該地址可用,並不代表整個信箱服務的網域都歸你使用。自有網域驗證適合需要多個寄件地址的情境。參考 AWS 寄件身分驗證

這次的 domain_not_allowed 還多了一層原因:它是自建 Orca SES Server 的授權錯誤,不是 AWS 的通用錯誤碼。AWS 已驗證地址後,Server 仍要確認這個客戶網站被允許使用該寄件身分,避免不同客戶互用寄件地址。

所以我在 Client 補上「寄件者 Email」與「寄件者名稱」,未指定時沿用 WordPress 的寄件者設定。查問題時看實際的 From,不要直接假設它就是 WordPress 管理員信箱。

希望客戶可以回信,要處理 Reply-To

例如通知信以已驗證的 [email protected] 寄出,希望回信到客服,就將 Reply-To 設為實際有人收信的 [email protected]。SES 不會因為你填了一個 service 地址,就替你建立可收信的信箱。AWS SendEmail API 說明也分別列出 From 與 Reply-To 的用途。

第三關:Cloudflare 的 MX 要加在 MAIL FROM 子網域

這次設定 ses.orca-biz.com 時,AWS 顯示一筆值為 10 feedback-smtp.ap-southeast-1.amazonses.com 的 MX。這是自訂 MAIL FROM 設定,主要與退信路徑及 SPF 有關;它和收件人畫面上的 From、按回覆時使用的 Reply-To,是不同欄位。

換成示意網域 example.com,Cloudflare 應新增下列兩筆;操作前要先在 SES 設定相同的 MAIL FROM 子網域,並以 AWS 顯示的內容為準。

類型名稱內容/郵件伺服器優先順序
MXsesfeedback-smtp.ap-southeast-1.amazonses.com10
TXTsesv=spf1 include:amazonses.com ~all不適用

我當時把名稱填成全形 ,郵件伺服器卻填成自己的 ses 子網域。正確做法是:名稱填 ses,郵件伺服器填 AWS 提供的主機,數字 10 放到獨立的優先順序欄位。

不要因此改掉根網域原本 Google Workspace 的收信 MX。自訂 MAIL FROM 是選用設定;採用時才要補上相應的 MX 與 SPF,同一個 MAIL FROM 子網域只能有一筆符合要求的 MX。DNS 查得到,也還要等 SES 偵測後更新狀態。參考 AWS 自訂 MAIL FROM 文件

收信轉寄與網站發信也應分開理解。如果想先釐清自己的信件會收去哪裡,可以搭配站上的 Cloudflare Email Routing 實作文章閱讀。

第四關:Local 可以測試,但 Job 編號不等於已寄出

當畫面終於顯示「已排入 Server 佇列(job: 1)」,我才發現測試按鈕回報得不夠清楚。這個 Job 是我自己的寄信 Server 建立的工作編號,不是 AWS 已寄出的證明。背景工作還要拿到這筆任務,真正呼叫 SES,才知道成功或失敗。

本機 WordPress 可以測試,只要 Client 連得到 Server,Server 也連得到 AWS。容易卡住的是背景排程:預設 WP-Cron 依頁面請求觸發,Local 沒有瀏覽流量時,工作不一定準時執行。WordPress 官方 WP-Cron 說明有解釋這個限制。排查方式也可參考我的 WP-CLI 與 WP-Cron 排查文章

這次 Job 1 在實際執行後顯示 IAM 權限不足;修正後,另一封測試信拿到 AWS Message ID。但再換一個未驗證收件信箱,又被沙盒限制拒絕。這幾個結果分別指出不同問題,不能只用一個「寄送失敗」涵蓋。

我因此補上兩邊的寄信紀錄:Client 只看自己網站的信,Server 看所有客戶;都支援每頁 20 筆分頁、狀態與工作編號查詢,Server 再多客戶和網站篩選。查詢不會重寄,也不要求客戶登入 Server。

列表將成功狀態寫成「AWS 已接受」,因為 API 回傳 Message ID 仍不等於郵件已進收件匣。若要確認後續送達、退信或投訴,還要接事件通知與處理流程。參考 SES 事件通知

第五關:會員不能逐一驗證?下一步是申請離開沙盒

寄件地址驗證好後,收件地址仍被拒絕,原因是新加坡區域的 SES 帳戶還在沙盒。這時只能寄給已驗證的收件身分或 AWS 模擬信箱;要寄給一般會員,必須申請生產存取權。

  1. 切到實際寄送的區域,例如新加坡 ap-southeast-1
  2. 進入「完成設定」,按「請求生產存取權」。
  3. 依主要用途選擇郵件類型:會員促銷、電子報選「行銷」;以訂單、重設密碼等觸發通知為主則選「交易」。
  4. 填網站 URL 與聯絡資料。網站應能讓審核人員了解業務,不一定要填 API 主機。
  5. 確認收件人同意收信,並已有退信與投訴處理程序,才能如實勾選確認並提交。

AWS 通常在 24 小時內初次回覆,可能要求補充資料,不能保證一定核准。正式核准後,會員不必逐一驗證收件信箱;寄件身分仍要驗證。沙盒狀態依區域分開,切換 Region 不等於沿用原區域核准。參考 AWS 生產存取權申請流程

這次我完成的是寄送測試與查詢工具,還不能因此宣稱整套會員群發已經準備完成。退訂、退信與投訴後停止寄送,以及依 AWS 額度控制發送速度,仍是正式使用前要落實的工作。自訂 MAIL FROM 的 MX 加好了,也不會自動解除沙盒。

這次調整後的 WordPress 寄信架構

部署規劃是把 SES Server 與 orca-customer-license 放在同一個 WordPress,服務站使用 app.orca-biz.com;客戶網站只裝 Client。這是部署規劃,本文的實際寄送測試是在本機環境完成。

客戶網站:WordPress → Orca SES Client
                         ↓ 網站授權與簽章
中央服務:SES Server + Customer License
                         ↓ 佇列與背景工作
                      AWS SES
                         ↓ 後續送達/退信結果
                       收件人

AWS 金鑰集中放在 Server。Client 沿用虎鯨後台的共用 Site Key,由 Server 驗證網站與模組授權,使用者不用再填另一組 SES API Key 或手動 Site ID。這裡的 client/網站隔離是外掛自己的設計,不是 AWS 自動替每個 WordPress 網站完成的設定。

後台文字也一起修正。例如「Selective 模式下,收件人數達門檻即轉交 server」,改用「當一封信的收件人達到設定人數,就交由集中寄信服務處理;填 0 表示不使用這個人數條件」來解釋。這個門檻是外掛的寄送分流規則,不是 AWS 的寄信額度,也不會改變沙盒限制。

我這次最實用的收穫,是讓每一封信都能回答三個問題:誰接到工作、誰拒絕了它、下一步該查哪裡。有了這些資訊,遇到失敗才不會一直在 DNS、金鑰和程式之間來回猜。

常見問題 FAQ

AWS SES 只要填 Access Key 和 Secret Key 就能寄信嗎?

還不夠。金鑰要有效、IAM 要允許程式實際使用的寄信動作,寄件身分也要在同一個 Region 完成驗證。若帳戶還在沙盒,收件人也有限制;使用自建 Server 時,還要通過該服務的網站授權。

本機 localhost 或 Local WordPress 可以測試 SES 嗎?

可以,只要本機連得到寄信 Server,Server 也連得到 AWS。測試要使用已驗證的寄件身分,沙盒內還要搭配已驗證收件人或 AWS 模擬信箱。若採佇列寄送,背景排程也必須有執行。

設定 SES 一定要修改原本 Google Workspace 的 MX 嗎?

不需要。本文的 MX 是設在自訂 MAIL FROM 子網域,用來處理退信,不是把公司原本的收信服務搬到 SES。根網域的收信 MX 應保留,子網域的 MX 與 SPF 則依 AWS 顯示的值設定。

離開 SES 沙盒後,會員還要逐一驗證收件信箱嗎?

不需要;正式寄送權限核准後,一般收件人不必逐一驗證,但寄件身分仍要驗證。申請會依 AWS 區域審核,必須如實說明用途、收件人同意來源,以及退信與投訴處理方式。

▧ 文章分類

▧ Google熱蒐文章

▧ 最新文章

✦ 虎鯨 OrcaBiz SEO 優化專業團隊 ✦

專業 SEO 公司幫助你將流量累積成看得見的業績,成為長期有效的最強業務!

載入中…
沒有更多相關文章可閱讀