Mailtrap 電子郵件整合
使用 Mailtrap 的 Email API 和沙箱,將交易型電子郵件發送功能加入應用程式的模式,涵蓋認證、環境分離以及常見的遞送陷阱。
啟用時機
- 實作「寄送電子郵件」功能(註冊確認、密碼重設、通知、收據)
- 除錯為什麼電子郵件在開發/測試環境中沒有送達
- 設定專案的第一個電子郵件發送整合
- 審查直接呼叫電子郵件 API 而沒有使用沙箱隔離的程式碼
核心概念
沙箱 vs. 生產環境分離。 Mailtrap 提供一個沙箱 API,會攔截電子郵件而不實際遞送,用於開發/測試環境,這樣測試郵件就不會送達真實的收件匣。生產環境發送則使用另一個經過網域驗證的端點。絕對不要將開發環境指向生產環境的發送端點。
認證。 請求需要在 Authorization 標頭中使用 Bearer Token。Token 的作用域是針對每個專案;沙箱和生產環境通常使用不同的 Token。
網域驗證。 生產環境發送需要事先透過 DNS 記錄(SPF、DKIM、DMARC)驗證寄件網域,Mailtrap 才會將郵件遞送給真實收件人。跳過此步驟會導致郵件遞送靜默失敗或進入垃圾郵件資料夾。
程式碼範例
// 透過 Mailtrap 的 Email API 發送(生產環境)
async function sendEmail(to: string, subject: string, html: string) {
const response = await fetch("https://send.api.mailtrap.io/api/send", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.MAILTRAP_API_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
from: { email: "[email protected]", name: "Your App" },
to: [{ email: to }],
subject,
html,
}),
});
if (!response.ok) {
throw new Error(`Email send failed: ${response.status}`);
}
return response.json();
}
// 同一個呼叫,在非生產環境中路由到沙箱
const MAILTRAP_ENDPOINT = process.env.NODE_ENV === "production"
? "https://send.api.mailtrap.io/api/send"
: `https://sandbox.api.mailtrap.io/api/send/${process.env.MAILTRAP_INBOX_ID}`;
反模式
| 反模式 | 為什麼有問題 | 正確做法 |
|---|---|---|
| 在開發/測試環境使用生產環境發送端點 | 真實的測試郵件會送達真實收件匣,有垃圾郵件投訴和測試資料外洩的風險 | 將非生產環境路由到沙箱端點 |
| 在原始碼中寫死 API Token | 如果提交到版本控制,有憑證外洩的風險 | 從環境變數 / 密碼管理員載入 Token |
| 在網域驗證完成前就開始發送 | 郵件會靜默失敗或進入垃圾郵件 | 在啟用生產環境發送前,先驗證 SPF/DKIM/DMARC 記錄 |
| 發送失敗時沒有重試/錯誤處理 | 靜默的通知失敗(例如使用者永遠收不到密碼重設郵件) | 檢查回應狀態碼、記錄失敗、提供可操作的錯誤訊息 |
最佳實踐
- 將沙箱和生產環境的 Token 放在不同的環境變數中,絕對不要讓一個 Token 跨環境使用
- 在任何涉及電子郵件的生產環境發布前,先驗證寄件網域的 DNS 記錄
- 記錄遞送失敗時,要附上足夠的除錯上下文(收件人、範本、時間戳、回應碼)
- 將電子郵件發送視為可能失敗的網路呼叫:使用 try/catch 包覆,永遠不要假設成功
相關技能
api-and-interface-design、security-and-hardening、ci-cd-and-automation