はじめに
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.cf | master.cf |
|---|---|---|
| 日本語名 | 主な設定ファイル | デーモン(サービス)設定ファイル |
| 何を書く | パラメータ(key = value) | サービス定義(1行=1プロセス) |
| 答える問い | 「どう動くか」 | 「何を動かすか」 |
| 具体例 | myhostname / smtpd_use_tls / disable_vrfy_command | smtp(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)。長いリスト系(mydestination・mynetworks・各種 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_mailboxにMaildir/を渡す” であって専用項目はない(定番のひっかけ)。- 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(不備を検出)は別物。前者は値を出し、後者は問題がなければ何も出さない。reloadはpostfixの役目で、postconf reloadは存在しない。
メールキューの操作(表示・再送・削除 × sendmail/Postfix)
「やりたいこと」と「どの MTA か」の2軸で整理する。mailq だけは両対応(互換インターフェース)。
| やりたいこと | sendmail 流 | Postfix 流 |
|---|---|---|
| 表示 | mailq / sendmail -bp | mailq / postqueue -p |
| 再送(flush) | sendmail -q | postqueue -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を再構築する。cmdrilllpic202.sm.5.11(「エイリアスDBを更新するコマンドを2つ」)の正解がこの2つ。 - aliases 専用が
postalias/newaliases、それ以外の lookup テーブル(virtual / access / transport / canonical 等)は後述のpostmap。postqueue(キュー)・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 を生成して反映する。aliases の newaliases に相当し、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 / EHLO | EHLO は拡張版(ESMTP・STARTTLS 等のネゴシエーション)。綴りは HELO(HELLO は誤り) |
| 送信 | MAIL FROM → RCPT TO → DATA | FROM は MAIL、TO は RCPT(MAIL TO・RCPT FROM・BODY は存在しない) |
| 終了 | 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 = yes | TLS を有効化 | 2.2 |
smtpd_enforce_tls = yes | TLS を強制(非 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 のサービス
| サービス | ポート | 暗号化 |
|---|---|---|
smtps | 465 | SSL/TLS(暗黙) |
submission | 587 | STARTTLS |
バージョン差(2.2 vs 2.3+)
| Postfix 2.2(旧) | Postfix 2.3 以降(新) | |
|---|---|---|
| 有効化 | smtpd_use_tls = yes | smtpd_tls_security_level = may |
| 強制 | smtpd_enforce_tls = yes | smtpd_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にすることが多い。