maildrop 利用のメモというかtips

最終更新日: 2006年6月17日
文責: 柳澤 佳里

はじめに

これは maildrop利用者の助けとなればと思い作成した文書である。 maildropは文法が一般に普及してるプログラミング言語であるC言語や JavaPerl に近く、一般のプログラマーにとって理解しやすいと考えられる。 また、maildropは他のMDA(メール配送エージェント)と違い近代的な Maildir ファイル名命名規則を使っておりファイル名の衝突によるメールの消失が 非常に起きにくくなっている。 さらに、maildropのソースコードは洗練されていて非常に読みやすく、 それだけでプログラムにあるバグの量は少ないように思われる。 しかし、これだけの利点を持ちながらmaildropは日本で普及しているとは言いがたい。 そして、これには日本語のドキュメントの不足が原因であると思い、 この文章を認めた次第である。


Table of Contents


簡単な振り分けルールの例

maildropによる振り分けルールの例を示す。

振り分け例の前準備

まず、maildropを使うようにする設定について述べる。 maildropはSendmail, Postfix, qmailのローカル配送エージェントから呼び出すように する必要があり、次のような設定を.forward(Sendmail,Postfix)あるいは.qmail(qmail) に書く必要がある。 /usr/local/bin/maildropにmaildropがある場合は次のように記述する。

SenamailやPostfixの場合:
~/.forwardに次のように記述する。
--
"|/usr/local/bin/maildrop"
--

qmailの場合:
~/.qmailに次のように記述する。 (chmod go-rwxする必要がある)
--
|/usr/local/bin/maildrop
--

次に、以下の振り分けルール例の前に~/.mailfilterに定義しておくべきルールを示す。 maildropはDEFAULTやMATCHなど予約されている変数の他は 自由に変数を定義することができる。
以下ではMAILDIR変数を自分のホームディレクトリ下のMaildirディレクトリに設定し、 MAILDROP変数をホームディレクトリ下の.maildropディレクトリに指定している。 そして、MAILDROP変数はその下のログファイル指定時に利用している。
その下のlogfileというコマンドは引数としてファイル名をとって、 そのファイルにmaildrop実行時のログを吐かせることができる。
ちなみにshellやPerlと同じで#以下の文はコメントとして扱われる。 なお、.mailfilterのパーミッションはchmod 600 (あるいは、chmod go-rwx) しておかないとmaildropが異常終了するので注意すること。

MAILDIR="$HOME/Maildir/"	# MAILDIR変数として$HOME/Maildir/を設定
DEFAULT=$MAILDIR
MAILDROP="$HOME/.maildrop/"	# MAILDROP変数として$HOME/.maildrop/を設定

logfile "${MAILDROP}maildrop.log"	# ログの出力先を設定

メーリングリストの振り分け その1

maildropの振り分けルールは正規表現で記述できる。
例えば次のルールはToやCcにFreeBSD-users-jp@jp.FreeBSD.orgが含まれている 場合にマッチしてMaildir形式のディレクトリである Maildir/.FreeBSD-users-JP/ディレクトリ下にメールを保存する。
なお、マッチングルールに付いている:hというのはヘッダーのみにマッチする ということを示していて、toというのは引数のディレクトリ、あるいは ファイルにメールを格納してマッチングを打ち切ることを示す。
ちなみにtoの代わりにccと書くとマッチングを打ち切らずに下のルールに付いて も評価を行う。

# FreeBSD-users-jp
if (/^(To|Cc):.*FreeBSD-users-jp@jp.FreeBSD.org/:h)
{
	to "$MAILDIR.FreeBSD-users-JP/"
}

メーリングリストの振り分け その2

メーリングリストによってはList-IdやSenderがヘッダに入っている場合があるが、 これの振り分けルールは次のようになる。
maildropのルールはshellのように"\"によって折り返したり、 PerlやC言語のプログラムのように||や&&で条件のorをとったりandをとったり することができる。
下記のプログラムはList-Idにfreebsd-announce.freebsd.orgを含むものか Senderにowner-announce-jp@jp.FreeBSD.orgを含むものにマッチし、 マッチしたものはMaildir/.FreeBSD-announce/以下に配送される。

# FreeBSD-announce
if (/^List-Id:.*freebsd-announce.freebsd.org/:h \
	|| /^Sender: owner-announce-jp@jp.FreeBSD.org/:h)
{
	to "$MAILDIR.FreeBSD-announce/"
}

送信者による振り分け

同様にして送信者による振り分けも可能である。
下記の例はmailman-owner@freebsd.orgから来たメールを Maildir/.FreeBSD.mailman/ディレクトリ下に配送する。

if (/^From: mailman-owner@freebsd.org/:h)
{
	to "$MAILDIR.FreeBSD.mailman/"
}

転送

ディレクトリ名やファイル名を書くところに『! メールアドレス』と書くことで 転送が行える。
下記の例はfoo@example.ne.jpにメールを転送し、 Maildir/にも配送するという例である。 これは、~/.forwardに『\ユーザー名,foo@example.ne.jp』と記述した場合と 同じ意味になる。

cc "! foo@example.ne.jp"
to "$MAILDIR"

振り分けルールまとめ

ここで、上記で紹介した振り分けルールをまとめる。 上記では振り分けルールの中で変数が使える事、 振り分けルールを正規表現で記述する事、 to,ccの使いかた、Maildirへの配送の仕方を例示した。

変数の使いかた

上記の振り分けルールではmaildropにあらかじめ定義されている変数と ユーザ定義の変数との両方を用いた。 まず、上記の例で用いたmaildropに定義されている変数を紹介する。
HOME: ホームディレクトリを示す
DEFAULT: デフォルトの配送先を示す
ホームディレクトリとはUnixでログインした時に行くディレクトリで、 Maildirを利用している場合は通常、このホームディレクトリの下に Maildirディレクトリが作成される。 変数の使いかたはShellでの利用と同じで参照する時は$を付け、 代入する時は=で行い、代入先には$をつけない。 この点はPerlなどとは異なっているので注意が必要である。 例えば、次のようになる。
DEFAULT="$HOME/Maildir/"

to, ccの使いかた

toもccも次のような文法で使用され、メールの転送を表す。
to "配送先"
cc "配送先"
これらの違いはtoの場合は指定された配送先に送り、そこから下に書いてある処理を 行わないのに対し、ccの場合は指定された配送先に送った後に下に書いてある 処理を続けるということだ。C言語やJavaのプログラムで例えると、 次のようにいえるかも知れない。
to: send("配送先");return;
cc: send("配送先"); /* 終了せず、続きを実行 */
この配送先はファイル、ディレクトリ(Maildir形式)、メールアドレスが選べる。 ファイル、ディレクトリの場合は配送先 としてファイル、ディレクトリの名前を書き、メールアドレスの場合は 配送先として"!メールアドレス"と 最初に!を付けて記述する。
なお、Maildirディレクトリに配送する場合はあらかじめMaildir形式でディレクトリを 作成しておかなくてはならない。 例えば/var/mail/yanagisawa、ホームディレクトリのMaildir、 yanagisawa@example.comに転送する場合は次のようになる。
cc "/var/mail/yanagisawa"
cc "${HOME}/Maildir/"
cc "! yanagisawa@example.com"

ifの使いかた

振り分けルールにはif文が使える。 if文に寄りメールのヘッダや本文を判定し、配送先を変更する。
上記の例ではメーリングリストに付記されるヘッダや送り主(From)や 送り先に基づいて振り分けをするやりかたに付いて述べた。 これらの例で/.../:hとルールの最後に:hが付いていたと思うが、 これはルールをヘッダにのみ適応するという意味である。
これの他に本文のみに適応するという意味の:bなどがある。
なお、if文を用いて複数行に渡る場合は{や}を 使う所で{、}しか無い行を作らなければならない。
悪い例:
if (...) { # if文と同じ行に{がある
    cc "example@example.org"
    to "example@example.gr.jp"
} else { # elseと{や}が同じ行にある
    to "example@example.net"
}


良い例:
if (...)
{
    cc "example@example.org"
    to "example@example.gr.jp"
}
else
    to "example@example.net"

CプログラマはK&R風にif (...) {と同じ行にifと{とを書きたい所ではあるが、 これをやるとエラーになる。 ちなみに、C言語やJavaなどと同じで、if文のbodyが1行の場合は{}を省略する事ができる。

xfilter

xfilterは以上の例では登場していないが、以下の例で登場するので説明しておく。
xfilterとは標準入力にメールの本文を受け取り、標準出力から処理した結果を 出力するプログラムを指定する命令で、フィルタを呼び出すのに使う。
例: メールヘッダにループチェックのためのフィールドを追加する
MAIL_ADDRESS="example@example.co.jp"
LOOP_CHECK_FIELD="X-LOOP-CHECK: $MAIL_ADDRESS"
if (/^$LOOP_CHECK_FIELD/:h) # ループしていたら配送せず捨てる
    to "/dev/null"

xfilter "reformail -A'$LOOP_CHECK_FIELD'"
下記の例ではbogofilterやcheck_uri.plを紹介しているが、 どちらのソフトも標準入力より電子メールの内容を受け取り、 標準出力から判断結果を返す。
例えば、check_uri.plはプログラムを通すとX-URIRBLというフィールドが ヘッダに増え、そこに電子メールがspamだったかが出力される。
そして、この内容を元にif (/X-URIRBL: .../)というようなルールを書く事で spamを振り分けることができる。

bogofilter と連携してspam(UBE,UCE)を排除

bogofilterはC言語で書かれた高速に動作する Bayesian Spam Filter (ベイズ統計学を利用した迷惑メールフィルター)である。 そして、利用できるアルゴリズムの数は他のベイズ統計学を利用した フィルターと遜色が無い。 しかし、日本語の単語をトークンとして認識してくれないため わかち書きをして日本語の単語をトークンとして認識させる必要がある。

spamメール、非spamメールの登録

Bayesian Spam Filterを使う場合はどのソフトでも まずspamと非spamの登録を行う。 登録の仕方は英文メールに対するbogofilterの使い方と わかち書きを行うという箇所が異なっている。
そして、それは次のように行う。

Spamの登録: ((t)cshの場合)
まず、Spam_dirの下にこれまで受け取ったspamを1メール1ファイルに分割して入れる。
- Spam_dirの下に移動
% cd Spam_dir
- Spam_dirのファイルをわかち書き後、bogofilterに投入
% foreach i (*)
> cat $i | nkf -Zme | kakasi -wakati | bogofilter -sv
> end
以上でSpamの登録は完了である。

非spamの登録: ((t)cshの場合)
まず、NonSpam_dirの下にこれまで受け取ったspamではないメールを1メール1ファイルに
分割して入れる。
- NonSpam_dirの下に移動
% cd NonSpam_dir
- NonSpam_dirのファイルをわかち書き後、bogofilterに投入
% foreach i (*)
> cat $i | nkf -Zme | kakasi -wakati | bogofilter -nv
> end
以上で非spamの登録は完了である。
なお、わかち書きにchasenmecab を使いたい場合は上記のkakasi -wakatiを chasen -F "%m "やmecab -O wakatiに書き換えれば良い。
また、手前味噌であるがわかち書きではなくbigramを使いたい場合のために bigram.plというスクリプトを用意した。 これを使う場合はbigram.plの先頭の行のPerlのパスをシステムのPerlのパス (/usr/bin/perl等)に変更した上で上記のkakasi -wakatiのところを bigram.plのように書き換えてこのプログラムを呼び出すようにすれば良い。
ちなみに、bogofilterの引数のオプションは-sでspamの登録、 -nで非spamの登録、-vは経過の表示を表している。

以上の操作をbogofilterと同じように行いたい場合は次のようなshell scriptを 用意するとほとんどできる。
しかしながら、これは標準入力以外からメールが入る場合には対応していない。
#!/bin/sh
BOGOFILTER="/usr/local/bin/bogofilter"
BOGOFILTER_OPTION="$*"
NKF="/usr/local/bin/nkf"
NKF_OPTION="-Zme"
WAKATI="/usr/local/bin/kakasi -wakati"
 
cat | ${NKF} ${NKF_OPTION} | ${WAKATI} \
        | ${BOGOFILTER} ${BOGOFILTER_OPTION}

maildropでの設定

maildropで使う場合にはまずわかち書きをしたものをbogofilterに通す。 そして、そのときのbogofilterの結果(X-Bogosity)をreformailで 取り出し、本体に書き込むという手順を踏む。
このときbogofilterをxfilterとして適用せずに``で適用するのは わかち書きにより単語が空白で区切られているメールが送信されるのを 防ぐためである。
このときの.mailfilterは次のようになる。
NKF="/usr/local/bin/nkf"
NKF_OPTION="-Z -mS -e"
FORMAIL="/usr/local/bin/reformail"
WAKATI="/usr/local/bin/kakasi -wakati"
BOGOFILTER="/usr/local/bin/bogofilter"
BOGOFILTER_OPTION="-e -p -u"
BOGOHEADER=`${NKF} ${NKF_OPTION} | ${WAKATI} \
        | ${BOGOFILTER} ${BOGOFILTER_OPTION} \
        | ${FORMAIL} -X '^X-Bogosity:'
 
xfilter "${FORMAIL} -i '${BOGOHEADER}'"
if (/^X-Bogosity: Yes/:h)
{
    to "迷惑メール用メールボックス"
}
なお、chasenやmecabをわかち書きに使用したい場合や 本サイトで配布しているbigram.plを使用したい場合は 上記のWAKATIの箇所をそれぞれ次のように書き換えれば良い。
Chasenの場合:
WAKATI="/usr/local/bin/chasen -F "%m "

Mecabの場合:
WAKATI="/usr/local/bin/mecab -O wakati"

bigram.plの場合
WAKATI="/bigram.plを保存したpath/bigram.pl"
ちなみにbogofilterのオプションである-eはエラーが起きなかった場合に 終了コードに0を返すというオプションで、-pは入力されたメールに bogofilterのヘッダをつけて出力するオプションであり、 -uは今回のメールを判定結果に基づきデータベースに登録するという オプションである。

参考文献

check_uri.pl と連携してspam(UBE,UCE)を排除

check_uri.pl とは

check_uri.plとは RBL.JPのurl.rbl.jpを用いて迷惑メールを排除するためのソフトである。 これは電子メールの内容に基づいてurl.rbl.jpに問い合わせ、 その電子メールが迷惑メールか否かを判定する。 そして、迷惑メールと判定した場合にはヘッダにX-URIRBL: Yes,...という文字列を 付記する。なお、迷惑メールでないと判定した場合にはX-URIRBL: No,...という 文字を付記する。
迷惑メールにはメールを受け取った人を出会い系サイトや商品購入サイトに 誘導するものが多い。そして、それらの迷惑メールには必ずそれらの出会い系 サイトや商品購入サイトへのリンクが入っている。url.rbl.jpはそのようなサイトを 登録してあるブラックリストであり、check_uri.plはメールの本文からリンク文字列を 取り出してurl.rbl.jpに問い合わせる事でそのようなサイトへのリンクが 無いか調べ、迷惑メールか否かを判定している。
なお、check_uri.plはここから得る事が出来る。
http://www.is.titech.ac.jp/~yanagis0/text/check_uri.html

maildropでの設定

check_uri.plについての説明は 配布ページに頼る事にしてここではmaildropでの設定方法を述べる。
check_uri.plはフィルターとして作成してあるため、次のように設定すると 利用する事が出来る。
xfilter "/<check_uri.plを置いた場所>/check_uri.pl"
例えば、/usr/local/bin/check_uri.plに置いた場合は次のように設定する。
xfilter "/usr/local/bin/check_uri.pl"
if (/^X-URIRBL: Yes,/:h)
{
    to "迷惑メール用メールボックス"
}

ウィルス対策ソフトと連携してウィルスを排除

前準備

この章の説明には、GPLのウィルス対策ソフトである ClamAVを用いている。ClamAVはFreeBSDやNetBSD、LinuxなどのPC Unixにパッケージ として用意されていることが多いため、このソフトのインストール方法に付いての説明は 割愛する。
この説明ではclamdscanというコマンドの標準入力としてメールを送り込み、 ウィルスチェックを行う。 ClamAVにはパターンファイルをあらかじめ読み込んでいるデーモン(clamd)に ファイルを調査してもらうclamdscanというコマンドと、実行する時にパターンファイルを 読み込むclamscanというコマンドが用意されている。このうち、clamdscanはデーモンの 実行ユーザーに読めるようにしてあるファイルしか調査できないがパターンファイルを 起動時に読み込まないのでそれだけ高速にウィルススキャンをはじめる事が出来る。 今回、標準入力から調査するファイルを与えるため、起動が高速なclamdscanを使う事にした。
clamdscanで調査を行うにはあらかじめclamdを起動しておく必要がある。 起動の方法はOSによって異なるが、FreeBSDの場合はclamav_clamd_enable="YES"を /etc/rc.confに記述すると良いだろう。他のOSについても、それぞれのOSあるいは パッケージの方法でOS起動時に起動するように設定して欲しい。 また、freshclamにより、パターンファイルを常に最新のものに保つために、 こちらもclamd同様、OS起動時に起動するようにする事が望ましい。 こちらも、clamav_freshclam_enable="YES"と/etc/rc.confに書き込むと良いだろう。 (FreeBSDの場合)

maildropでの設定

以上の準備を終えると、次のような設定でclamdscanをmaildropから呼び出し、 ウィルスチェックをする事が出来る。
CLAMSCAN="clamdscan"

`${CLAMSCAN} - `
if ($RETURNCODE == 1)
        to "ウィルス感染メール用メールボックス"
これは、ウィルスに感染していた場合にclamdscanが終了コード1で終了する事を 利用している。 なお、toで指定する宛先を/dev/nullとしておくと、メールを自動的に捨てる事ができる。
感染していたウィルスの情報をファイルに残すには、次のように設定する。
FORMAIL="/usr/local/bin/reformail"
SCANHEADER="X-Virus-Scan"
CLAMSCAN=clamdscan
GREP=grep
SED=sed

TMPFILE="$$_$TIME.tmp"
`$CLAMSCAN - > /tmp/$TMPFILE || true`
SCANSTATUS=`cat /tmp/$TMPFILE | ${GREP} 'stream' | \
        ${SED} "s/stream/$SCANHEADER/"`
`rm /tmp/$TMPFILE`
xfilter "${FORMAIL} -i '$SCANSTATUS'"
if (! /^${SCANHEADER}: OK/)
        to "ウィルス感染メール用メールボックス"

Valid XHTML 1.1!
Copyright > All rights reserved.