2026年6月1日
2026年6月1日
Postfixの送信レート制限を設定する方法|受信側(anvil)と配送側の2つの仕組み
Postfixのレート制限には、外部から接続してくるクライアントを抑える「受信側(smtpd+anvil)」と、自分が外へ送り出す速さを抑える「配送側(キューマネージャー)」の2つの仕組みがあります。WordPressからの大量送信を抑えたい場合に効くのは、ほとんどの構成で配送側の設定です。この記事を読むと、自分の目的にどちらの設定が効くのかを判断し、実在するパラメーターで制限をかけ、効いているかをログで確認できるようになります。
2つの仕組みの違い
Postfixの中で、メールは大まかに「受け付け」と「配送」の2段階を通ります。
- 受信側:外部のクライアントがSMTPで接続してきたときに、smtpdが応答します。接続数や送信数の数え上げは anvil というサービスが担当し、上限を超えたクライアントには一時エラー(4xx)を返します。スパム送信元や、不正ログインされたアカウントからの大量送信を抑えるのが目的です。
- 配送側:キューに入ったメールを、キューマネージャー(qmgr)が宛先ごとに smtp クライアントへ渡します。ここで同時配送数や配送間隔を調整すると、送信先サーバーやメール配信サービスの受け入れ上限に合わせられます。
WordPressからの送信に受信側の制限が効かない理由
WordPressの wp_mail() は、既定ではPHPの mail() 関数を使い、Postfixの sendmail コマンドにメールを渡します。この経路は smtpd を通らず、pickup というサービスから直接キューに入るため、anvil による制限はかかりません。
SMTPプラグインで同じサーバーの 127.0.0.1:25 に送る構成なら smtpd を通りますが、受信側の制限には除外の設定があり、既定では mynetworks に含まれるクライアント(通常はローカルホストを含む)は数えられません。
つまり、「WordPressから送る量を抑えたい」場合は配送側の設定を、「外部からの不正な大量送信を防ぎたい」場合は受信側の設定を使う、と考えると整理しやすくなります。
設定前に現在の値を確認する
main.cf を変更する前に、現在の設定を保存しておきます。
sudo cp /etc/postfix/main.cf /etc/postfix/main.cf.bak
sudo cp /etc/postfix/master.cf /etc/postfix/master.cf.bak
# 既定値から変更されている設定だけを表示
postconf -n
# 関連パラメーターの既定値
postconf -d anvil_rate_time_unit smtpd_client_connection_count_limit \
smtpd_client_event_limit_exceptions default_destination_concurrency_limit \
default_destination_rate_delay default_destination_recipient_limit
ここで紹介するパラメーターは、2026年10月現在広く使われているPostfix 3系を前提にしています。一部はバージョンによって使えないため、postconf mail_version でバージョンを確認しておいてください。
受信側:anvilで接続元ごとに制限する
受信側の制限は、すべて「1つのクライアント(IPアドレス)あたり、anvil_rate_time_unit の時間内に何回まで」という形で数えます。時間の単位を変えると、すべての *_rate_limit の意味が変わる点に注意してください。
# /etc/postfix/main.cf
# レート計算の時間単位(既定値 60s)
anvil_rate_time_unit = 60s
# 1クライアントあたりの同時接続数の上限: 10本
smtpd_client_connection_count_limit = 10
# 1クライアントあたり、60秒間に新規接続30回まで
smtpd_client_connection_rate_limit = 30
# 1クライアントあたり、60秒間にメッセージ20通まで
smtpd_client_message_rate_limit = 20
# 1クライアントあたり、60秒間に宛先100件まで
smtpd_client_recipient_rate_limit = 100
# 1クライアントあたり、60秒間にAUTHコマンド10回まで(Postfix 3.1以降)
smtpd_client_auth_rate_limit = 10
# 制限を適用しないクライアント(既定は mynetworks)
smtpd_client_event_limit_exceptions = $mynetworks
smtpd_client_connection_rate_limit などの *_rate_limit は、既定値が0(制限なし)です。smtpd_client_connection_count_limit だけは既定で50が入っています。
main.cf では、行の途中に # を書いてもコメントになりません。smtpd_client_message_rate_limit = 20 # 20通 と書くと、# 以降も値の一部として扱われ、数値として解釈できずにエラーになります。コメントを書くなら独立した行にしてください。
値の決め方
値を決める前に、現状の最大値を把握します。anvil は、一定時間ごとに各サービスで観測した最大値をログに出力しています。
# anvil が記録した最大接続レート・最大メッセージレート
grep "postfix/anvil" /var/log/mail.log | grep -E "max (connection|message) rate"
正常な利用者の最大値より余裕のある値を上限にすれば、通常の送信を妨げずに異常な送信だけを止められます。社内の複合機や、別サーバーで動く複数のWordPressサイトなど、正当に大量送信するクライアントがあるなら、そのIPを smtpd_client_event_limit_exceptions に追加します。
サービスごとに値を変える
ポート25(外部サーバーからの受信)と587(認証して送る利用者向け)では、適切な上限が違います。master.cf の -o で、サービスごとに上書きできます。
# /etc/postfix/master.cf の submission サービス(既存の行に -o を追加)
submission inet n - y - - smtpd
-o smtpd_client_message_rate_limit=60
-o smtpd_client_recipient_rate_limit=300
これで、587番ポートだけは「60秒間に60通、宛先300件まで」になります。chroot などの列の値は、環境の既存の行にそろえてください。
配送側:送り出す速さを制限する
配送側では、宛先(既定では受信者のドメイン、relayhost を設定していればそのリレー先)ごとに、同時に何本配送するか、どれだけ間隔をあけるかを調整します。
# /etc/postfix/main.cf
# 同じ宛先への同時配送数の上限(既定値 20)
default_destination_concurrency_limit = 10
# 同じ宛先への配送の間隔: 1秒(=同じ宛先へは1秒に1回まで)
default_destination_rate_delay = 1s
# 1回の配送でまとめる宛先数の上限(既定値 50)
default_destination_recipient_limit = 50
default_ で始まるパラメーターは全トランスポートの既定値です。smtp だけに適用したい場合は、smtp_destination_concurrency_limit、smtp_destination_rate_delay、smtp_destination_recipient_limit のように、トランスポート名を頭に付けた名前で指定します。
rate_delay と recipient_limit の関係
*_destination_rate_delay に0以外を指定すると、同じ宛先への配送は、指定した間隔で1回ずつ行われるようになります。このとき「1回」がメール1通分なのか、宛先1件分なのかは、対応する *_destination_recipient_limit で決まります。
- recipient_limit が2以上:同じドメイン宛ての受信者をまとめて1回で配送するため、1回に複数の宛先が含まれる
- recipient_limit が1:1回の配送が宛先1件になるため、「1秒に宛先1件まで」という制限になる
メール配信サービスの上限が「1秒あたりの宛先数」で決まっている場合は、recipient_limit を1にしないと、想定より多く送ってしまうことがあります。
relayhost経由で送る場合
Amazon SESなどの配信サービスに relayhost で中継している場合、すべてのメールの宛先が同じリレー先になります。そのため、smtp の rate_delay は事実上サーバー全体の送信速度の上限になります。
# /etc/postfix/main.cf(relayhost 経由で送る構成の例)
relayhost = [email-smtp.example.com]:587
# リレー先への配送を1秒に1回、1回あたり宛先1件に(=1秒に宛先1件まで)
smtp_destination_rate_delay = 1s
smtp_destination_recipient_limit = 1
配信サービス側の上限(1秒あたりの送信数や1日の送信数)は、契約やアカウントの状態で変わります。サービスの管理画面で現在の上限を確認し、それより少し低い値になるよう調整してください。
特定の宛先ドメインだけ遅くする
大手のフリーメールなど、短時間に大量に届くと受け入れを一時的に拒否するドメインだけ、配送を遅くしたい場合があります。その場合は、専用のトランスポートを作り、そこにだけ制限をかけます。ここでは relayhost を使わず、相手のMXへ直接配送している構成を前提にします。
master.cf に、smtp と同じプログラムを使う slow というトランスポートを追加します。
# /etc/postfix/master.cf(既存の smtp unix の行と同じ列の値で追加)
slow unix - - - - - smtp
main.cf で、slow 専用の値を指定し、宛先ドメインとの対応表を読み込ませます。
# /etc/postfix/main.cf
transport_maps = hash:/etc/postfix/transport
# slow トランスポートの同時配送数: 2本まで
slow_destination_concurrency_limit = 2
# slow トランスポートの配送間隔: 2秒(同じ宛先へは2秒に1回まで)
slow_destination_rate_delay = 2s
# /etc/postfix/transport(宛先ドメイン → トランスポート)
example.net slow:
対応表を変更したら、postmap でデータベースを作り直してから反映します。
sudo postmap /etc/postfix/transport
sudo postfix check
sudo systemctl reload postfix
slow: のように、コロンの後ろ(ネクストホップ)を空にすると、通常どおり宛先ドメインのMXへ配送されます。
制限が効いているかを確認する
設定を反映したら、ログとキューで動作を確認します。
# 受信側の制限に引っかかったクライアント
grep -i "rate limit exceeded" /var/log/mail.log | tail -20
# キューにたまっているメールの件数
postqueue -p | tail -1
# 宛先ドメインごとの滞留状況(qshape が入っている環境)
sudo qshape deferred | head -20
配送側の制限は、ログに「制限した」とは出ません。postfix/smtp の行の時刻が、指定した間隔で並んでいるかを見て確認します。
注意したいのは、配送側の制限を厳しくしすぎた場合です。送信する速さより新しいメールが入ってくる速さが上回ると、キューはふくらみ続けます。キューにとどまれる期間は maximal_queue_lifetime(既定値5日)で決まっていて、超えたメールは送信者にエラーとして返されます。会員向けの一斉送信などで大量のメールが発生する場合は、WordPress側で送信を分割するか、配信サービス側の上限を引き上げることも合わせて検討してください。
送信者ごとの上限が必要な場合
Postfixの標準機能には、「このメールアドレスは1時間に何通まで」といった送信者単位の上限はありません。複数のサイトで1台のメールサーバーを共有し、サイトごとに上限を分けたい場合は、postfwd のようなポリシーサービスを組み合わせて実現します。まずは標準の受信側・配送側の制限で足りるかを検討し、足りない場合に導入を考えるとよいでしょう。
まとめ
- Postfixのレート制限は、受信側(smtpd+anvil)と配送側(キューマネージャー)の2系統
- WordPressの
mail()経由の送信は smtpd を通らず、ローカルホストは既定で除外されるため、受信側の制限は効かない。送信量を抑えるなら配送側を設定する - 受信側は
smtpd_client_connection_rate_limit・smtpd_client_message_rate_limitなどで、anvil_rate_time_unitあたりの回数を指定する - 配送側は
default_destination_rate_delay・smtp_destination_concurrency_limitなどで間隔と同時数を指定し、*_destination_recipient_limitで1回の範囲が変わる - 特定ドメインだけ遅くするなら、専用トランスポートと
transport_mapsを使う - main.cf の行末コメントは値の一部になる。コメントは独立した行に書き、値と内容を一致させる