procmail


procmail は受信したメールをチェックして、自動的にディレクトリに振り分けてくれるツールです。 単純なメールの振り分け以外にも、フィルタリングのベースツールとして利用可能です。

インストール手順の説明は省略します。ports の mail/procmail からインストールするなり、 packages からインストールするなり、ソースからコンパイルするなりしてください。

1. .forward の設定

procmail は .forward から起動されます。

システム管理者のポリシによっては、ローカルメイラを procmail に置き換えている所もあるかと思います。 その場合は .forward に何を書いても無意味です。.procmailrc が存在すれば、 その記述に従って procmail の処理が走ります。

.forward に procmail を起動するよう指示を記述しておきます。 単純な方法なら


  "|exec /usr/local/bin/procmail"

で十分ですが、しっかりやりたいなら


  "|IFS=' ' && p=/usr/local/bin/procmail && test -x $p && exec $p -Yf- || exit 75 "

とでもしてください。

これで、受信したメールの内容が procmail に渡ります。

2. .procmail の設定

procmail の動作は ~/.procmailrc に記述します。 以降、.procmailrc の記述内容ついて説明していきます。

3. 環境変数

まずは環境変数の設定を行います。PATH, MAILDIR, LOGFILE が設定できます。 PATH はその名の通り PATH の設定です。.procmailrc 内でコマンドを起動する場合、 この PATH に従ってサーチされます。

MAILDIR はメールボックスのパスです。Mew や MH などで使っている MH 形式のメールボックスが存在するフォルダを指定すると、 ここにリファイルされます。

LOGFILE は procmail のログが残るファイルです。必須ではありませんが、 メールをロストしてしまったり、といった事故が起こるかもしれませんので、 念の為ログを残しておいた方が良いでしょう。

僕のところでは、こんな感じに設定しています。


  PATH=/bin:/usr/bin:/usr/local/bin:$HOME/bin
  MAILDIR=$HOME/Mail
  LOGFILE=$HOME/.mail/log

ホームディレクトリは $HOME で参照できます。

4. レシピの書き方

.procmailrc 内でのメール処理のルールのことをレシピと呼びます。 このレシピを書いてやることで、該当するメールをどのように処理するかを設定します。

レシピの書式は以下のようになります。


  :0 [flags] [:[lockfile]]
  * condition
    (任意の数の condition が続く)
  action

:0 がそのレシピの始まりを示します。condition の部分にメールを識別するためのパターンを記述します。 このパターンにマッチしたメールに対して action で指定した処理が行われます。 これが基本的なレシピの書式です。

5. リファイル

以下は最も単純なレシピの例です。


  :0
  * ^Subject: .*TESTMAIL.*
  test/.

この例は『Subject フィールドに TESTMAIL という文字列が含まれるメールを $HOME/Mail/test/ 配下にリファイルする』というレシピです。 3 行目の test/. というのは『test というディレクトリ配下に MH 形式でリファイルする』 という意味になります。MH 形式のメールボックスでは、それぞれのメールに数字のファイル名を付けますので、 この場合、test/ 配下にあるファイル名のうち最も大きい数字を持つファイル名に 1 を加えた値をファイル名として採用します。 この場合、メールが到着した時点で test/ ディレクトリにリファイルされていますので、 POP 経由で新規に受信することはありません。

MH 形式ではなく mbox 形式でリファイルする場合は、3 行目を『test』とだけ書きます。 これで test というメールボックスにリファイルされます。

condition で指定する条件は複数記述することが出来ます。例えば


  :0
  * ^Subject: .*TESTMAIL.*
  * ^From: .*foo@example.com.*
  test/.

とすれば、『Subject フィールドに TESTMAIL という文字列が含まれ、 かつ From フィールドに foo@example.com という文字列が含まれる』メールが対象となります。


  :0
  * (^Subject: .*TESTMAIL.*|^From: .*foo@example.com.*)
  test/.

というように記述すれば 『Subject フィールドに TESTMAIL という文字列が含まれているか、 または From フィールドに foo@example.com という文字列が含まれる』メールが対象となります。

『.*』は正規表現です。『.』は任意の 1 文字に match します。 『*』は直前の表現の 0 回以上の繰返しに match します。

6. ロックファイル

ロックファイルの指定はレシピの先頭行で行います。 : 以下がロックファイル名ですが、ファイル名を指定しない場合、 action が実行されるファイル名に .lock という文字列を付けたファイルをロックファイルとして作成します。


  :0 :
  * ^Subject: .*TESTMAIL.*
  test/.

このように記述すると、このレシピにマッチした場合はロックファイルが作成され、 このレシピにマッチするメールが複数同時に処理されようとした場合にも、 排他制御が行われます。

7. c フラグ

c フラグを指定することで、そのメールに対するコピーを作成します。 例えば


  :0 c
  * ^Subject: .*TESTMAIL.*
  test/.

というレシピにマッチした場合、そのメールは test というディレクトリにリファイルされますが、 同時にコピーが作成され、そのコピーが次のレシピへと渡っていきます。 最終的にそのコピーが以降のレシピにマッチしなかった場合、そのメールはメールスプールに蓄積されます。

反対に c フラグを指定しない場合は、最初のレシピにマッチした時点で、 そのメールに対する処理が終わり、メールスプールに蓄積することはありません。

8. 重複メールの削除

メーリングリスト等に参加している場合、To: が自分のメールアドレスで、 Cc: が自分が参加しているメーリングリスト、というリプライを受け取ることがしばしばあります。 この場合、同一の Message-ID を持つメールを 2 通受け取ることになりますが、 procmail ではこのような重複メールを自動的に削除することが出来ます。

そのためには procmail の配布物に含まれる formail というコマンドを利用します。 formail で同一 Message-ID のメールを削除するには、以下のようなレシピを書いておきます。


  :0 Wh: msgid.lock
  | formail -D 8192 msgid.cache

この例では condition は指定されていませんから、全てのメールがこのレシピにマッチします。 action の先頭が『|』(パイプ)で始まっていますが、 『この場合は続くコマンドを起動する』という意味になり、指定したコマンドにメールが渡されます。

この例では msgid.cache というファイルにこれまで受信したメールの Message-ID を蓄積しておき、同一の Message-ID を持つメールが渡されてきた場合、 そのメールを破棄します(-D オプション)。8192 という引数は msgid.cache というファイルを 8192 byte まで蓄積する、という上限値です。

レシピの先頭で『W』というフラグと『h』というフラグを指定しています。 W フラグは実行するコマンドの完了を待ち合わせ、かつ、 コマンドが出力するエラーメッセージを無視する、という意味です。 コマンドの完了を待ち合わせるだけなら『w』フラグを指定します。

h フラグは『条件にマッチしたメールを action に送る』 という意味で、このフラグはデフォルトで設定されています。

このレシピを .procmailrc のレシピの先頭に記述し、 msgid.cache というファイルを touch しておけば、重複メールを削除することができるので便利です。

9. procmail の応用

以上が基本的な procmail の使い方の説明です。 UNiX MAGAZINE 1998 年 10 月号に詳細な説明記事が掲載されていますんで、 より詳細な情報はそちらを当たってください。

| 指定でコマンドを記述することができるので、procmail を振り分けの入り口にだけ使い、 そこから先は、自分で書いたスクリプトを用意して、より複雑な処理を行うといった応用が可能です。 僕は普段から個人宛のメールの From フィールドと Subject フィールドの内容をケータイ電話に通知するようなスクリプトを自分で書いて利用しています。 自宅が常時接続環境ではないため biff 代わりに活用しています。

また、以前、学生からのメールでのレポートに対して、 受け取った旨、元メールを引用して返信するようなスクリプトを(退屈しのぎに)書いて、 他人にあげたこともあります。

このように procmail をベースとして、様々な応用が可能ですが、 これをやり始めると、段々、自分自身で procmail 部分を実装してしまいたくなってくるので、 注意が必要です ;-p


tetSTREAMS > FreeBSD > procmail