Amazon SES 利用時、何も考えずメールを大量送信していると以下のようなエラーが出ることがあります。
Maximum sending rate exceeded
最大送信レートを超過したぞ、というエラーメッセージです。
最大送信レートとは
SESのドキュメントには以下のようにあります。
最大送信レート – Amazon SES が 1 秒あたりにアカウントから受け付ける E メールの最大数。この制限を瞬間的に超えることはできますが、制限を超えた状態が長時間続くことは許可されません。
1秒あたりの送信メール数制限ということですね。これを超えると前述のエラーが発生するわけです。
制限に到達した場合、それ以降のメールは送信されず破棄されてしまいます。
どうやって制限を回避するの?
大きく分けて2つの方法が考えられます。
- Amazon に送信レート制限を引き上げてもらう
送信レート制限は、基本的に SES の利用制限解除時に申請した数値になっています(利用制限解除方法はこちら)
手順は制限解除のときと同じです。「希望する最大送信レート」の数値を引き上げて申請しましょう。
ただしあまりにも大きい数値は蹴られます。わたしは 200 を申請して蹴られました。(90までは上げてもらえました) - アプリケーションで制御する
こちらが現実的になると思います。アプリケーション側で最大送信レート制限に達しないように調整を行います。
ドキュメントには「無作為的に 0~10 分間待機したうえで送信リクエストを再試行するようにアプリケーションをプログラムする必要があります」とあるのみで、具体的なプラクティスは提示されていません。
アプリケーションで制御する
いくつかの実装方法を考えてみました。
エラーをキャッチしたらSleep後にリトライする
ゴリ押し気味ですが、確実性があり簡単な方策。
エラーが発生したら時点で一定時間スリープ後、リトライをかけます。以下は簡単な例。
try { SendEmailResult result = client.sendEmail(request); } catch (AmazonServiceException e) { if ("Maximum sending rate exceeded.".equals(e.getMessage())) { try { Thread.sleep(1000); } catch (InterruptedException e1) { return; } // リトライ処理 } }
エラーを頻発させると Amazon の心象が悪化する気がしなくもないので、送信レート制限分送出した後にも Sleep を入れたほうがいいかもしれません。
キューに送信メッセージを蓄え、一定周期で送出する
送信メッセージを直ちに送出せず、キューに蓄えます。 Timer クラスなどを利用してキューに対してポーリングを行い、送信レート制限分だけ送信メッセージを取り出し、送出します。
デメリットは、オペレーションを行ったユーザが送信エラーを知ることができない点が挙げられます。バッチ処理などなら問題はありませんが。
送信レート制限の上限は、運用を続けていると Amazon 側で徐々に引き上げてくれるようです。上限を確認し、必要であれば Sleep やポーリング周期を調整する必要があるでしょう。