メール配送の仕組みとqmailを知る

最近、qmailを管理するようになったが、まったくといっていいほど理解していないので、ポイントをメモします。

メール配送のしくみ


図の参照元 => http://japan.internet.com/webtech/20030807/7.html



1. メールクライアントにてメールを記述(宛先、件名、内容など)
2. メールクライアントはリレー許可のあるSMTPサーバ(以降、メールサーバ)に配送を依頼
3. メールクライアントから送信依頼を受けたメールサーバは、メールが送り届けられるべきメールサーバを調べます。この情報は、メールの宛先とネームサーバ(DNSサーバ)のMXレコードから調べられます。
4. メールが送り届けられるべきメールサーバがわかったら、そのサーバに接続して配送します。
5. メールが送られてきたメールサーバは、そのサーバ内の受け取り人のメールボックスにメールを届けます。
6. 最後に、受取人がメールクライアントを用いて、そのメールをダウンロードし、実際に読まれます。

SMTPサーバとリレー

メール配送は、SMTP(Simple Mail Transfer Protocol)という通信規則を用いて行われています。SMTPTCPの25番ポートを利用する通信で、手元にあるメールを相手に送り渡すときに利用されます。

通常、SMTPで受信を受け付ける(受け取る)メールは限定されています。それは自サーバ内にメールボックスが設置されているメール以外は受け取る必要がないからです。したがって、SMTPで接続されてメールを送られてきたとしても、あて先の情報を見て、自サーバ宛のものではないという場合は、受け取りを拒否します。

しかし、「2」をよく見るとメールサーバ[A]は、自サーバ内にメールボックスがないメールについても受け取っています。これは、リレーと呼ばれる機能を実現するために特別に受け取っているのです。

リレーは、完全な配送機能をもっていないメールクライアントなどからひとまずメールを受け取り、代わりにそのメールが本来届けられるべきサーバに送信するものです。したがって、中継と呼ばれることもあります。


リレーの設定を間違えると、悪意を持った人から、SPAMなどの踏み台にされてしまう可能性があります。実際、踏み台にされてしまうと、サーバに負荷をかけられ本来の機能を実現できなくなってしまったりします。なんといっても、ほかの人に迷惑をかけてしまう可能性があり、非常に深刻な問題となります。

なぜ、このような問題が起きてしまうのかというと、SMTPでの通信にあたって、特にパスワード認証などが行われていないためです。適切な設定ができていないと、赤の他人によって利用されて不正中継などの問題を生むのです。

したがって、通常は、あらかじめリレーを許可するマシンのIPアドレスを登録しておき、SMTP接続されると、毎回そのリストと相手のIPアドレスを比べることで自サーバ宛以外のメールを受け付けるかどうかを判定します。最近では、固定されたIPアドレス情報だけでなく、POP before SMTPSMTP Auth などといった手法を用いて制限する方法も利用されています。

POPサーバ

代表的なものに、POP、APOPIMAPがあります。

メールの形式

メールを構成する基本要素

メール(メッセージ)はテキスト形式のデータであり、大きく分けて「ヘッダー部」と「ボディ部(本文)」の2つの部分で構成されます。メールはヘッダー部で始まり、区切りのための空行が1行、そしてボディ部の順に現れます。

メールにはASCII文字だけを含めることができます。よってASCII文字以外のコードが含まれるバイナリーデータや、SJIS(Shift_JIS)やEUC-JPコードで符号化されている日本語を含めることはできません。バイナリーデータをメールで送付したい場合は、バイナリーからASCIIテキスト形式に変換しなければなりません。また、日本語を含めるときはJIS(ISO-2022-JP)コードを用います。

ヘッダー部に日本語を含めたい場合は、JISコードの日本語文字列をさらにMIME(Multipurpose Internet Mail Extensions)エンコードと呼ばれる形式で符号化する必要があります。

メールヘッダー部の形式

メールのヘッダー部には、件名、送信者と送付先の名前やアドレス、日付、配送経路などの情報が含まれています。各情報は「フィールド」と呼ばれる単位で保持され、1つのフィールドは次のような形式になっています。

 フィールド名: フィールド内容

代表的なフィールドとその内容と意味を紹介

From:フィールド メール送信者のアドレス情報
To:フィールド Cc:フィールド あて先:Toは本来伝えたい相手、Ccは関係者などに使い分ける
Bcc:フィールド 内容・用途はCcフィールドに同じ、Bcc:はあて先アドレスを隠蔽するために利用される
Reply-To:フィールド メールの返信先アドレスを指定
Subject:フィールド メールの件名
Date:フィールド メールの送信日時
Message-ID:フィールド メールを一意に特定するために識別子。メールクライアントが自動的に付加する
Received:フィールド メール配送システム(MTA)が付加する受信情報。受信元と配送システムのホスト名とIPアドレス、受信した時間などが含まれる
メールアドレス

メールアドレスは、アットマーク「@」を境に2つの部分から構成されます。

user@example.gr.jp
※user = ローカル部、example.gr.jp = ドメイン

ローカル部(local part)は】ユーザー名、ドメイン部(domain part)は、ユーザーが所属するサイトを識別するホスト名あるいはドメイン名。

エンベロープアドレス

メール配送システムは、メールクライアントやほかのメール配送システムからメールを受信するときに、送信者アドレスと宛先アドレス、そしてメールのメッセージを受け取ります。ここで注目すべきは、メール配送システムは、送信者と宛先のアドレス情報を得るためにメールのヘッダー部は参照しないという点です。

メールクライアントでメールを作成するとき、送信者と宛先のアドレスは、メールヘッダー部のFrom:/To:フィールド(あるいはそれに相当する入力欄)に指定することと思います。作成したメールの送信を指示すると、メールクライアントはメールのヘッダー部の該当フィールドから送信者のアドレスと宛先アドレスを抜き出し、そのアドレスとメールメッセージを配送システムに渡します。

通常、メールがメールクライアントから送出された後は、メールヘッダー内のメールアドレスが配送に影響を与えることはありません。

インターネットメールの配送にかかわる要素を従来の郵便物による配送に当てはめると次のように対応します。

インターネットメール配送 郵便による配送
宛先アドレス 封筒の宛先欄に書かれている住所
送信者アドレス 封筒の送信者欄に書かれている住所
メール(メッセージ) 便箋(封筒の中身)


このように、メール配送における宛先と送信者のアドレスは、封筒(envelope)に書かれた宛先と送信者の住所のようなものです。実際、メール配送における宛先アドレスのことを「エンベロープ受信者アドレス(envelope recipient address)」、送信者のアドレスのことを「エンベロープ送信者アドレス(envelope sender address)」と称します。その両方を指して「エンベロープアドレス」と称します。

メールヘッダー部のアドレスとエンベロープアドレスの不一致

 ヘッダーのTo:/Cc:フィールドのアドレスとエンベロープの宛先アドレスは、通常は一致していますが、一致していないこともあります。From:フィールドのアドレスとエンベロープの宛先アドレスも同様です。


 よくあるの例がメールの転送サービスです。メールをほかのアドレスに転送する際は、ヘッダーのアドレスは手を加えられず、エンベロープの宛先アドレスだけが転送先アドレスに置き換えられます。

 アドレスを詐称するための小細工としてそのようなメールが送付されることもあります。

メールの不達(バウンス)と差し戻し先アドレス

 メールが宛先アドレスに送付できなかった場合、メール配送システムは不達通知メールを送信者アドレス(エンベロープ送信者アドレス)に送信します。まれに、ヘッダー部のFrom:やErrors-To:フィールドなどに含まれるアドレスに不達通知を返すシステムがありますが、そのような動作は好ましくありません。

 メールが宛先アドレスに送付できないことを「メールがバウンス(bounce)」すると表現します。

qmail

qmailとは

qmailは、イリノイ大学助教授であるDJ.Bernstein氏が開発したメールサーバソフトです。

qmailの特徴

sendmailと比較することで、qmailの特徴を見ていきましょう。

セキュリティへの配慮

qmailでは、開発時にセキュリティホールに対して極めて厳格なポリシーのもとに開発されているため、非常に堅牢といえます。たとえば、セキュリティーホールを生み出しやすいCライブラリを利用せずに、Bernstein氏が用意したライブラリを利用しているなど工夫がなされています。このほかに、qmailではセキュリティ向上のために、次のような工夫がなされています。

  • 構成を単純にする
  • 相互には信用しない機能別のプログラムに分割する
  • root権限でする仕事は最小限にする
  • setuidすることは最小限に抑える
設定ファイルの構造

qmailの設定ファイルは、sendmailに比較すると圧倒的に間単に記述できます。

設定ファイルが、1設定項目に対して1ファイルという対応もqmailの特徴ともいえるでしょう。

安全性の確保

sendmailをはじめとして従来は、mbox形式やmhフォルダ形式が採用されていました。しかし、これらはメール配送中にマシンがクラッシュすると、メールデータが破壊される可能性がありました。そこで、qmailでは、新しい方式としてmaildir形式を採用しています。この方式では、各メールデータがそれぞれ独立して扱われることで、mbxo形式やmhフォルダ形式に見られるトラブルを防ぐことができます。

高速なメール配送

大量のメールを配送を短時間で完了するためにはそれなりの工夫が必要です。その点では、qmailではデフォルトでかなりの配送速度を実現しています。

現代ニーズに対応

バーチャルドメイン(複数ドメインのメールを管理する)やSPAMメール対策などが比較的容易に行えます。

また、qmailには数多くのツールやパッチが多く存在してます。これらを使うことで、「POP before SMTP」「sendmailの/etc/aliasesの利用」などを実現することができます。これらは非常に有力であり、qmailに対してちょっとした機能追加などを施したいときに有効です。

qmailの構成

qmailは非常にシンプルな構成をとっています。ここでは、qmailディレクトリ構造やプロセス構造を中心に見ていきます。

qmailディレクトリ構造

qmailでは、/var/qmail以下に各役割を持つディレクトリを利用します。各ディレクトリはqmailの動作にとって非常に重要な意味を持っています。

qmailディレクトリ構成

  bin 実行ファイルが配置
  control 動作設定ファイルが配置
  alias 転送設定ファイルが配置
/var/qmail queue キュー管理用ディレクト
  doc ドキュメントファイルが配置
  man マニュアルが配置
  boot 起動スクリプト
  users qmail-lspawnが生成するユーザーデータベースファイル配置
qmailのプロセス

qmailは、1つのプログラムファイルではなく、複数のプログラムで成り立っています。これは、郵便局員にたとえると「1人がポストから集配を担当し、1人が仕分け作業、もう1人が配達を」といった具合に、役割ごとに作業を分担を行っているのです。


qmialの中心となるプロセスとして、qmail-send, qmail-clean, qmail-lspawn, qmail-rspawn, sploggerの5つがあげられます。この5つのプロセスは常に起動していて、キューの確認やメッセージの配送を行います。

qmailのプログラム群

qmailには多くのプログラムが準備されています。実際、/var/qmail/bin 以下を確認すると40近くのプログラムがあります。この中には、qmailを操作したり、メールを送信するためのユーティリティがあります。ユーティリティの中には、単体で起動し実行するものと、ほかのプログラムと連携して利用するものがあります。

プログラム 役割
qmail-inject コマンドライン版のメールクライアント
qmail-smtpd SMTP経由でメールを受信する。受信したメールは qmail-queue に渡される
qmail-queue メールをキューに登録する
qmail-clean システムがクラッシュしたときににキュー内に残された不要なファイルを削除する
qmail-send キュー上のメールの配送制御を行う
qmail-lspawn qmail-localを呼び出してローカルユーザ宛のメールを配送させる。qmail-sendから呼び出される
qmail-local ローカルユーザ宛のメールを配送する
qmail-rspawn qmail-remoteを呼び出してリモートユーザ宛のメールを配送させる。qmail-sendから呼び出される
qmail-remote リモートユーザにメールを配送する
qmail-showctl 現在の設定を表示する
qmail-start メールの配送のためのプロセス qmail-send、qmail-lspawn、qmail-rspawn、qmail-cleanを起動する
qmail-qmtpd QMTPでの接続を受け付ける
qmail-pop3d POP3の接続時に、ユーザーのメール読み込み・削除を支援する
qmail-popup POP3の接続時に、ユーザ・パスワード情報を確認するために利用する
qmail-qread キューにあるメールの情報を表示する
qmail-qstat キューにたまっているメールの数を表示する
qmail-tcpto qmail-remoteのタイムアウトテーブルを表示する
qmail-tcpok qmail-remoteのタイムアウトテーブルを初期化する
sendmail sendmailコマンド互換のインターフェースを持つプログラム。sendmailの置き換えのために準備されている
splogger syslogに各種ログを渡す
tcp-env ネットワーク接続時の情報を環境変数に設定する
qbiff 新着メールが届くと画面にその旨を表示する
maildir2mbox maildir形式のメールボックスをmbox形式に変換する
maildirmake maildir形式のメールボックスを作成する
maildirwatch 環境変数MAILDIRに指定されたメールボックスの新着メールを表示する
qmail-newmrh 設定ファイルmorercpthostsからデータベースファール morercpthosts.cdbに書き出す。このファイルはqmail-smtpdが利用する
qmail-newu 設定ファイル /var/qmail/users/assignの情報を、データーベースファイル /var/qmail/users/cdbに書き出す。このファイルは qmail-lspawnがりようする。
qmail-pw2u /etc/passwdなどのユーザ情報ファイルを標準出力から読み込み、/var/qmail/users/assignに出力する

qmailの設定ファイル

qmailは設定情報に基づいて動作します。qmailの設定ファイルは/var/qmail/controll 以下に配置することになっています。
qmailでは、1つの設定項目に対して、1つのファイルが割り当てられています。ファイル名が設定項目名であり、ファイルの本文が設定値となります。設定項目によって設定値を1つだけ指定できるものと複数できるものがあります。複数指定する場合は、1つの設定ファイルを記述するごとに改行することで、1行に月1つの設定値を記述するようにします。

 必須の設定ファイルはmeとrcpthostsだけです。(厳密には不正中継の可能性がなければmeのみでも動作します)


qmail全般の設定

設定ファイル 初期値 設定内容
me(※) なし※必須 qmailが稼動するホストのFQDN(Fully Qualified Domain Name)を記述する
badmailfrom (none) 拒絶アドレスリスト
bouncefrom MAILER-DAEMON 差戻し管理者名
bouncehost me 差戻しホスト名
concurrencylocal(※) 10 ローカル配送多重度
concurrencyremote(※) 20 リモート配送多重度
databytes 0 受信データ量上限
defaultdomain(※) me メールの送信先(To:)にドメイン名が無い場合に補完するドメイン名を記述する
defaulthost me 省略時ホスト名
doublebouncehost me 2重バウンスホスト名
doublebounceto postmaster 2重バウンスの宛先
envnoathost me ホスト省略時ドメイン
helohost me SMTP開始ホスト名
idhost me Message-IDホスト名
localiphost me 当ホストの対応IPアドレスを指定
locals(※) me qmailが受信するメールのホスト名とドメイン名を記述する
morercpthosts (none) 受信ドメイン一覧(2)rcpthostsの補助的役割に使用
percenthack (none) %ハック適用ドメイン名一覧
plusdomain me 追加ドメイン
qmqpservers (none) qmqpサーバリスト
queuelifetime 604800 メールがキューに保存される秒数
rcpthosts(※) (none) qmailが受信するメールのホスト名とドメイン名を記述する
smtpgreeting me SMTP応答用ホスト名
smtproutes (none) SMTP経路指定
timeoutconnect(※) 60 接続時待ち時間
timeoutremote(※) 1200 応答待ち時間
timeoutsmtpd(※) 1200 SMTPデータ待ち時間
virtualdomains(※) (none) 仮想ドメイン名一覧
qmail環境変数

qmailでは、UNIXの環境設定を巧みに利用しています。環境変数を利用することで設定値を(設定ファイルを越えて)変更することができます。たとえば、SMTPでのメール受信時に環境変数RELAYCLIENTが指定されていると、qmail-smtpdはcontrol/rcpthostsの設定を無視し、どんな宛先のメールでも受信するようになります。
 環境変数はそれを解釈する各プログラムを実行する前に設定します。これを実現するのが、tcpserverTCP wrappers(tcpd)などのプログラムです。
 これらは、外部からの接続があると指定されたプログラムを起動して接続に対応しますが、そのときに接続情報などを環境変数として渡すことができます。

qmailによるメール配送のしくみ

qmailでは、複数のプログラムによってメールの配送が行われます。配送に当たっては、9つのプログラムが主にかかわっています。


図 => A high performance MTA, qmail (Make full use of qmail, a high performance mail transfer agent)

qmail-smptd

qmail-smtpdは外部ホストからの接続によってメールを受け取り、qmail-queueにそのメール情報を渡します。
qmail-smtpdには外部からの接続を直接受け付ける機能がないため、tcpserverやinetdなどのプログラムが利用されます。これらは、外部ホストからSMTPでの接続があると自動的にqmail-smtpdを起動し、接続の橋渡しをします。

qmail-smtpdを起動されSMTPでの接続が確立されると、外部ホストからメールを受け取ります。その様子は下記のようになります。telnetSMTPのポート(25番)に接続し、メールを送っています。

$ telnet mail.hogehoge.com 25
Trying 121.119.174.207...
Connected to mail.hogehoge.com.
Escape character is '^]'.
220 mail.hogehoge.com ESMTP
HELO mail.hogehoge.com
250 mail.hogehoge.com
MAIL FROM: fuga@mail.hogehoge.com
250 ok
RCPT TO: bar@mail.hogehoge.com
250 ok
DATA
354 go ahead
To: bar@mail.hogehoge.com
Subject: Test
From: fuga@mail.hogehoge.com

test mail

.
250 ok 1239692617 qp 3222
QUIT
221 mail.hogehoge.com
Connection closed by foreign host.
qmail-inject

qmail-injectはコマンドライン用のメールクライアントです。ローカルからのメール送信を受付、qmail-queueにそのメール情報を渡します。
qmail-injectは、標準入力からメールを受け取ります。その後必要に応じて、ヘッダ情報を整形します。たとえば、From:情報がない場合、qmail-injectを起動したユーザーや環境変数の情報をもとにFrom:をヘッダに付け加えます。

qmail-queue

qmail-queueは、qmail-smtpdやqmail-injectから受け取ったメールをキューに格納し、qmail-sendに配送を依頼します。

qmail-send

qmail-sendjは、絶えずキューを確認してメール配送の管理を行っています。キュー上にメールがあれば、qmail-rspawnやqmail-lspawnプログラムに対してそのメールを配送するように促します。メールの宛先がローカルユーザのときはqmail-lspawn、リモートユーザの時はqmail-rspawnとなります。

qmail-clean

qmail-queueやqmail-sendがキュー内のファイルを操作している最中にシステムがクラッシュすると、キュー内に処理途中の不完全なファイルが取り残されてしまうことがあります。qmail-cleanは、そのようにして残されたゴミファイルを削除します。

qmail-rspawn

qmail-rspawnは、リモートユーザー宛のメールを配送する場合に、qmail-sendから呼び出されます。その後、qmail-rspawnは、qmail-remoteを起動しメールの配送を実行させます。

qmail-remote

qmail-remoteはSMTPを利用して、リモートユーザー宛のメールを配送します。qmail-remoteは宛先ごとに別々に起動されます。

qmail-lspawn

qmail-lspawnは、ローカルユーザ宛にメールを配送する場合に、qmail-sendから呼び出されます。その後、qmail-lspawnは、qmail-localを起動しメールの配送を実行させます。

qmail-local

qmail-localはローカルユーザ宛のメールを配送します。多くの場合、各ユーザーのメールボックスにメールを配置することになります。qmail-localは、宛先ごとに別々に起動します。


キュー

qmailのキュー

配送待ちのメールはキューと呼ばれるしくみによって管理されます。キューは複数のディレクトリを用いることで、キュー内のメールの状態がわかるようになっています。qmailのキューはディレクトリ /var/qmail/queue以下のサブディレクトリによって管理されています。

新しいメールは、まず一意なファイル名が付けられ、キューに格納されます。その後、qmail-localやqmail-remoteによって配送されることになります。

キューのサブディレクト

ディレクト 中身
pid 空のファイル(メールをキューに登録するときに利用)
mess メール(メッセージ)
intd 送信者と宛先のアドレス(アドレスをキューに登録するときに利用)
todo 送信者と宛先のアドレス(qmail-queueからqmail-sendに渡すときに利用)
info 送信者のアドレス
local 宛先のアドレス(ローカル配送)
remote 宛先のアドレス(リモート配送)
bounce 配送に失敗したメールの情報(宛先アドレスとしっぱりの理由)
lock ロックファイル

qmailのインストール

※一番最後に記述しました。

maildir形式のメールボックスの利用

メールボックスの配置場所は、各ユーザのホームディレクトリの「Mailbox」という名前ファイルになります。qmailでは、mbox形式以外に、maildir形式のメールボックスを利用することができます。

maildir形式のメールボックスは、mbox形式のように1ファイルに複数のメールを格納することはしません。専用のディレクトリを作り、その中に1メール1ファイルという形式で保管します。このことで配送効率を上げ、安全性を向上します。ただし、その一方でmaildir形式に対応していないアプリケーション(メールクライアント、POP/IMAPサーバなど)があるので、相性の面で注意が必要です。

maildir形式を個人的に利用する場合は、自分のホームディレクトリに .qmail というファイルを作成し、そのファイルに次のように記述しておきます。

■.qmailへの記述

./Maildir/

また、自分のホームディレクトリに maildir形式に対応したディレクトリを作成する必要があります。maildir形式のメールボックスを作成するためには maildirmake を利用します。このとき、作成されたメールボックスの所有者・パーミッションには注意が必要です。

■maildir形式のメールボックスディレクトリ)の作成

$ cd
$ pwd
/home/user
$ /var/qmail/bin/maildirmake Maildir

これで、このユーザーへ配送されるメールはmaildir形式のメールボックス ~/Maildir へ配送されます。

 一方、すべてのユーザーに対して maildir形式を利用する場合は、 /var/qmail/rc を修正するほうが効率が良いでしょう。

■/var/qmail/rcの修正

(修正前) qmail-start ./Mailbox splogger qmail
(修正後) qmail-start ./Maildir/ splogger qmail

 これで、qmailを再起動すれば、maildir形式でメールが配置されるようになります。ただし、このときも各ユーザに対して maildirmake で maildir形式のディレクトリを作成させる必要があります。

 ユーザーを追加するたびに、コマンド maildirmake を実行するのは面倒なため、Linuxなどでは次のようにしておくとよいでしょう。

■実行例

# /var/qmail/bin/maildirmake /etc/skel/Maildir

これで、ユーザを追加をするときに、ホームディレクトリに maildir形式のディレクトリができるようになり、便利です。useraddは、ユーザのホームディレクトリを作成するときに、/etc/skel 以下のファイルやディレクトリをコピーしてくれます。


SMTPサーバの設定

 qmail環境でSMTPサーバを構築するには、qmail-smtpdを利用します。しかし、qmail-smtpd自体にはSMTP接続を受け付ける機能はありません。したがって、tcpserverやinetd, xinetdなどのスーパーサーバーを経由してSMTP接続を受け付けます。

 tcpserverqmailの作者であるD.J.Bernstein氏が作ったサーバ制御ツールです。

tcpserverにおけるリレー設定

リレーを許可するホストのアクセス制御情報を記述したデータベースファイルを準備する必要があります。このデータベースファイルを tcpserver が認識することおで、リレーの許可がうまく適用されることになります。tcpserverではデータベースファイルとして cdb という形式を採用しています。

 それでは、このエータベースファイルである cdb ファイルを作りましょう。cdbファイルを作成するためにファイル /etc/tcp.smtp を準備します。

■/etc/tcp.smtpの設定例

172.25.0.:allow,RELAYCLIENT=""
127.:allow,RELAYCLIENT=""

 これはIPアドレスが172.25.0.*と127.*.*.*(*は任意)であるホストからの接続に対しては、環境変数RELAYCLIENTを設定するという意味です。 qmail-smtpdにRELAYCLIENTが渡されると、その接続に対しては(tcpthostsにかかわらず)リレーが許可されます。

 それでは、このファイルtcp.smtpを用いてデータベースファイル tcp.smtp.cdbを作成しましょう。作成にはtcprulesコマンドを用います。コマンド tcprulesの書式は以下のとおりです。

tcprules <生成するcdbファイル> <生成時に利用する一時ファイル>

今回の場合は、以下のようになります。

■実行例

# /usr/local/bin/tcprules /etc/tcp.smtp.cdb /etc/tcp.smtp.tmp < /etc/tcp.smtp

これでデータベースファイル /etc/tcp.smtp.cdb が生成されます。一時ファイルはコマンド tcprulesを実行し終えたら、自動的に削除されます。

 では、このデータベースファイルを使って tcpserverを起動し、qmail-smtpdが特定のホストからのリレーを受け付けるように設定しましょう。tcpserverはオプション -x cdb ファイルでデータベースファイルを読み込むようになっているため、次のようにします。


tcpserverにアクセス制御データベースファイルを指定して起動

# nohup /usr/local/bin/tcpserver -HR -x /etc/tcp.smtp.cdb -u 502 -g 501 0 smtp /var/qmail/bin/qmail-smtp &

これで、/etc/tcp.smtp に記述したとおりにリレーが実現されるようになっているはずです。
※-u 502 -g 501 はqmaildのユーザID、nofilesのグループIDです。

$ id -u qmaild
502
$ id -g qmaild
501

tcpserverの書式とオプション

tcpserverの書式は次のとおりです。

tcpserver [オプション] <監視IPアドレス> <監視ポート> <デーモンプログラム>
オプション 役割
-c 接続数 同時に起動できる接続数の上限を指定
-x cdb ファイル cdbファイルに指定されたルールに従う
-u UID ポート監視開始後tの実行ユーザID
-g GID ポート監視開始後の実行グループID
-h 接続元のホスト名をDNSに問い合わせ、結果を $TCPREMOTEHOST に格納(デフォルト)
-H 接続元のホスト名をDNSに問い合わせない
-p ホスト名を調べた後、逆引きを問い合わせ、IPアドレスが一致しない場合、$TCPREMOTEHOSTの情報を削除する(デフォルト)
-P ホスト名を調べた後、逆引きを問い合わせない
-r 接続元ホストから、$TCPREMOTEINFOを 得る(デフォルト)
-R 接続元ホストから、$TCPREMOTEINFOを得ない

POPサーバの設定

tcpserverによるPOPの設定

 tcpserverを利用して、POPの接続を受け付けるようにしてみます。

 その前に、準備として、checkpasswordプログラムを導入します。これはPOP接続時のユーザ・パスワード認証を担うものです。qmail-pop3dには、認証機能が実装されていません。すなわち、認証に関してはほかのソフトウエアに任せています(ここでは checkpassword です)。

$ tar xzvf checkpassword-0.90.tar.gz
$ cd checkpassword-0.90
# make setup check

これにより、プログラムが /bin/checkpassword にインストールされます。

POPサーバの起動

基本的なやり方はSMTPサーバと同じです。

# nohup /usr/local/bin/tcpserver -HR 0 pop3 /var/qmail/bin/qmail-popup <サーバのFQDN> /bin/checkpassword /var/qmail/bin/qmail-pop3d Maildir &

サーバのホスト名が host.example.com の場合、次のようになります。

■実行例

# nohup /usr/local/bin/tcpserver -HR 0 pop3 /var/qmail/bin/qmail-popup host.example.com /bin/checkpassword /var/qmail/bin/qmail-pop3d Maildir &

これで、110番(POP)への接続は、qmail,pop3dに渡されるようになりました。


SMTPの認証の必要性

 メールサーバーを管理する上で、SMTPのリレーを許可する範囲を決めることは極めて重要な判断です。しかし、モバイル環境の発達した現在、SMTPサーバを外出先や出張先からも利用したいというニーズは少なくありません。しかし、インターネットのどこからでもリレーを許可するわけにはいきません。したがって、何らかの方法によって、接続相手を認識し、適切な相手のみに対してリレーを許可するという方法をとる必要があります。現在、これを実現する方法として、SMTP AUTHとPOP before SMTPがあります。

 SMTP AUTHは、SMTPに対して認証を行うAUTHコマンドを拡張定義したもので、SMTPでの接続時にユーザ認証を行い、接続元の確認を行います。認証に成功すればリレーが許可され、そうでなければリレーは送信できません。

 本来ならば、SMTP AUTHによる方法がシンプルですが、メールクライアント側での実装がなかなか進まないのが現状であるため、既存のSMTPとPOPをうまく組み合わせる方法が採用されています。それが、POP before SMTPです。これは、リレーを許可する相手を識別するためにPOPでのユーザ認証を利用します。SMTPによるリレー送信をする前にPOPでの接続を行い、そこでユーザ認証を行います。POPで認証が成功した接続元に関しては、その後の一定期間のリレーが許可されるようになります。すなわち、リレー送信をする前にあらかじめPOPでユーザー認証を行うというものです。

.qmailファイルの利用

.qmailファイルとは?

.qmailファイルは sendmailの .forwardファイルに似た用途を持ち、書式や動作も似通っていますが、いくつか異なる点があります。

.qmailファイルの役割

 .qmailファイルは通常はユーザのホームディレクトリに置かれ、ユーザーに配送されたメールをどのように扱うかを制御します。メールの配送指定には、次のいずれかの方法を指定できます。

  • maildir形式のメールボックスへの保存
  • mbox形式のメールボックスへの保存
  • ほかのメールアドレスへの転送
  • コマンドを起動して標準入力に渡す

.qmailファイルを評価して指定された配送処理を実行するのは、qmail-localコマンドです。.qmailファイルが存在しない、あるいは.qmailファイルのサイズが0バイトの場合、qmail-localはqmail-startコマンドを介して指定されたデフォルトの配送方法を実行します。ただし、拡張メールアドレスの場合、対応する.qmailファイルが存在しないとき、メールはバウンスされます。

拡張メールアドレス

 qmailが稼動しているシステムで自分宛のメールを受け取っているユーザは、自分のユーザー名に続いてハイフン「-」と任意の文字列を足したものをローカル部に持つ「拡張メールアドレス」を利用することができます。たとえば、yoursite.example.com ドメインのユーザー carol は、「carol@yoursite.example.com」のほかに「carol-anything@yoursite.example.com」といったアドレスでも受け取れます。

 拡張アドレスは好きな数だけ用意することができます。ハイフン以降の「anithing」の部分は、メールアドレスのローカル部に含めることができる文字であれば、どんあものでもかまいません。ただし、末尾が「-default」、「-owner」となっているアドレスは特殊です。

仮想ドメイン機能

qmailには、複数のドメインのメールを受信し、ドメインごとに異なるユーザ空間とメールボックスを扱うための機能があります。

非常時接続環境におけるメール送信

非常時接続環境における問題と解決方法

 多くのMTAは、何らかの理由で配送先のメールサーバに接続できなかった場合、メールをキューに滞留し、しばらく時間をおいたあとに配送を再施行するようになっています。qmail(qmail-send)の配送の仕様もそのようになっており、一時的な理由で配送に失敗したメールは、しばらくキューに滞留し続けます。
 MTAはこの特性を利用するならば、オフライン状態になるローカルの環境内に1つMTAサーバを用意して、ローカル環境のメールクライアントからのメール送信にそれを使用するように設定するだけで、目的は達成されます。

ローカルのqmailの配送経路の設定

 オンライン時にDNSが利用できるなら、もちろんローカルのqmail自身に配送させることもできます。しかし特定のSMTPサーバーに配送をまかせることで、ローカルのqmailは宛先アドレスごとの送付先ホストの検索(ドメインのMXレコード検索)をしなくて済む分、配送にかかる時間を短縮できます。
 また、わずかですが、ネットワークの帯域を節約できます。

 qmail(qmail-remote)に静的な配送経路を指示するには、control/smtproutesファイルを指定します。control/smtproutesファイルの各行には、ドメイン名とそのドメイン宛のメール配送を依頼するSMTPサーバ名を、以下のような書式で記述します。

ドメイン名:SMTPサーバー名:SMTPポート番号

リモートへのメール配送をすべて特定のSMTPサーバに送るには、次のようにドメイン名を省略した行を記述します。ポート番号を省略すると、SMTP標準のポート番号(25)が利用されます。

■リモートへのメール配送をすべてISPSMTPサーバーに以来する(control/smtpproutes)

:mailhost.isp.example.net

 control/smtproutesファイルの設定を終えたら、オンライン状態でメールを送信し、正しく配送が行われることを確認してください。

ローカルのqmailに配送させたいなら

 オンライン時にqmailが稼動するホストからDNSが利用できるなら、qmail自身に宛先ホストの検索(MXレコードの検索)と配送を行わせることができます。よって、先の節で解説したcontrol/smtproutesファイルの設定は必要ありません。

 特定のドメイン宛のメールだけMXレコードに従い配送させたいという場合は、control/smtproutesファイルに宛先のSMTPサーバー名を省略した行を記述します。control/smtproutesの設定は、明示的にドメインが指定されている行のほうが優先されます。

■特定のドメイン宛のメールはMXレコードに従い配送させる(control/smtpproutes)

:mailhost.isp.example.net
specific.domain.example.jp:
キューの最長滞留時間の調整

 長期にわたりオフライン状態になる可能性があるなら注意が必要です。qmailはデフォルトで7日以上キューに滞留していたメールはバウンスし、送信者に返してしまいます。キューの視聴の滞留時間は /control/queuelifetime ファイルで設定可能です。通常であれば、このファイルを用意せずデフォルト(604800秒、つまり7日間)にしておけばよいでしょう。

SMTPによるメール配送を制限する

qmailqmail-smtpd)は、SMTPのMAILコマンドで渡される送信者アドレス(control/badmailfrom)や、RCPTコマンドで渡される宛先アドレスのドメイン部(control/rcpthosts, morercpthosts)、DATAコマンドで渡されるメールのサイズ(control/databytes)により、メールの受信を拒否することができます。

大量メール配信時のパフォーマンス改善

送信処理の最大並列数の上限を上げる

■最大並列数に指定できる値の上限
 qmailはメール配送処理を、複数のプロセスを生成し平行して実行します。ローカルユーザへの配送の最大並列数は control/concurrencylocal、リモートへの配送の最大並列数はcontrol/concurrencyremoteの設定により制限され、デフォルトの最大並列数はローカル配送は10、リモート配送は20に設定されています。大量のメールを配送する必要があるならば、配送処理の最大並列数をあげることで(ほかにボトルネックが生じない限り)、その分だけメール配送のパフォーマンスは向上します。

 しかし、control/concurrencylocal、control/concurrencyremoteで指定できる並列数は、最大で120に制限されています。この制限は、qmailコンパイル時、qmailのソースツリーに含まれる conf-spawnファイルに記述されている値で決まります。このファイルの値を増やしてqmailコンパイルすることで、121以上の並列配送を実現できます。

 しかしそれでも、conf-spawnファイルに記述できる最大並列の最大値は255に制限されます。これはqmail内部実装による制限です。


■最大並列数の上限を256以上にする
 次のパッチを適用することで、qmailは256以上のプロセスを生成できるようになります。


■256以上の最大並列数を指定可能にするパッチ

big-concurrency.path


■このパッチの適用例

$ cd source/dir/of/qmail-1.03
$ patch -p1 < /path/to/big-concurrency.path

このパッチにより、実装として最大65536の並列実行に対応しますが、65000以下に制限するように作られています。conf-spawnファイルは1000に書き換わります。通常UNIXカーネルは、システム全体あるいはユーザごとに、同時に実行できるプロセスや扱えるファイル記述子の数、消費メモリサイズなどに制限をかけています。このパッチを適用しqmailの制限を増やすだけでなく、同時にカーネルパラメーターの調整を確認することを忘れないようにしてください。

そのほかこの書籍に載っている情報

sendmailからqmailへの移行

sendmailからのメールボックス移行や、sendmail互換環境を作るなどが説明されています。

パッチによるqmailの動作変更

qmailのさまざまなパッチが紹介されています。

qmailのインストール例

for Linux. qmail version 1.03。下記はCentOS5.2上で行ったものです。

■qmail
$ su -
# mkdir /var/qmail
# groupadd nofiles
# useradd -g nofiles -s /sbin/nologin alias -m -d /var/qmail/alias -k /dev/null
# useradd -g nofiles -d /var/qmail -s /sbin/nologin -M qmaild
# useradd -g nofiles -d /var/qmail -s /sbin/nologin -M qmaill
# useradd -g nofiles -d /var/qmail -s /sbin/nologin -M qmailp
# groupadd qmail
# useradd -g qmail -d /var/qmail -s /sbin/nologin -M qmailq
# useradd -g qmail -d /var/qmail -s /sbin/nologin -M qmailr
# useradd -g qmail -d /var/qmail -s /sbin/nologin -M qmails
# mkdir ~/src
# cd ~/src
# wget ftp://ftp.jp.qmail.org/qmail/qmail-1.03.tar.gz
# tar zxvf qmail-1.03.tar.gz
# cd qmail-1.03
# wget http://www.itheart.com/phpgw/qmail-date-localtime.patch
# wget http://members.elysium.pl/brush/qmail-smtpd-auth/dist/qmail-smtpd-auth-0.31.tar.gz
# wget http://qmail.mirrors.summersault.com/qmail-smtpd-relay-reject
# wget http://www.qmail.org/big-concurrency.patch
# tar zxvf qmail-smtpd-auth-0.31.tar.gz
# /bin/mv qmail-smtpd-auth-0.31/* .
# patch < qmail-date-localtime.patch
# patch < auth.patch
# patch < qmail-smtpd-relay-reject
# patch -p1 < big-concurrency.patch
# sed -i 's/1000/509/g' conf-spawn
# vi error.h
 - extern int errno;
 + #include<errno.h>
# make setup check
# ./config-fast `hostname`
# echo `hostname -d` >> /var/qmail/control/me
# echo `hostname -d` >> /var/qmail/control/rcpthosts
# echo `hostname -d` >> /var/qmail/control/locals
# cd
# echo "MANPATH /var/qmail/man" >> /etc/man.config


■checkpasswordインストール
# cd ~/src
# wget http://cr.yp.to/checkpwd/checkpassword-0.90.tar.gz
# tar zxvf checkpassword-0.90.tar.gz
# cd checkpassword-0.90
# vi error.h
 - extern int errno;
 + #include<errno.h>
# make && make setup check
# cd
# chown root:nofiles /bin/checkpassword
# chmod 4750 /bin/checkpassword


■tcpserverインストール
# cd ~/src
# wget http://cr.yp.to/ucspi-tcp/ucspi-tcp-0.88.tar.gz
# tar zxvf ucspi-tcp-0.88.tar.gz
# cd ucspi-tcp-0.88
# vi error.h
 - extern int errno;
 + #include<errno.h>
# make setup check
# cd
# echo '127.:allow,RELAYCLIENT=""' > /etc/tcp.smtp
# tcprules /etc/tcp.smtp.cdb /etc/tcp.smtp.tmp < /etc/tcp.smtp


■sendmailの停止
# /etc/rc.d/init.d/sendmail stop
# chkconfig sendmail off
# chkconfig --list sendmail
# chmod 0 /usr/lib/sendmail
# chmod 0 /usr/sbin/sendmail
# mv /usr/lib/sendmail /usr/lib/sendmail.bak
# mv /usr/sbin/sendmail /usr/sbin/sendmail.bak
# ln -s /var/qmail/bin/sendmail /usr/lib/sendmail
# ln -s /var/qmail/bin/sendmail /usr/sbin/sendmail


■qmail起動スクリプト作成
# cp /var/qmail/boot/home /var/qmail/rc
# sed -i 's/Mailbox/Maildir\//g' /var/qmail/rc
# yum -y install tcsh    #yum list installed | grep tcsh で入っていたらいらない
$ touch qmail
$ vi qmail
 + #!/bin/bash
 + #
 + # qmail
 + #
 + # chkconfig: 2345 80 30
 + # description: qmail start/stop script
 +
 + # Source function library.
 + . /etc/rc.d/init.d/functions
 +
 + PATH=/var/qmail/bin:/usr/local/bin:/bin:/usr/bin
 +
 + [ -f /var/qmail/rc ] || exit 0
 +
 + start() {
 +     # Start daemons.
 +     if [ -z $(/sbin/pidof qmail-send) ];  then
 +         echo -n "Starting qmail"
 +
 +         # qmail
 +         csh -cf '/var/qmail/rc &' 2>&1 > /dev/null
 +
 +         # SMTP
 +         tcpserver -qv -l0 -HR -u `id -u qmaild` -g `id -g qmaild` \
 +         -x /etc/tcp.smtp.cdb 0 smtp \
 +         qmail-smtpd `hostname` /bin/checkpassword /bin/true 2>&1|\
 +         splogger smtp &
 +
 +         RETVAL=$?
 +         echo
 +         [ $RETVAL = 0 ] && touch /var/lock/subsys/qmail
 +         return $RETVAL
 +     else
 +         echo "qmail is already started"
 +     fi
 + }
 +
 + stop() {
 +     # Stop daemons.
 +     if [ ! -z $(/sbin/pidof qmail-send) ];  then
 +         echo -n "Shutting down qmail"
 +         /bin/kill $(/sbin/pidof tcpserver)
 +         /bin/kill $(/sbin/pidof qmail-send)
 +         until [ -z $(/sbin/pidof qmail-send) ] && [ -z $(/sbin/pidof tcpserver) ]; do :; done
 +         echo
 +         rm -f /var/lock/subsys/qmail
 +     else
 +         echo "qmail is not running"
 +     fi
 + }
 +
 + case "$1" in
 +   start)
 +         start
 +         ;;
 +   stop)
 +         stop
 +         ;;
 +   restart)
 +         stop
 +         start
 +         ;;
 +   status)
 +         if [ ! -z $(/sbin/pidof qmail-send) ] ;  then
 +             echo -n "qamil (pid"
 +             echo -n " `/sbin/pidof qmail-send`"
 +             echo -n " `/sbin/pidof tcpserver`"
 +             echo ") is running..."
 +         else
 +             echo "qmail is stoped"
 +         fi
 +         ;;
 +    *)
 +         echo "Usage: qmail {start|stop|restart|status}"
 +         exit 1
 + esac
 +
 + exit 0
$ sudo cp qmail /etc/rc.d/init.d/qmail
$ sudo chmod +x /etc/rc.d/init.d/qmail

■qmail起動
# /etc/rc.d/init.d/qmail start
# chkconfig qmail --add
# chkconfig qmail on
# chkconfig --list qmail

■Maildir 作成
# /var/qmail/bin/maildirmake Maildir   ## root
$ /var/qmail/bin/maildirmake Maildir   ## 一般ユーザー