【メール入門 第8回】MTAの運用 ― Postfixの構成・キュー・main.cf、オープンリレー対策、ログの読み方、スマートホスト

メールサーバー
スポンサーリンク
スポンサーリンク

「昨日の夕方に送ったメールが、相手に届いていないそうです。調べてもらえますか」

メールサーバーの担当者なら、必ず受ける問い合わせです。答えはログとキューにあります。ただし、読み方を知らないと、大量のログの中で迷子になります。

第8回では、広く使われているMTAのPostfixを例に、構成、設定、オープンリレーを作らないリレー制御、キューとログの読み方、そして送信専用サーバーの組み方を見ていきます。


Postfixの構成

Postfixは、役割ごとに分かれた小さなデーモンの集まりです。常駐するmasterが、必要に応じて各デーモンを起動します。

SMTPの25・587番から届いたメールはsmtpdが、sendmailコマンドで投入されたメールはmaildropキューを経てpickupが受け取り、どちらもcleanupでヘッダーの補完とアドレスの書き換えを受けてincomingキューに入り、qmgrが外部宛てはsmtpへ、メールボックス宛てはlocalへ配送を頼み、失敗したものはdeferredキューで再送を待つことを示す図
  • 入口:外部からSMTPで届いたメールはsmtpdが受け取り、サーバー上のsendmailコマンドで投入されたメールはmaildropキューを経てpickupが拾う
  • 整形:どちらもcleanupでヘッダーの補完(Message-ID・Date等)やアドレスの書き換えを受け、incomingキューに1つのファイルとして置かれる
  • 出口:qmgr(キューマネージャー)が配送の順番を管理し、外部宛てはsmtpに、ローカルのメールボックス宛てはlocal(またはvirtual・lmtp)に配送を頼む。失敗したメールはdeferredキューで再送を待つ

最小の権限で動くプロセスに分けるのは、脆弱性の被害を広げないためです。


キューの種類

キュー入るメール次の動き
maildropsendmail コマンドでローカルから投入されたものpickup が拾って cleanup へ渡す
incomingcleanup が整えた到着直後のメールqmgr が active へ移す
active配送中のメール(数に上限がある)成功で削除、一時失敗で deferred、恒久失敗でバウンス
deferred一時エラーで配送できなかったメール間隔を空けて再試行。期限を過ぎたらバウンス
hold管理者が保留にしたメールpostsuper -H で戻すまで配送しない
maildropからincomingを経てactive(配送中)に入り、成功で削除、恒久失敗でバウンス、一時失敗でdeferredに移って300〜4000秒の間隔で再試行し、5日で期限切れならバウンスすることと、postsuperでどのキューからでもholdに移せることを示す図
  • 再試行の間隔はminimal_backoff_time(既定300秒)からmaximal_backoff_time(既定4000秒)まで延び、maximal_queue_lifetime(既定5日)を過ぎると送信者にエラーメールを返す(第2回)
  • 遅延の通知(delay_warning_time)は既定で無効
  • キューのファイルは直接消さず、この後のコマンドで操作する

一時失敗は消えずに、deferredとactiveを行き来して待つのです。


main.cfの主な設定

パラメーター意味既定値例(送信専用サーバー)
myhostname自分の FQDN。EHLO・Received に使うOS のホスト名app01.example.jp
mydomain自分のドメインmyhostname の先頭の部分を除いたものexample.jp
myoriginローカルで出したメールに付けるドメイン$myhostname$mydomain
mydestination自分が最終配送先になるドメイン$myhostname, localhost.$mydomain, localhost空(ローカル配送しない)
mynetworksリレーを許す「信頼する」接続元自ホストだけ(3.0 以降)127.0.0.0/8 [::1]/128
relayhost外部宛てを渡す次のサーバー(スマートホスト)空(MX へ直接配送)[relay.example.jp]:587
inet_interfaces受け付けるネットワークインターフェースallloopback-only
  • mydestinationにドメインを入れると、そのドメイン宛てをローカルのユーザーとして配送しようとする。Microsoft 365などに本物のメールボックスがあるドメインを入れてしまい、外に出ず「User unknown」になるのは典型的な誤り
  • [ ]で囲んだrelayhostは、MXを引かずにその名前へ直接送る

postconfで設定を確かめる

$ postconf -n                    # 既定値から変えた設定だけを表示(抜粋)
compatibility_level = 3.10
inet_interfaces = loopback-only
mydestination =
myhostname = app01.example.jp
relayhost = [relay.example.jp]:587
$ postconf -d mynetworks_style   # 既定値を表示
mynetworks_style = host
$ postconf mail_version          # 版を確認
mail_version = 3.10.6
$ sudo postconf -e 'relayhost = [relay.example.jp]:587'   # main.cf を書き換える
$ sudo postfix check && sudo systemctl reload postfix      # 検査して反映
  • 設定の確認は、main.cfを目で読むよりpostconf -nが確実。同じパラメーターを2回書いた場合も、実際に効いている値が分かる
  • postconf -Mでmaster.cfのサービスの一覧、postconf -Pでmaster.cfの-oによる上書きを表示する。3.11からは-jでJSONでも出力できる
  • compatibility_levelは、版を上げても古い既定値のまま動かす安全装置。上げると既定値が変わる(例:3.11でsmtp_tls_security_levelの既定がmayになる)ため、ログの警告とpostconf -nを確かめてから上げる

master.cf:submissionとsubmissions

# service   type  private unpriv chroot wakeup maxproc command + args
smtp        inet  n       -      n      -      -       smtpd
submission  inet  n       -      n      -      -       smtpd
  -o syslog_name=postfix/submission
  -o smtpd_tls_security_level=encrypt
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_tls_auth_only=yes
  -o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
submissions inet  n       -      n      -      -       smtpd
  -o syslog_name=postfix/submissions
  -o smtpd_tls_wrappermode=yes
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
  • master.cfはどのポートでどのデーモンを動かすかを決める。-oはそのサービスだけmain.cfの設定を上書きする(抜粋。公式の既定ファイルにはほかの-oもある)
  • submission(587)はSTARTTLSを必須にし、認証したクライアントだけに送信を許す。submissions(465)は接続直後からTLSで話す(smtpd_tls_wrappermode=yes、第4回)
  • 既定のmaster.cfではどちらもコメントになっている。行頭の#を外し、SASL認証(Dovecot等)の設定と合わせて有効にする(Dovecot 側の設定は連載「POP・IMAP入門」第11回(サーバーの構築と運用 前編))。古い版やディストリビューションの既定ファイルでは、465のサービス名がsmtpsのことがある
  • 変更後はpostfix reload。ss -ltnp | grep masterで25・587・465を待ち受けていることを確かめる

リレーの制御:オープンリレーを作らない

オープンリレーとは、誰からのメールでも、どこ宛てでも中継してしまうメールサーバーです。見つかるとすぐにスパムの踏み台にされ、DNSBLに載って(第7回)自社のメールまで届かなくなります。

社内の機器(mynetworks内)と認証済みのクライアントからは中継し、インターネットの誰かからの他ドメイン宛てはRelay access deniedで断り自ドメイン宛ては受け取ることと、mynetworksに0.0.0.0/0やロードバランサーの内部IPを入れるとオープンリレーになることを示す図
  • Postfixが中継(自分が最終配送先でないドメイン宛て)を許す条件はsmtpd_relay_restrictionsで決まる。既定値はpermit_mynetworks, permit_sasl_authenticated, defer_unauth_destination
  • mynetworksの接続元か、SMTP AUTHで認証したクライアントでなければ、担当外のドメイン宛ては断る
  • 危ないのは、mynetworksに「とりあえず」広い範囲を入れることや、接続元がすべてロードバランサーの内部IPに見える構成で、そのIPを入れること

許可は、送信元のIPだけを列挙します。

リレー制御の設定と確認

# /etc/postfix/main.cf(抜粋)
mynetworks = 127.0.0.0/8 [::1]/128 192.0.2.21/32 192.0.2.22/32
smtpd_relay_restrictions = permit_mynetworks, permit_sasl_authenticated,
    reject_unauth_destination

# 許可していない IP から試す:他ドメイン宛ては拒否されるのが正しい
$ nc -C relay.example.jp 25
220 relay.example.jp ESMTP Postfix
EHLO test.example.com
(250- の行は略)
MAIL FROM:<test@example.com>
250 2.1.0 Ok
RCPT TO:<someone@example.org>
554 5.7.1 <someone@example.org>: Relay access denied
  • 既定のdefer_unauth_destinationでは454 4.7.1(一時エラー)、reject_unauth_destinationでは554 5.7.1(恒久エラー)で断る
  • 受信側のログにはNOQUEUE: reject: RCPT from unknown[198.51.100.7]: 554 5.7.1 <someone@example.org>: Relay access denied; …と出る
  • 確認は必ず自分が管理するサーバーに対して行う。他組織のサーバーをオープンリレーか試すのは迷惑行為になる。Windowsからは、第9回のPowerShellの方法で同じ確認ができる

キューの操作

コマンド動作使いどころ
postqueue -p(mailq)キューの一覧と、遅延の理由を表示まず状況を見る
postqueue -fキューのメールをすべて今すぐ再送相手の復旧後
postqueue -i キューID指定の1通を今すぐ再送1通だけ試す
postsuper -d キューID指定の1通を削除(-d ALL deferred で deferred を全部削除)誤送信・スパムの滞留
postsuper -h キューID/-H保留にする/保留を解く調べる間だけ止める
postcat -q キューIDキューのファイルの中身(エンベロープ・ヘッダー・本文)を表示送信者・宛先・内容の確認
$ postqueue -p
-Queue ID-  --Size-- ----Arrival Time---- -Sender/Recipient-------
A3D5F20C41      2210 Sat Sep 26 09:02:44  alert@example.jp
(connect to mx.example.org[203.0.113.25]:25: Connection timed out)
                                         user@example.org

-- 2 Kbytes in 1 Request.

キューIDの直後の*は配送中(active)、!は保留中(hold)を表します。括弧の中が最後の失敗の理由です。postsuper -d ALLはキューのメールをすべて消すため、スパムの滞留の後始末などを除いて使いません。


ログの読み方① キューIDで1通を追う

冒頭の「昨日送ったメールが届いていない」を調べる方法です。

$ grep 8C1E0A1B2F /var/log/maillog       # RHEL 系(Debian 系は /var/log/mail.log)
Sep 26 10:15:01 relay postfix/smtpd[2345]: 8C1E0A1B2F: client=app01.example.jp[192.0.2.21]
Sep 26 10:15:01 relay postfix/cleanup[2346]: 8C1E0A1B2F: message-id=<20260926011501.4F2A@app01.example.jp>
Sep 26 10:15:01 relay postfix/qmgr[1101]: 8C1E0A1B2F: from=<alert@example.jp>, size=1532, nrcpt=1 (queue active)
Sep 26 10:15:02 relay postfix/smtp[2347]: 8C1E0A1B2F: to=<user@example.com>, relay=mx.example.com[198.51.100.25]:25, delay=1.2, delays=0.05/0.01/0.62/0.52, tls=may, dsn=2.0.0, status=sent (250 2.0.0 Ok: queued as 4ZbQ1x2Kp3z9)
Sep 26 10:15:02 relay postfix/qmgr[1101]: 8C1E0A1B2F: removed
$ journalctl --facility=mail --since today | grep 8C1E0A1B2F    # journal だけの環境
同じキューID 8C1E0A1B2Fの行が、smtpdがapp01から受け取る、cleanupがMessage-IDを記録、qmgrが送信者と宛先の数を記録、smtpがmx.example.comへsent、qmgrがキューから削除の順に並び、queued asの後ろが相手側のキューIDであることを示す図
  • Postfixは1通ごとにキューIDを振り、受け取りから削除まで同じIDでログに出す。キューIDでgrepすれば1通の一生が分かる
  • 行の順:smtpd(接続元)→ cleanup(Message-ID)→ qmgr(エンベロープの送信者・宛先の数)→ smtp(配送の結果)→ qmgr(removed)。from・toはエンベロープの値(第3回)
  • queued asの後ろは相手側のキューID。相手の管理者に伝えれば、その先を追ってもらえる。tls=mayは3.11以降で出るTLSの使われ方の表示
  • ログの場所:RHEL系は/var/log/maillog、Debian・Ubuntu系は/var/log/mail.log。rsyslogを入れない環境(Debian 12以降の既定など)ではjournalにだけ残る(連載「syslog入門」)

Message-IDしか分からないときは、まずMessage-IDでgrepしてキューIDを見つけ、次にキューIDでgrepします。


ログの読み方② statusの読み方

表示意味次に確認すること
status=sent相手が 250 で受け取った届かないなら相手側(迷惑メール判定・転送)を調べる
status=deferred一時的な失敗。キューに残り再送する括弧内の理由(接続できない・4xx の応答)
status=bounced恒久的な失敗。送信者にエラーメールを返す括弧内の相手の応答(5xx と拡張ステータスコード)
status=expired, returned to sender再送を続けたが期限(既定5日)が切れたそれまでの deferred の理由をさかのぼる
NOQUEUE: reject:受信側(smtpd)が受け取りを拒否した拒否の理由と接続元・from・to
delays=a/b/c/da:キューマネージャーに渡るまで(受け取りを含む)、b:キューマネージャーの中での待ち、c:接続の確立(DNS・EHLO・TLS を含む)、d:メッセージの送信どの段階で時間がかかったか
… to=<nosuch@example.com>, relay=mx.example.com[198.51.100.25]:25, …, dsn=5.1.1, status=bounced
  (host mx.example.com[198.51.100.25] said: 550 5.1.1 <nosuch@example.com>: Recipient address rejected: User unknown (in reply to RCPT TO command))
… to=<user@example.org>, relay=none, delay=300, …, dsn=4.4.1, status=deferred
  (connect to mx.example.org[203.0.113.25]:25: Connection timed out)

status=sentは「相手が受け取った」までで、「受信箱に入った」ではありません。sentなのに届かないなら、相手側の迷惑メール判定や転送を疑います。

(in reply to RCPT TO command)は、相手がどのコマンドに対して断ったかを示します。RCPT TOなら宛先の問題、end of DATA commandなら内容の問題(迷惑メール判定・DMARCの不合格など)であることが多いです(第11回)。


TLSの設定

# 受信側(smtpd)
smtpd_tls_chain_files = /etc/postfix/tls/mail.example.jp.pem   # 鍵→証明書→中間証明書の順
smtpd_tls_security_level = may          # 公開の25番では may(必須にしない)
smtpd_tls_auth_only = yes               # 暗号化の前は AUTH を出さない
smtpd_tls_received_header = yes         # Received に TLS の情報を書く
smtpd_tls_loglevel = 1

# 送信側(smtp)
smtp_tls_security_level = may           # 3.11 以降(compatibility_level 3.11)は既定で may
smtp_tls_loglevel = 1
smtp_tls_policy_maps = lmdb:/etc/postfix/tls_policy   # 宛先ごとに encrypt・secure 等を指定
  • smtp_tls_security_level:none(使わない)/may(日和見的TLS)/encrypt(暗号化は必須、証明書は検証しない)/dane(DNSSECのTLSAに従って検証、無ければmay)/verify・secure(証明書と名前を検証)
  • インターネットへの配送はmay(またはdane)を既定にする。encrypt以上を全体の既定にすると、TLS非対応の相手に届かなくなる。リレー先や取引先など決まった相手だけ、smtp_tls_policy_mapsでencrypt・secureにする
  • ログにはTrusted TLS connection established to …: TLSv1.3 with cipher …のように、相手の証明書の信頼の程度(Anonymous・Untrusted・Trusted・Verified)が出る。MTA-STS・DANEは第4回、証明書の用意は連載「証明書入門」で扱っている

送信専用サーバーとスマートホスト

アプリケーションサーバーや監視サーバーのように、メールを送るだけのサーバーでは、Postfixを送信専用(null client)にします。

アプリケーションサーバーや監視サーバーを受けない(loopback-only)・ローカル配送しない(mydestination空)送信専用サーバーにし、587番(TLS+AUTH)か25番で社内リレーやSES等のスマートホストに渡し、SPF・DKIM・PTR・外向き25番はスマートホストだけで整えれば、台数が増えても外から見える送信元は1つのままであることを示す図
  • 外からのメールを受け取らないようinet_interfaces = loopback-only、ローカル配送をしないようmydestinationを空にし、外部宛てはすべてrelayhostのスマートホスト(社内のリレーサーバーやクラウドの送信サービス)に渡す
  • 各サーバーはMXを引かず、外向きの25番も要らなくなる。SPF・DKIM・逆引きといった外向けの整備を、スマートホストに集約できる
  • スマートホストが認証を求める場合は、SASLのクライアント設定(smtp_sasl_auth_enable・smtp_sasl_password_maps)でIDとパスワードを渡し、必ずTLSと組み合わせる

台数が増えても、外から見える送信元は1つのままです。

Microsoft 365・SESへのリレー設定の例

# Amazon SES:587番の STARTTLS+SMTP 認証(AWS のドキュメントの手順に準拠)
relayhost = [email-smtp.ap-northeast-1.amazonaws.com]:587
smtp_sasl_auth_enable = yes
smtp_sasl_security_options = noanonymous
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_tls_security_level = secure
# /etc/postfix/sasl_passwd(chmod 600 にしてから postmap hash:/etc/postfix/sasl_passwd)
[email-smtp.ap-northeast-1.amazonaws.com]:587 SMTPユーザー名:SMTPパスワード

# Microsoft 365 の SMTP リレー:受信コネクターで IP か証明書を認証(パスワード不要)
relayhost = [example-jp.mail.protection.outlook.com]:25
smtp_tls_security_level = encrypt
  • SESのSMTPの認証情報は、IAMのアクセスキーとは別物。リージョンのSMTPエンドポイントを使い、送信元の検証とサンドボックスの解除が要る(第10回、連載「クラウド入門」第14回)。Berkeley DBを外したディストリビューションでは、hash:の代わりにlmdb:等を使う(postconf -mで確認)
  • Microsoft 365へのリレーは、受信コネクター(固定のパブリックIP、または受け入れ済みドメインを含む証明書で認証)を作り、MXのエンドポイントへ25番で送る。送信元は受け入れ済みドメインのアドレスにし、SPFに送信元IPを加える。証明書で認証する場合は、smtp_tls_chain_filesでクライアント証明書を送る
  • smtp.office365.com:587のSMTP AUTHは、Basic認証が2026年12月末から既定で無効になる(第4回)。Postfixは標準ではOAuth 2.0(XOAUTH2)で認証できないため、コネクター方式やSES等を選ぶ(第10回)

WindowsでのSMTPとPostfixの現行版

項目状況(2026年9月)対応
IIS の SMTP サーバー(IIS 6 由来の機能)Windows Server 2025 で削除。Windows Server 2022 が最後の版新しく使わない。既存は移行を計画する
IIS SMTP から Microsoft 365 へのリレーMicrosoft はサポート対象外としているExchange Server、Linux の Postfix、クラウドの送信サービスへ移す
Windows からのテスト送信Send-MailMessage は非推奨PowerShell の TcpClient で確かめる(第9回)
Postfix の現行版3.11.7(2026年9月7日)。更新の対象は 3.8〜3.11postfix.org の告知で確認する
ディストリビューションの版例:Ubuntu 26.04 は 3.10.6postconf mail_version。修正はパッケージの更新で入る

2026年9月の3.11.7と各版の更新には、遠隔からのサービス停止やSMTPスマグリング(改行の扱いの違いを突いてメールを紛れ込ませる攻撃)につながる不具合の修正が含まれます。MTAはインターネットに直接さらされるため、ディストリビューションのセキュリティ更新を定期的に当て、更新の対象から外れた版(3.7以前)を使い続けないようにします。


考えてみよう

  1. 社内のリレーサーバーでpostconf -nを実行し、mynetworksに入っている範囲をすべて説明できますか。不要に広い範囲はありませんか。
  2. 「昨日の夕方に送ったメールが届いていない」と言われました。Message-IDしか分からない場合、どのコマンドの順でログを追いますか。
  3. アプリケーションサーバー20台が、それぞれ直接インターネットへメールを送っています。送信専用+スマートホストの構成に変えると、何が楽になり、何に注意が要りますか。

ヒント:この記事のpostconf、リレーの確認、キューIDでログを追う方法、送信専用サーバーの図が答えにつながります。


まとめ

  • Postfixは役割ごとのデーモンの集まり。入口はsmtpdとpickup、出口はsmtpとlocal
  • 一時失敗はdeferredで再送を待ち、既定5日で期限切れ。キューはpostqueue・postsuperで操作する
  • 設定の確認はpostconf -n。mydestinationに本物のメールボックスがあるドメインを入れない
  • 中継はmynetworksかSMTP AUTHの相手にだけ許す。外から試してRelay access deniedを確かめる
  • ログはキューIDでgrepして1通を追う。status=sentは「相手が受け取った」まで
  • 送るだけのサーバーは送信専用+スマートホストにし、外向けの整備を集約する
  • MTAはインターネットにさらされる。セキュリティ更新を定期的に

次回は、MTAの外側から、dig・nc・openssl・PowerShellでメールの経路を調べる方法を見ていきます。


連載「メール入門」全12回

  1. メールが届くまで
  2. SMTPのやり取り
  3. メッセージの構造
  4. ポートと暗号化・認証
  5. 送信ドメイン認証 前編
  6. 送信ドメイン認証 後編
  7. 迷惑メール対策と配信
  8. MTAの運用(この記事)
  9. コマンドで調べる
  10. クラウドと現代のメール
  11. メールのトラブルシュート
  12. メールの設計演習

コメント

タイトルとURLをコピーしました