Mailtrap 郵件整合
用於將交易郵件發送功能整合至應用程式的模式,透過 Mailtrap 的 Email API 與 Sandbox,涵蓋身分驗證、環境分離以及常見的投遞問題。
何時啟用
- 實作「寄送郵件」功能(註冊確認、密碼重設、通知、收據)
- 偵錯開發/測試環境中郵件未送達的問題
- 設定專案的第一個郵件發送整合
- 審查直接呼叫郵件 API 但未使用沙箱隔離的程式碼
核心概念
沙箱與正式環境分離。 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: "您的應用程式" },
to: [{ email: to }],
subject,
html,
}),
});
if (!response.ok) {
throw new Error(`郵件發送失敗:${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