2026年5月17日

2026年5月17日

Postfix のパフォーマンスチューニング|キューとログで詰まりを見つけて設定する

メールサーバーが遅いときに、いきなり数値を大きくするのは逆効果になりがちです。Postfix は既定値でも多くの環境で十分に動くように作られており、遅さの多くは 受信側のプロセス不足、相手先サーバーの受け入れ制限、DNS の遅さ、届かない宛先への再送 のどれかが原因です。

この記事では、まず詰まっている場所を測り、その場所に合った設定だけを変える手順を説明します。パラメーター名と既定値は Postfix 3.10(Debian 13 のパッケージ)の postconf -d と、公式マニュアル(postconf(5)、TUNING_README)で確認したものです(2026年11月時点)。

手順 1: 今の設定と既定値を確かめる

# Postfix のバージョン
postconf mail_version

# 既定値から変えている設定だけを表示
postconf -n

# 個別の値(-d を付けると既定値)
postconf default_process_limit default_destination_concurrency_limit
postconf -d default_process_limit default_destination_concurrency_limit

postconf は存在しないパラメーター名を指定すると unknown parameter と警告します。ネットの記事からコピーした設定は、反映する前にこのコマンドで名前が正しいか確かめます。

手順 2: どこで詰まっているかを測る

キューの量を見る

# キューにあるメールの一覧(最後の行に件数と合計サイズ)
postqueue -p | tail -n 1

# キュー別・宛先ドメイン別・滞留時間別の件数
qshape active
qshape deferred
qshape incoming

qshape は Postfix に付いている Perl スクリプトです。Debian・Ubuntu では postfix パッケージに、RHEL 系では postfix-perl-scripts パッケージに含まれます。

多いキュー 意味 主な原因
incoming 受け取ったが配送の順番待ちに入れていない ディスクが遅い、キューマネージャーが追いつかない
active 配送の順番待ち・配送中 相手先への接続が遅い、同時接続数の不足、相手先の受け入れ制限
deferred 一度失敗して再送待ち 存在しないドメイン・応答しないサーバー宛て、相手先からの拒否・一時エラー

deferred に特定のドメインが大量にたまっている場合は、性能の問題ではなく配送できない宛先の問題です。理由はログで確かめます。

ログの delays= を読む

配送ごとのログ行に、どの段階で時間がかかったかが記録されます。

postfix/smtp[12345]: 4A1B2C3D4E: to=<user@example.net>, relay=mx.example.net[192.0.2.10]:25, delay=3.2, delays=0.05/0.01/2.9/0.24, dsn=2.0.0, status=sent (250 2.0.0 OK)

delays=a/b/c/d の意味は次のとおりです(postconf(5) の説明による)。

値 意味 大きいときに疑うこと
a 到着してから配送待ちの列(active キュー)に入るまで 受信の処理が重い、キューマネージャーが詰まっている
b 配送待ちの列に入ってから接続を始めるまで 配送プロセス数・宛先ごとの同時接続数が足りない
c 接続の準備(DNS 検索、TCP 接続、EHLO、STARTTLS) DNS が遅い、相手先の応答が遅い、TLS の確立に時間がかかる
d 本文の送信 回線が遅い、メールが大きい、相手先の受信が遅い

ログの場所は、Debian・Ubuntu では /var/log/mail.log(rsyslog が入っていない環境では journalctl -u 'postfix*')、RHEL 系では /var/log/maillog です。

# 接続準備(c)に5秒以上かかった配送を探す
grep -E 'delays=[0-9.]+/[0-9.]+/([5-9]|[1-9][0-9]+)(\.[0-9]+)?/' /var/log/mail.log | tail

# プロセス数の上限に達した記録
grep 'has reached its process limit' /var/log/mail.log | tail

手順 3: 受信側(smtpd)の設定

プロセス数

同時に動く smtpd などのプロセス数の上限は、master.cf の各行の maxproc 欄で決まります。欄が - なら default_process_limit(既定 100)が使われます。

上限に達すると、ログに service "smtp" (25) has reached its process limit のような警告が出て、新しい接続は空きを待ちます。この警告が出ていて、メモリーに余裕がある場合に限り上限を上げます。

# 全サービスの既定の上限を 150 にする例
postconf -e 'default_process_limit = 150'

上限を上げるとメモリーの使用量も増えます。スパム送信元からの接続でプロセスが埋まっている場合は、上限を上げるより postscreen で入口をふさぐほうが効きます(master.cf にコメントアウトされた雛形があります)。

クライアントごとの制限(anvil)

パラメーター 既定値 内容
smtpd_client_connection_count_limit 50 1つのクライアントが同時に張れる接続数
smtpd_client_connection_rate_limit 0(無効) 1つのクライアントの単位時間あたりの接続回数
smtpd_client_message_rate_limit 0(無効) 1つのクライアントの単位時間あたりの送信メール数
smtpd_client_recipient_rate_limit 0(無効) 1つのクライアントの単位時間あたりの宛先数
anvil_rate_time_unit 60s 上の rate 系の単位時間

これらは乱用を防ぐための制限で、速くするための設定ではありません。公式マニュアルも、正当なメールの流量調整に使わないよう注意しています。mynetworks に含まれるクライアントは、既定で smtpd_client_event_limit_exceptions により制限の対象外です。

# 例: 外部の1クライアントあたり、1分に送れる宛先数を 200 までにする
postconf -e 'smtpd_client_recipient_rate_limit = 200'

手順 4: 送信側(smtp クライアント)の設定

宛先ごとの同時接続数と送信間隔

パラメーター 既定値 内容
default_destination_concurrency_limit 20 1つの宛先(ドメイン)へ同時に配送する数
default_destination_rate_delay 0s(無効) 同じ宛先ドメインへの配送の間隔。0 以外にすると、その宛先へは間を空けて1件ずつ配送する
default_destination_recipient_limit 50 1回の配送でまとめて送る宛先数

大手のメールサービスは、短時間に大量のメールが来ると一時エラー(4xx)を返して受け入れを遅らせます。この場合、同時接続数を増やすと拒否が増えるだけです。拒否される宛先だけ、同時接続数を下げて間隔を空けます。

宛先によって設定を分けるには、配送方式(トランスポート)を複製します。

(1) master.cf にトランスポートを追加する。 既存の smtp unix ... smtp の行を複製し、名前を slow に変えます。欄の値は元の行と同じにします。

# /etc/postfix/master.cf(既存の smtp unix の行の下に追加。欄は元の行に合わせる)
slow      unix  -       -       y       -       -       smtp

(2) slow で送る宛先を決める。 宛先ドメインとトランスポート名を書きます。

# /etc/postfix/transport
example.jp    slow:

(3) slow だけに効く設定を入れて反映する。

postconf -e 'transport_maps = hash:/etc/postfix/transport'
postconf -e 'slow_destination_concurrency_limit = 2'
postconf -e 'slow_destination_rate_delay = 1s'
postconf -e 'slow_destination_concurrency_failed_cohort_limit = 10'
postmap /etc/postfix/transport
postfix check && postfix reload

パラメーター名の先頭を default_ から master.cf のトランスポート名(ここでは slow)に変えると、そのトランスポートだけに効きます。送信間隔を設定するときは、公式マニュアルの注意に従って _destination_concurrency_failed_cohort_limit を 10 以上にします。小さいままだと、一時的な失敗が続いただけでその宛先が応答しないものとして扱われ、配送が止まることがあります。

transport_maps をすでに使っている場合は、既存のファイルに行を足します。

再送の間隔とキューの保存期間

届かない宛先への再送が多いと、それだけで配送プロセスと接続が使われます。

パラメーター 既定値 内容
queue_run_delay 300s deferred キューを調べる間隔
minimal_backoff_time 300s 再送までの最短の待ち時間
maximal_backoff_time 4000s 再送までの最長の待ち時間
maximal_queue_lifetime 5d 配送をあきらめて差出人に返すまでの期間
bounce_queue_lifetime 5d エラー通知メール自体をあきらめるまでの期間

送信者が自分のシステムだけ(フォームの通知など)で、5日も待つ必要がない場合は、保存期間を短くすると deferred キューがたまりにくくなります。

postconf -e 'maximal_queue_lifetime = 2d'
postconf -e 'bounce_queue_lifetime = 1d'

再送の間隔を短くすると、相手先にも自分のサーバーにも負荷が増えます。公式マニュアル(TUNING_README)も、再送の頻度を上げると配送全体が遅くなることがあると注意しています。

手順 5: TLS と DNS

TLS セッションキャッシュ

TLS の確立には時間がかかります。セッションキャッシュを使うと、同じ相手への再接続で確立が速くなります。Debian・Ubuntu の既定の main.cf には送信側の設定がすでに入っています。

postconf smtp_tls_session_cache_database
# 空なら設定する
postconf -e 'smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache'

使えるデータベース形式(btree、lmdb など)は postconf -m で確かめます。

DNS

ログの delays= の c が大きい場合や、受信ログで相手が unknown と記録される場合は、DNS の応答が遅いか失敗しています。公式マニュアル(TUNING_README)は、サーバーにキャッシュする DNS サーバー(ローカルのリゾルバー)を置くことを勧めています。/etc/resolv.conf が指している DNS サーバーに dig で問い合わせ、応答時間を確かめます。

dig example.net MX | grep 'Query time'

手順 6: 反映と確認

# 設定ファイルの誤りを確かめる
postfix check

# 設定を読み直す(master.cf の変更も反映される)
postfix reload

# 変えた設定を確かめる
postconf -n

postfix reload を実行すると、_destination_rate_delay の待ち時間の状態はリセットされます。変更後は、手順 2 の qshape とログの delays= をもう一度見て、詰まっていた段階が改善したかを確かめます。改善しない設定は元に戻します。

まとめ

  • 先に qshape とログの delays=a/b/c/d で、詰まっている場所(受信、配送待ち、接続準備、送信)を特定します。
  • プロセス数は「process limit」の警告が出ているときだけ上げます。スパムで埋まっているなら postscreen を使います。
  • smtpd_client_* の制限は乱用対策です。宛先数の制限の正しい名前は smtpd_client_recipient_rate_limit です。
  • 相手先に拒否される宛先は、トランスポートを分けて同時接続数を下げ、送信間隔を空けます。
  • deferred キューが多いときは、再送の設定と保存期間、届かない宛先の整理を先に行います。

関連記事

お気軽にご相談ください

お見積りへ お問い合わせへ
▲