はじめに

LPIC202 のトピック 211「電子メールサービス」より、電子メールサーバの使用についての学習メモをまとめる。
シラバスは公式サイトを参照。

メール配送の用語と全体像(MTA / MDA / MRA / MUA)は211.3 メールボックスアクセスの管理のメモで整理した。本稿はその「送る・運ぶ」を担う MTA(Postfix / sendmail) が主役になる。

そもそも Postfix と sendmail とは(MTA の基礎)

両方とも MTA(Mail Transfer Agent=メール転送エージェント)。配送フローでいう「送る・運ぶ」を担う中核。

[送信MUA] --SMTP--> [MTA: Postfix/sendmail] --> [MDA] --> メールボックス
                          ↑ここ                          ↓
[受信MUA] <--POP3/IMAP-- [MRA: Dovecot] <----------------┘
  • sendmail
    • 1980年代に作られた Unix 標準の元祖 MTA
    • 高機能だが設定(sendmail.cf、m4 マクロ生成)が難解
      • その反省から Postfix / qmail がより安全な代替として生まれた。
  • LPIC202 では Postfix が主役、sendmail は比較対象という立ち位置。
  • sendmail コマンドは事実上の標準インターフェース
    • mail コマンドや cron、Web アプリは /usr/sbin/sendmail を叩いて送信する。
    • そのため Postfix なども sendmail 互換コマンドを備えており、中身が Postfix でも sendmail コマンドが使える。
  • Debian系の標準MTAでeximというものがあるが、こちらは名前だけ知っているというぐらいでOK。

設定ファイルの全体像(main.cf / master.cf とディレクトリ)

混同しやすい最重要ポイント。ディレクトリ(どの MTA か)ファイルの役割(パラメータか/サービスか) の2軸で押さえる。

ディレクトリ(Postfix と sendmail で別)

MTA設定ディレクトリ主なファイル
Postfix/etc/postfix/main.cf / master.cf
sendmail/etc/mail/sendmail.cf / access / aliases

main.cf と master.cf の役割分担

役割main.cfmaster.cf
日本語名主な設定ファイルデーモン(サービス)設定ファイル
何を書くパラメータkey = valueサービス定義(1行=1プロセス)
答える問いどう動くか」何を動かすか」
具体例myhostname / smtpd_use_tls / disable_vrfy_commandsmtp(25) / smtps(465) / submission(587)
編集頻度高い(設定の大半)低い(サービス追加・有効化時)
名前の由来main=主たる設定master=master デーモンが起動する子サービス一覧

判別のコツは xxx = 値 なら main.cf、サービス名の行なら master.cf」。Postfix は master という親デーモンが smtpd や qmgr といった子プロセスを起動・管理しており、その名簿が master.cf。

main.cf の書式

# これはコメント行(# 始まり)
myhostname = mail.example.com          # パラメータ = 値

mydestination = $myhostname,           # 行末で続けて、
    localhost.$mydomain,               # 空白始まりの行は前行の継続
    localhost

myorigin = $mydomain                   # 他の項目は $名前 で参照

書式ルールは4つ。

ルール内容
代入パラメータ = 値(区切りは =: ではない)
コメント# 始まり(; はコメントではない)
参照$名前 で他項目の値を展開(! ではない)
継続行空白(スペース/タブ)始まりは前行の続き(1項目を複数行で書ける)

mydomain を1か所定義して myorigin = $mydomain のように使い回せるため、変更に強い(DRY)。長いリスト系(mydestinationmynetworks・各種 restrictions)は継続行で読みやすく書ける。

main.cf の主要パラメータ

試験で問われるのは大きく (a) 自サーバの識別・受信系(my 接頭辞が中心)(b) リレー(中継)制御系 の2グループ。「ホスト名とドメイン名の取り違え」「リレー許可の”軸”の取り違え」が定番。

識別・受信系(my* ファミリー)

設定項目意味設定例
myhostname自サーバの FQDN(ホスト名)mail.example.com
mydomain自サーバの ドメイン名example.com
myorigin送信メールの 差出人 @ 以降を補完$mydomain
mydestination自分宛として受信するドメイン一覧$myhostname, localhost.$mydomain
inet_interfaces待ち受けるインターフェースall / localhost

リレー制御系

中継(リレー)の可否は 「誰が/どこ宛なら/どこへどう」 の3軸で決まる。名前が似ていて取り違えやすい。

設定項目中継の軸意味設定例
mynetworks誰が(送信元IP)中継を許可する信頼ネットワーク127.0.0.0/8, 192.168.0.0/24
relay_domainsどこ宛なら(宛先ドメイン)中継を引き受ける宛先ドメインexample.com, example.org
relayhost(送り先)全送信を丸投げする上位 SMTP[smtp.isp.com]
transport_mapsどこへどう(経路表)宛先ごとの中継方式・中継先を引く変換表の場所hash:/etc/postfix/transport
  • mynetworks(送信元IPで許可)と relay_domains(宛先ドメインで許可)は中継を許す軸が別。どちらかを満たせば中継する。
  • relay_domains(受ける宛先の許可)と relayhost(自分が送り出す先)は向きが逆relay_host / relaydomain という項目名は存在しないrelayhost_ なし)。
  • transport_maps の値はテーブルの場所hash:/etc/postfix/transport)。中身は別ファイルに 宛先 transport:nexthop(例 example.com smtp:[mail.example.com])と書き、postmap でDB化して反映する。smtp/relay はテーブル内側の transport 種別であって、パラメータの値ではない。

配送先(home_mailbox と mbox / Maildir)

「届いたメールを どこに置くか」も main.cf で制御する。配送先は3系統。

設定配送先形式
(無指定=既定)/var/spool/mail/ユーザ名(システム共通スプール)mbox
home_mailbox$HOME/<値>(各ユーザのホーム配下)値の末尾 / で Maildir、無しで mbox
mailbox_command外部コマンドに委譲(procmail 等)コマンド次第
home_mailbox = Maildir/        # ~/Maildir/ に Maildir 形式で配送(末尾スラッシュが要)
# home_mailbox = Mailbox       # ~/Mailbox に mbox 形式で配送(スラッシュ無し)
  • 末尾スラッシュの有無で保存形式が変わる/ あり=Maildir、無し=mbox)。これは mail_spool_directory でも共通の流儀。
  • home_maildir という項目は存在しない。Maildir 化は “home_mailboxMaildir/ を渡す” であって専用項目はない(定番のひっかけ)。
  • mbox(1ファイルに連結・破損に弱い)と Maildir(1メール1ファイル・ロック不要で堅牢)の特徴は211.3 のメモで整理した。

ここで決めた保存形式・場所は、読み出す側の Dovecot(211.3)の mail_location(例 maildir:~/Maildir)と一致していないと噛み合わない。Postfix が home_mailbox = Maildir/~/Maildir に置き、Dovecot が同じ ~/Maildir を読む、という対応で1セットになる。

Postfix のコマンド体系

役割で3系統に分かれる。postfixctl のような 存在しないコマンド名が定番の罠。

コマンド役割主な使い方
postfixデーモンの 制御start / stop / abort / reload / flush / check / status
postconf設定の 表示・編集postconf -n(変更分)/ -d(既定値)/ -e 'k=v'(編集)
postqueue / postsuperキュー操作postqueue -p/-f / postsuper -d

postfix サブコマンド

サブコマンド動作
postfix start起動
postfix stop穏便に停止(実行中処理の完了を待つ)
postfix abort即座に強制停止(待たずに落とす)
postfix reload停止せず 設定だけ再読込
postfix flushキューを再送(停止ではない)
postfix check設定・環境の 不備をチェック(問題なければ無言)
postfix status稼働状態表示
  • 停止は stop(穏便)と abort(強制)の2つflush は止めずにキュー再送。
  • postconf(設定内容を表示)と postfix check(不備を検出)は別物。前者は値を出し、後者は問題がなければ何も出さない。reloadpostfix の役目で、postconf reload は存在しない。

メールキューの操作(表示・再送・削除 × sendmail/Postfix)

「やりたいこと」と「どの MTA か」の2軸で整理する。mailq だけは両対応(互換インターフェース)。

やりたいことsendmail 流Postfix 流
表示mailq / sendmail -bpmailq / postqueue -p
再送(flush)sendmail -qpostqueue -f / postfix flush
削除rm -f /var/spool/mqueue/*postsuper -d <ID> / postsuper -d ALL
  • キューの場所: sendmail=/var/spool/mqueue、Postfix=/var/spool/postfix
  • sendmail の -b動作モード指定フラグ。-bp=print queue(表示)、-bd=daemon、-bi=alias DB 初期化(=newaliases)、-bt=アドレステスト。
  • 表示は p-bp / postqueue -p)、再送は q / f・flush、削除は postsuper -d、で覚える。

/etc/aliases とメール転送

/etc/aliases の書式(右辺4種)

書式は 別名: 配送先[, 配送先...]。右辺(配送先)に書けるものが4種類あり、これを区別できるかが問われる。

右辺の書き方意味
ユーザ名 / アドレスそのユーザ・宛先へ 転送admin: test / admin: foo@example.com
絶対パス(そのまま)ファイルに追記admin: /root/admin
|コマンドプログラムを実行し標準入力へ渡すadmin: |/usr/local/bin/example
:include:パスファイルを 配送先リストとして読み込むmailinglist: :include:/etc/mail/userlist
  • \| の有無で意味が真逆: admin: /path はファイルに書き出し、admin: \|/path はプログラム実行。
  • :include:前後にコロンが必須(include:include は誤り)。
  • 複数ユーザへの配送はカンマ区切り(admin: test,example)。

反映コマンド

/etc/aliases はテキストだが、MTA が実際に読むのは バイナリ DB /etc/aliases.db。編集後は必ず再構築する。再構築コマンドは2つ。

newaliases               # sendmail 由来の互換コマンド(引数なし。= sendmail -bi)
postalias /etc/aliases   # Postfix ネイティブ版。対象ファイルを引数で明示(= newaliases 相当)
  • どちらも /etc/aliases/etc/aliases.db を再構築する。cmdrill lpic202.sm.5.11(「エイリアスDBを更新するコマンドを2つ」)の正解がこの2つ。
  • aliases 専用が postaliasnewaliases、それ以外の lookup テーブル(virtual / access / transport / canonical 等)は後述の postmappostqueue(キュー)・postconf(設定)は対象違いのダミー。
  • 「aliases を編集したのに効かない → 再構築忘れ」が定番トラブル。

~/.forward(一般ユーザの転送)

一般ユーザが 自分宛メールを転送する設定は、ホームディレクトリの ~/.forward

/etc/aliases~/.forward
編集する人管理者(root一般ユーザ本人
対象範囲システム全体自分宛のみ
左辺(別名)必要書かない(配送先だけ列挙)
反映newaliases が必要不要(配送のたび読まれる)
右辺の書式共通(ユーザ / アドレス / |cmd / /file / :include:共通

~/.forward は所有者が本人で、他者書き込み可(world-writable)だと無視される(セキュリティ上の仕様)。

canonical_maps(アドレス書き換え)

送信者・受信者のアドレスを書き換える仕組み。main.cf にパラメータを書き、変換表ファイルを指す。

項目書き換え対象
canonical_maps送信者+受信者の 両方
sender_canonical_maps送信者のみ
recipient_canonical_maps受信者のみ
sender_canonical_maps = hash:/etc/postfix/sender_canonical

変換表(テキスト)を編集したら postmap で DB を生成して反映する。aliasesnewaliases に相当し、lookup テーブル全般(virtual / access / transport 等)で共通のパターン。

postmap /etc/postfix/sender_canonical

SMTP プロトコル(telnet で動作確認)

telnet サーバ 25 で SMTP セッションを手動で叩き、サーバの動作確認ができる。

$ telnet mail.example.com 25
220 mail.example.com ESMTP Postfix      ← 220 接続準備完了(サービスready)
HELO client.example.com                 ← セッション開始の挨拶(拡張版は EHLO)
250 mail.example.com
MAIL FROM:<sender@example.com>          ← ① 差出人(FROM は MAIL とペア)
250 2.1.0 Ok
RCPT TO:<recipient@example.com>         ← ② 宛先(TO は RCPT とペア)
250 2.1.5 Ok
DATA                                    ← ③ 本文開始の宣言
354 End data with <CR><LF>.<CR><LF>     ← 354 本文入力可
Subject: test mail

This is a test.
.                                       ← 本文終端は「単独のドット」
250 2.0.0 Ok: queued as XXXX
QUIT                                    ← セッション終了
221 Bye

主要 SMTP コマンド

段階コマンド補足
開始HELO / EHLOEHLO は拡張版(ESMTP・STARTTLS 等のネゴシエーション)。綴りは HELO(HELLO は誤り)
送信MAIL FROMRCPT TODATAFROM は MAIL、TO は RCPTMAIL TORCPT FROMBODY は存在しない)
終了QUIT切断

本文終端は 単独の .(ドットだけの行)

SMTP 応答コード

先頭の数字で意味が分かる 3桁コード。

区分意味
2xx成功220 準備完了 / 250 処理完了 / 221 切断
3xx中間(続けて入力)354 本文入力可(DATA 後)
4xx一時的失敗(後で再試行)421 / 450 / 452
5xx恒久的失敗500 構文誤り / 550 ユーザ不明 / 554
  • 220(接続時の準備完了)と 250(処理が完了)の区別が頻出。

TLS / 暗号化設定

Postfix で TLS を使うには main.cf(パラメータ)と master.cf(サービス) の両方が関わる。
さらにバージョンによって設定項目が変わる点が独特。

main.cf のパラメータ

項目役割
smtpd_use_tls = yesTLS を有効化2.2
smtpd_enforce_tls = yesTLS を強制(非 TLS を拒否)2.2
smtpd_tls_security_level = may / encrypt有効化/強制を 統合may≒use_tls、encrypt≒enforce_tls)2.3 以降
smtpd_tls_cert_file = /pathサーバ証明書共通
smtpd_tls_key_file = /pathサーバ秘密鍵共通

master.cf のサービス

サービスポート暗号化
smtps465SSL/TLS(暗黙)
submission587STARTTLS

バージョン差(2.2 vs 2.3+)

Postfix 2.2(旧)Postfix 2.3 以降(新)
有効化smtpd_use_tls = yessmtpd_tls_security_level = may
強制smtpd_enforce_tls = yessmtpd_tls_security_level = encrypt
方式boolean を2つ使い分け1つの security_level に統合
  • 接頭辞 smtpd_=受信(サーバ)側smtp_(d なし)=送信(クライアント)側

セキュリティ・スパム対策

オープンメールリレー

オープンリレー = 誰からでも・誰宛でも無条件にメールを中継してしまう状態。本来は「自ドメイン宛の受信」と「信頼できる利用者からの送信中継」だけを許すべき。

放置すると スパムの踏み台にされ、送信元が自サーバに偽装される。やがて RBL / DNSBL に登録され、正規のメールまで世界中で拒否される(信頼の崩壊)。

補足: SMTP は1980年代の「身元の知れた研究者だけ」という性善説で設計されたため、当時は不安定なネットワークで確実に届けるべく「誰のメールでも中継する」のがむしろ美徳だった。商用化・大衆化で匿名の悪意が流入し、同じ仕様が脆弱性に変わった。Telnet→SSH、FTP→SFTP と同じ構図。

中継を信頼できる相手だけに絞る(=閉じる)設定:

mynetworks = 127.0.0.0/8, 192.168.0.0/24   # 中継を許可する信頼ネットワーク

smtpd_recipient_restrictions =
    permit_mynetworks            # 内部ネットは許可
    permit_sasl_authenticated    # 認証済ユーザは許可
    reject_unauth_destination    # それ以外の「外部→外部」中継は拒否(オープンリレー防止の要)

外出先の正規ユーザは submission(587) + SASL 認証で送らせる。

RBL(DNSBL)

RBL(Realtime Blackhole List) = スパム送信元 IP のブラックリスト。別名 DNSBL(DNS-based Blackhole List) の通り、照会は DNS クエリで行う。

接続元 IP 203.0.113.45 を逆順 → 45.113.0.203
RBL ドメインを付与         → 45.113.0.203.zen.spamhaus.org
これを DNS で問い合わせ     → 127.0.0.x が返れば登録あり → 拒否
smtpd_recipient_restrictions =
    reject_rbl_client zen.spamhaus.org
  • RBL は DNS に相乗りするため、DNS(ポート53)を塞ぐと RBL は機能しない
  • SPF / DKIM / DMARC も DNS(TXT レコード)で実現されるため、メールのスパム対策・認証はだいたい DNS に乗っている

VRFY コマンドの無効化

VRFY = SMTP で「このユーザは実在するか」を問い合わせるコマンド。スパマーに 実在アドレスの収集(harvesting) を許すため、運用では無効化する。

disable_vrfy_command = yes

項目名が disable(無効化する)なので、「無効化を肯定する=yes」 で VRFY がオフになる(二重否定に注意。= no が VRFY 有効=デフォルト)。関連コマンドに、メーリングリストを展開する EXPN(これも収集に悪用されうる)。

chroot jail

chroot = “change root”。プロセスのルートディレクトリ(/)を指定サブディレクトリに付け替え、それより上を見えなくする。乗っ取られても 被害を jail 内に封じ込めるセキュリティ策。

Postfix の chroot は サービス単位の設定なので master.cf を編集する。master.cf は1行=1サービスで、8列のうち 5列目が chroot 列y/n/-)。

# service type  private unpriv chroot wakeup maxproc command
  smtp    inet  n       -      n      -      -       smtpd
#                              ↑5列目が chroot
  • chroot 列を y にすると、そのサービスが chroot 環境で動く。jail のルートは通常 キューディレクトリ /var/spool/postfix
  • jail 内には外が見えないため必要ファイル(ライブラリ・/etc/resolv.conf 等)のコピーが要り、メンテ負担が大きい。近年のディストリは デフォルトで chroot を n にすることが多い。