在現代雲端應用中,自動化發送電子郵件(如:註冊驗證、系統通知、狀態更新)是不可或缺的功能。微軟推出的 Azure Communication Services (ACS) 提供了一個穩定且高度整合的 Email 解決方案。
然而,許多開發者在系統上線、面對批次發送或高並發(High Concurrency)場景時,常會突然撞上一道高牆:ACS email API returned status 429: Too Many Requests。
本篇文章將帶您從零開始了解 ACS Email 的佈署步驟,並分享如何透過三層防禦架構徹底解決 429 超額問題!
🛠️ 第一部分:ACS Email 基礎佈署三步驟
要使用 ACS 發送郵件,我們需要完成以下三個核心步驟:
1. 建立資源與網域
- Azure Managed Domain(預設):適合測試。系統會配發一組
.azurecomm.net結尾的隨機網域。它的限制非常嚴格(5 封/分、10 封/小時),且無法申請提升。 - Custom Domain(自訂網域):生產環境必備。您可以註冊如
notify.yourdomain.com的子網域。- 小提示:建議使用子網域,避免影響學校或企業既有的 MX/SPF 設定。
- 您需要在 DNS 管理員中設定微軟提供的四筆紀錄(包含 TXT 網域驗證、兩筆 CNAME DKIM 驗證、以及 SPF 設定)。
2. 連結 ACS 與 Email 服務
在 Azure Portal 中,將您的 Communication Services 資源與 Email Communication Services 進行連結(Connect domain),讓發信 client 端能正確調用該網域。
3. SDK 整合(以 Go 語言為例)
在程式碼中,我們可以透過 Access Key 或 Managed Identity (MSI) 來初始化 ACS Client,並調用發信 API。當有多位收件人時,ACS 支援將多個 Email 放入 To 欄位陣列中一次送出。
⚡ 第二部分:為什麼會遇到 429 錯誤?
當系統有多個異步任務(例如多個 Goroutines 或背景 Worker)同時觸發發信邏輯時,瞬間發出的 HTTP 請求會遠遠超過 Azure 網域的每分鐘速率上限。
- Managed Domain:上限 5 封/分。
- Custom Domain:預設上限 30 封/分。
一旦超過,ACS 就會毫不留情地回傳 HTTP 429。如果此時程式直接報錯丟棄,就會導致使用者收不到重要通知。
🛡️ 第三部分:完美修復 ACS 429 的「三層防禦機制」
為了確保信件 100% 送達,且系統不會因為並發而崩潰,建議在後端架構中實作以下三層防禦:
發送郵件請求 (多個 Goroutines 並發)
│
▼
┌───────────┐
│ Layer 2 │ ──► Client-side Rate Limiter (主動排隊,例如限制 24 封/分)
└───────────┘
│
▼
┌───────────┐
│ API 發送 │ ──► HTTP POST 到 Azure ACS
└───────────┘
│
├─ [202 Accepted] ──► ✅ 成功送出
│
└─ [429 Too Many Requests]
│
▼
┌───────────┐
│ Layer 1 │ ──► 自動 Retry (解析 Retry-After 標頭,等待後重試)
└───────────┘
│
▼
┌───────────┐
│ Layer 3 │ ──► 擴充根本 Quota (升級 Custom Domain / 調整環境變數)
└───────────┘
💡 Layer 1:客戶端自動重試(Client-side Retry)
當收到 429 錯誤時,不要立刻放棄!ACS 的 Response Header 中會帶有一個 Retry-After 欄位(通常為 60 秒),告知你多久後可以重試。
- 實作邏輯:在發信方法中加入一個最多 3 次的
for迴圈。 - 行為:若遇到 429,解析
Retry-After的秒數,讓執行緒time.Sleep()(或搭配context監聽)後再次重試。如果 3 次都失敗才記 Log 報錯。
💡 Layer 2:客戶端速率限制器(Rate Limiter)
與其等收到 429 才來重試,不如在「出門前」就先排隊。我們可以在記憶體中建立一個 Token Bucket 速率限制器(例如使用 Go 的 golang.org/x/time/rate)。
- 實作邏輯:將速率限制器封裝在 ACS Client 內,每次呼叫
Send()前,都必須先執行limiter.Wait(ctx)。 - 參數彈性化(拒絕 Hardcode):建議將限制速率改為環境變數化(例如
ACS_EMAIL_RATE_PER_MINUTE):- 測試環境(Managed Domain):設為
4(低於上限 5,保留 1 封緩衝)。 - 生產環境(Custom Domain):設為
24(低於上限 30,保留 6 封緩衝)。
- 測試環境(Managed Domain):設為
- 優點:並發的 Goroutine 會自動在本地排隊,不會佔用 HTTP 連線,更不會頻繁去撞 Azure 的 API 牆。
💡 Layer 3:切換自訂網域與申請提升 Quota
如果業務量持續成長,本地排隊隊伍越來越長,這代表您必須提升物理上限了。
- 全面捨棄 Managed Domain,切換至 Custom Domain,將基本盤直接從 5 封/分 擴展至 30 封/分。
- 若 30 封/分 仍不敷使用,可以前往 Azure Portal 提交 Support Ticket,問題類型選擇
Service and subscription limits (quotas),申請將 ACS Email 的發送速率調高(例如調整至 60 或 120 封/分)。 - 此時,由於我們在 Layer 2 將速率做成了環境變數,我們不需要修改任何程式碼、不需要重新打包 Docker Image,只需要更改雲端環境變數(例如將
ACS_EMAIL_RATE_PER_MINUTE改為54),重啟服務即可完美對接新的 Quota!
📝 總結
處理雲端服務的 Rate Limit 是後端工程師的必修課。透過 Layer 2 (本地排隊限制速率) 避免主動違規、Layer 1 (退讓重試) 處理突發流量,再配合 Layer 3 (彈性環境變數與自訂網域) 提升硬體上限,你的系統就能擁有極高韌性,再也不怕被 ACS 的 429 錯誤給擊倒!
希望這篇文章能幫助到正在與 Azure ACS 奮戰的你。歡迎在下方留言分享你們在處理第三方 API 限制時的心得!