Webは日々進化を続け、目まぐるしく変化し、次々と新しい技術が生まれています。一方、電子メールは昔からさほど変わっておらず、また、メールに取って代わるものも出てきていません。今後も電子メールは生き残って行くと思います。
筆者はそんなメールに焦点を当ててバウンスメール(エラーメール)解析専用のシステムを開発し、2010年3月に国産オープンソースソフトウェアとして公開しました。本稿はバウンスメール解析システム“ BounceHammer” (バウンスハンマー)を、その役割や特徴、導入方法、構成事例を中心に紹介します。
バウンスメールとは
バウンスメールとは、配信したメールや配信しようとしたメールが、何らかのエラーによって送信者に差し戻されたメールのことです。バウンスメールの他の表現としてエラーメール、リターンメール、不達メールなどと表記されることもありますが、本稿ではバウンスメールと表記します。
バウンスメールでは、メールの送信者(From)が“ MAILER-DAEMON” や“ Postmaster” として、件名(Subject)が“ Returned mail:see transcript for details” や“ Mail System Error - Returned Mail” などで返ってきます。
バウンスメールを放置すると...
その配信する量の大小にかかわらず、バウンスメールは確実に処理すべきであると筆者は考えています。バウンスメール処理を行わず、配信できないアドレスを放置していると、次に挙げるような不都合が生じます。
遅延の発生
メールサーバ管理者は、管理下のメールサーバにスパムが送られている、あるいは攻撃されていると判断した場合、Tarpitting[1] やGreylisting[2] 、そして接続の拒否という対応を採ります。多くの宛先不明アドレスに対していつまでも送信し続けると、このような対応を受けることになるでしょう。
前述の対策は、いずれも送信元のサーバにとってはメール配信の遅延につながるもので、フリーのWebメールなどでも、宛先不明が多く含まれている場合は、接続がたびたび拒否されることがを確認されています。宛先サーバの管理方針次第では、公開ブラックリスト(DNSBL[3] )に登録されることもあるでしょう。登録されると遅延の範囲は更に広がります。
遅延が発生してしまうと、配送完了までの時間がかかり、サーバリソースを無駄遣いしてしまう結果を招きます(図1 ) 。
図1 受信ブロックから遅延の悪循環
携帯電話宛での遅延/受信ブロック
日本国内の携帯電話宛メール配信では事情はもっと厳しくなります。送信するメールの宛先に宛先不明アドレス/ドメイン指定拒否になっているアドレスが一定の数/割合以上であると数分間、酷いときには1時間近くキャリアのメールサーバに接続できないという状況になってしまいます。これは受信ブロックと呼ばれていますが、その結果、大量の遅延が発生し、Webサイトにおけるメールの信頼性の低下、そしてユーザが離れ、売上が下るという事態にもなりかねません。
有効なメールアドレスの把握ができない
多くのメールを送信するWebサイトやメールマガジンでは、バウンス処理を適切に行い、配信ごとにメールアドレスの状態変化を把握するべきでしょう。さもなければ、どれほどのユーザにメールが配信できるのかが把握できない、メールサーバでの遅延発生頻度が高くなるといった問題が顕著になってきます。
メール本文内に広告を入れている場合は、配信可能なアドレス数が把握できていないと、広告の効果測定に用いる数値自体が信用できなくなります。送信できるアドレスと宛先不明で返ってくるアドレスが混在していると、配信時間もかかって非効率的です。
BounceHammerの特徴
バウンスメールは確実に処理すべき
前節ではバウンスメールを放置したことによるデメリットを述べました。筆者は配信するメール量の多少にかかわらずバウンス処理は確実に行うべきであると考えています。バウンス処理をすることによって、前述のデメリットはかなり解決[4] できます。
BounceHammerとは?
BounceHammerはオープンソースのバウンスメール解析システムです。バウンスメールを解析し、発信者アドレス/宛先アドレス/エラー理由/宛先分類/バウンス時刻などを構造化されたデータとしてYAML形式で書き出し、データベースに蓄積します。
ネットワークへの追加が容易
バウンスメール処理専用システムなので、ネットワークへの追加はBounceHammerをインストールしたホストを設置してバウンスメールを渡すだけです。
オープンソースのMTAに対応
BounceHammerはSendmail、Postfix、qmail、Exim、Courier-MTAの生成するバウンスメールに対応しています。これらのMTAは非常に多く使われているので、よほど特殊なMTAでない限り解析可能といえるでしょう。
エラー理由が正確にわかる
BounceHammerは、一般的なバウンスメールに加えて、日本の携帯電話主要キャリアのバウンスメールに対応[5] しています。BounceHammerでは、バウンスメールが返ってこない場合はエラーの理由を知ることはできませんが、携帯電話宛の宛先不明とドメイン指定拒否を区別して検出できます。表1 では、検出できる10種類以上のエラーのうち、実際の運用で重要なものを挙げています。
表1 おもなエラー理由
エラー理由(システム内での表記) エラーの説明
不明なホスト(hostunknown) @の右側が存在しないドメイン
宛先不明(userunknown) @の左側が存在しないユーザ
ドメイン指定拒否(filtered) メールアドレスは存在するが受信拒否されている
メールボックスいっぱい(mailboxfull) 宛先アドレスのメールボックスがいっぱい
メールが大きすぎる(mesgtoobig) 送信したメールのサイズがメールサーバの許容値を超えた
何らかのバウンスメールが返ってきたら、そのメールアドレスを配信不能なアドレスとして扱うという単純なバウンス処理を行った場合、“ メールボックスがいっぱい” や“ メールが大きすぎる” のようなエラーで宛先アドレスに配信不能フラグを立ててしまうという誤った対処をしてしまう危険性があります。
エラーになった理由ごとに適切な対処をすれば、メールアドレスの状態変化を管理しつつ、宛先不明アドレスの割合増加による遅延を回避ができます。検出できるエラーについての詳細は、http://bouncehammer.jp/features/engine/reason をご覧ください。
読みにくいバウンスメールを構造化する
BounceHammerは解析したバウンスメールの内容をYAML形式で出力します。YAML形式の解析結果は1行1レコードで書き出しているので、コマンドラインからcatで眺めたり、wcで行数計測することによって手軽に解析済みデータの確認が可能です。広く使われているYAML形式でデータを書き出すので、他のアプリケーションからも容易にバウンスした記録の参照ができます。
Webブラウザベースの管理画面
BounceHammerは基本的にコマンドライン上ですべての操作を行います。しかし、人間の目で内容を確認するには、やや見にくい点もありますし、バウンスの状況を確認するのはサーバにログインしてコマンドラインで操作する人ばかりではありません。
そこで図2 のようなWebブラウザベースの管理画面[6] を使えば、サーバにログインしない、あるいはコマンドラインに精通していない人でもバウンスメールの管理ができます。
図2 BounceHammerの管理画面
HTTPベースのAPI
BounceHammerはHTTPベースの簡易なAPIを持っていて、発信者アドレス(From)や宛先アドレス(To) 、宛先ドメインやエラー理由などを文字列としてURLに入れてアクセスし、その結果をJSON[7] 形式で受け取れます。図3 はcurlコマンドでAPIにアクセスしたときの実行結果です。APIを利用すると、Webサイトにバウンス記録の参照機能を短い開発期間で実装できます。
図3 HTTP-APIでJSON形式のデータを得る
< curl http://apitest.bouncehammer.jp/modperl/a.cgi/search/recipient/user01@example.org
[ { "bounced": 1234567890, "addresser": "sender01@example.jp", "recipient": "user01@example.org",
"senderdomain": "example.jp", "destination": "example.org", "reason": "exceedlimit", "hostgroup":
"reserved", "provider": "rfc2606", "frequency": 1, "description": { "deliverystatus": 500,
"diagnosticcode": "Example1", "timezoneoffset": "+0900" }, "token": "8dbb1b9ce9cc47eb6bb1316096c858cd" } ]
BounceHammerの構築と設定
BounceHammerの動作環境
BounceHammerの動作環境は次のとおりです。動作環境に関する詳細はhttp://bouncehammer.jp/environment をご覧ください。
*BSD、MacOSX、LinuxなどUNIX互換OS
Perl5.8.1以上といくつかのPerlモジュール
PostgreSQL、MySQL、SQLite3のいずれか
ライセンスはGPLv2またはPerlライセンスのどちらかで、2010年12月時点での最新版は2.6.2です。
BounceHammerの導入
本項では、図4 (BounceHammerを組み込んだ一般的な構成例)のような構成のネットワークにBounceHammerを組み込むことを前提とします。自社ドメインexample.jpのMXであるsmtp.example.jp(192.0.2.25)で受け取ったバウンスメールをaliasesでBounceHammerをインストールしたホストbh.example.jp(172.16.0.49)に転送し、解析結果をデータベースdb.example.jp(172.16.0.54)に蓄積するものとします。
図4 BounceHammerを組み込んだ一般的な構成例
なお図4のネットワークは、192.0.2.0/24をグローバルIPアドレスとして、172.16.0.0/24をプライベートIPアドレスとして扱っています。本稿では紙幅の都合上、構築方法の詳細まで説明できていませんので、導入する場合は、http://bouncehammer.jp/setup/install もご覧ください。
BounceHammerの構築
BounceHammerはconfigureを使って構築 します。configureをオプションなしで実行すると、インストール先は/usr/local/bouncehammerになります。また複数のバージョンのPerlをインストールしている場合、BounceHammerを動かすためのPerlを--with-perlで明示的に指定できます。おそらく、ほとんどのサーバでBounceHammerが必要とするPerlモジュールがすべて揃っていることはないでしょう。
図5 のように、configureを実行した時にエラーメッセージとともに表示されるモジュールをインストールして、再度同じオプションでconfigureを実行してください。必要なモジュールは、ソースアーカイブ同梱のModules.PLでも確認できます。必要なモジュールの他に、使用するデータベース用モジュール[8] も忘れずにインストールしてください。
図5 足りないモジュールをインストールしてconfigureを実行
root@172.16.0.49 # ./configure --with-perl=/usr/local/bin/perl
...
*** THE FOLLOWING PERL MODULES ARE REQUIRED ***
Class::Accessor::Fast::XS
Time::Piece
Term::ProgressBar
configure: error: *** 17 perl modules are missing
root@172.16.0.49 # cpan Class::Accessor::Fast::XS Time::Piece
root@172.16.0.49 # ./configure --with-perl=/usr/local/bin/perl
root@172.16.0.49 # make
root@172.16.0.49 # make test
root@172.16.0.49 # make install
[8] DBD::Pg,DBD::mysql,DBD::SQLiteのいずれかです。
BounceHammerの設定
データベースの準備
空のデータベースを作る
次にバウンスメールの解析結果データ蓄積用のデータベースを準備します。データベースはPostgreSQL、MySQL、SQLiteに対応しています。図6 はユーザ作成とデータベース作成の実行例です。
図6 空のデータベースを作成
postgres@172.16.0.54< createuser bouncehammer
postgres@172.16.0.54< createdb -Obouncehammer bouncehammer
postgres@172.16.0.54< psql -U postgres
postgres=# ALTER USER bouncehammer password '794-uguisu-heiankyo';
ALTER ROLE
テーブル作成と基本データ登録
続いて必要なテーブルの作成を行います。BounceHammerをインストールしたホスト172.16.0.49からデータベースホスト172.16.0.54へのアクセス権限は必要に応じて設定してください。テーブル作成用のSQLファイルはBounceHammerインストール先のshare/scriptにそれぞれ入っていますので、図7 を参考にしてください。
図7 PostgreSQLでテーブル作成
root@172.16.0.49 # cd /usr/local/bouncehammer/share/script
root@172.16.0.49 # cat PostgreSQL*.sql mastertable*.sql records-example.sql | \
< psql -U bouncehammer -d bouncehammer -h 172.16.0.54
設定ファイルの準備
bouncehammer.cf
bouncehammer.cfはBounceHammerの基本設定ファイル(YAML形式)で必須です。図8 の操作でサンプルファイルをコピーして、使用するデータベースにあわせてリスト1 のように編集します。データベースの項目以外は、とくに編集する必要はありません。
図8 bouncehammer.cfの準備
root@172.16.0.49 # cd /usr/local/bouncehammer/etc
root@172.16.0.49 # cp ./bouncehammer.cf-example ./bouncehammer.cf
リスト1 bouncehammer.cfの編集個所
database:
dbtype: 'PostgreSQL'
dbname: 'bouncehammer'
username: 'bouncehammer'
password: '794-uguisu-heiankyo'
hostname: '172.16.0.54'
port: 5432
webui.cf
続いてWebブラウザベースの管理画面(WebUI)用の設定ファイルを準備[9] します。準備は図9 のようにコピーするだけです。WebUIもHTTPベースのAPIも使用しない場合は、このファイルは不要です。
図9 webui.cfの準備
root@172.16.0.49 # cd /usr/local/bouncehammer/etc
root@172.16.0.49 # cp ./webui.cf-example ./webui.cf
WebUI用CGIの設定
WebUIを使う場合は、図10 のようにCGIスクリプトを実行可能なディレクトリに設置してください。設置するファイルは2つなので、ApacheのScriptAliasで指定されるディレクトリにコピーすると簡単でしょう。
図10 CGIスクリプトの設置例
root@172.16.0.49 # cd /usr/local/bouncehammer/share/script
root@172.16.0.49 # cp ./bouncehammer.cgi /usr/local/apache/cgi-bin/b.cgi
root@172.16.0.49 # cp ./api.cgi /usr/local/apache/cgi-bin/a.cgi
root@172.16.0.49 # chmod a+x /usr/local/apache/cgi-bin/{a,b}.cgi
管理するドメインの登録
BounceHammerは、データベースに登録された発信者ドメインに一致するバウンス記録だけを、データベースに蓄積するしくみになっています。図11 のように管理したい発信者(From)ドメインをデータベースに登録します。ここでは、BounceHammerをインストールしたディレクトリのbin/に入っているtablectlコマンドを使用し、自社ドメインexample.jpを例として登録しています。
図11 tablectlで発信者ドメインを登録する
user@172.16.0.49< cd /usr/local/bouncehammer
user@172.16.0.49< ./bin/tablectl --table s --insert --name 'example.jp'
バウンスメールを転送
図4では、ホストsmtp.example.jpがバウンスメールを受け取っています。解析を行うために、リスト2 のようなaliasesファイルを使って、バウンスメールをBounceHammerをインストールしたホストbh.example.jpに転送しています。
リスト2 ホストsmtp.example.jpの/etc/aliases(sendmail、postfix共通)
MAILER-DAEMON: postmaster
postmaster: root, bounce@bh.example.jp
BounceHammerはバウンスメールさえあれば解析できるので、SMTPで転送する以外にfetchmailやscpでメールボックスサーバから取得しても良いでしょう。
BounceHammerを使う
コマンドラインツール
BounceHammerは7つのコマンドラインツールですべての操作ができます。各コマンドラインツールの名前と役割は表2 のとおりです。それぞれのコマンドは多くのオプション[10] を持ち、コマンドラインの引数と標準入力のどちらからでもデータを受け付けます。一般的な使用方法は、メールの配信量や処理するバウンスの量に合わせて、/etc/crontab[11] で定期的に処理を行うと良いでしょう。各コマンドによる処理の流れはhttp://bouncehammer.jp/features/flow をご覧ください。
表2 各コマンドの名称と役割
コマンド名 コマンドの役割
mailboxparser バウンスメールを解析してYAML形式で出力する
logger 解析済みのYAMLファイルをバウンス発生日別にファイルに記録する
databasectl 解析済みのYAMLファイルを読込んでデータベースに記録する
datadumper データベースに登録されているバウンス記録を出力する
summarizer データベースに登録されているバウンス記録を集計して出力する
tablectl データベースのマスタデータを編集する(発信者ドメインの登録など)
messagetoken メッセージトークン(バウンス記録を識別する文字列)を生成する
他のシステムと協調する
BounceHammerはバウンスメール解析専用のシステムですので、Sendmail、Postfix、qmailなどのMTAでメール配信を行っていて、かつバウンス処理を行っていない場合、比較的短期間でバウンス処理のシステムを組み込めます。
システム自体はPerlで作られていますが、解析済みデータにアクセスする手段は、直接データベースに接続してSQLで行う、解析済みのYAMLファイルを読込む、API経由で参照[12] するなどいくつかの方法がありますので、WebサイトがPerl以外の言語で作られていても連動させることができます(図12 ) 。
図12 配信からエラー発生以降の具体的な処理の流れ
また、解析済みデータから宛先メールアドレスだけを取り出してMTAのaccessデータベース用に加工したり、CSVで出力して表計算ソフトで集計/分析をするという使い方もあります。
悪循環から好循環へ
BounceHammerでバウンスメールの処理[13] を日常的に行うと、本項前半で述べた悪循環から、次のような好循環に転じることが可能です。
① メール配信後に毎回バウンス処理をする
② 日々のバウンス記録を蓄積する
③ 配信時に前回配信できなかったアドレスは配信対象から除外
④ ①に戻る
配信後に毎回確実にバウンス処理をし、次回の配信に反映させることによって、次第にバウンスの発生が抑制され、配信に要する時間も必要最低限で済むようになり、宛先不明アドレスの発生は、前回信してから次回に配信するまでの間に増えたユーザ数に応じた一定範囲の割合に落ち着きます。
BounceHammerの今後
BounceHammerはまだ登場して間も無いシステムですが、数十万~百万のメールマガジンや通信販売サイト、大規模な無料のWebサービスなどで導入頂いています。今後の課題として、対応できるバウンスメールの種類を増やすための解析精度の向上と、大量のバウンスメールを高速に解析するためのシステムの更なる軽量化を予定しています。
本稿ではBounceHammerの詳細な部分についての紹介ができませんでしたが、バウンス処理を必要としている方や頻繁にメール配信をしている方、そしてBounceHammerに興味を持っていただいた方は、是非BounceHammerのWebサイトhttp://bouncehammer.jp/ をご覧ください。BounceHammerがみなさまのバウンス処理に役に立てれば幸いです。