メールの流量を調べる

メールサービスの将来像を検討するための材料として、現在のメール流通量を調べるべくチャンレンジ。

全部のバイト数

Solarisの場合、sendmailのログは/var/log/syslogにでます。調べたい月のログを抜き出してから全部のメールの流通量を調べるにはこんな感じ。

# grep '^Nov' /var/log/syslog* | mm.pl

mm.plの中身はこんなの。

#!/usr/local/bin/perl

while(<>){
    if (/, size=(\d+)/ ){
        $total_size += $1
    }
}

print $total_size ;

簡単だなぁ。私が管理している環境では受信用に3台、発信用に1台のサーバがあるのでそれぞれで実行して電卓を叩けば答えがでます。

でも

受信用のサーバではスパムフィルタを実施しています。スパムフィルタにひっかかったメールの流量は除きたい。すこし前に調べたところ、すべてのSMTPコネクションのうち、約70%はスパムとして扱っています。だからすべての流通量×0.3でいいかなと考えましたが、せっかくなのでちゃんと計算することに。ちょっと考えてこんなステップを踏むことにしました。

  • 全部のメールIDとSPAMチェックにひっかかったメールIDをそれぞれ調べる。
  • 上記の2つの差分を取ってスパムチェックにひっかからなかったメールIDを調べる。
  • このメールIDが含まれたログからサイズを計算する。

実際にやったことは

まずすべてのメールIDを抜き出します。nov_syslogには11月分だけのログが含まれています。

$ ./mmm.pl nov_syslog | sort -u > spamid.log

mmm.plの内容はこんなの。正規表現で引っ掛けます。定義あってるのかな。

#!/usr/local/bin/perl

while(<>){
    if( / ([a-zA-Z\d]{14}): / ){
        print $1 ,"\n";
    }
}

続いてSPAMチェックにひっかかったメールのIDを調べます。SpamAssassinをMimedefangと組みあわせて、ヘッダにタグをつけている運用をしています。この場合、スパムチェックにひっかかったメールはこんな風にログ出力されます。

Nov 24 03:10:12 hogehoge sendmail[3959]: [ID 801593 mail.info] lANIA0pjXXXXXX: Milter change: header Subject: from  Re: to =====SPAM===== Re:

SpamAssassinSPAM判断されるとヘッダ中のSubjectを書き換えて"=====SPAM====="を頭につけます。なので、perlに書く抽出条件はこんな感じ。

#!/usr/local/bin/perl

while(<>){
    if( / ([a-zA-Z\d]{14}): Milter change: header Subject:/ ){
        print $1 ,"\n";
    }
}

これをmmm.plに書き込んで先ほどと同じように実行。

$ ./mmm.pl nov_syslog | sort -u > allspam.log

差分を取ります。

$ diff allspam.log allid.log | grep '^[<>]'  | sed -e 's/^[<>] //' > ham.log

と、ここまでやってそのIDがなんと50万もあることがわかった。syslogからそのIDが含まれている行をどうやって抜き出すのがいいんだろう。
もちろんシェルでこうやって抜き出すこともできるけど、

for i in `cat ham.log`
do
    fgrep $i nov_syslog >> nov_syslog.ham
done

とりあえずはこれで抜き出しを実施しつつ、スマートな方法ないか考えよう。