bounceHammer has been EOL'ed on February 29, 2016

製品ライフサイクルの終了

2010年3月にオープンソースソフトウェアとして公開して以来、多くのユーザ様・企業様にダウンロードし、 ご利用いただきましたbounceHammerは、2016年2月29日(月)を持ちまして製品ライフサイクルの終了(EOL: End Of Life) となりました。長きにわたりbounceHammerをご使用いただき誠に有り難う御座いました。 開発元では後継となるバウンスメール解析ライブラリとして、より高精度で高速なSisimai(シシマイ) を二条項BSDライセンスで公開しています。

Sisimai
商用サポート

  • 1一式導入・設定・保守・開発の補助
  • 2独自MTA用解析モジュールの開発
  • 3個別案件の対応とメールサポート
  • 4バウンス管理・運用コンサルティング
  • 5スポット解析・解析済みデータ提供

Webサイトにバウンス照合機能を実装する

2010/11/08

HTTP-APIを使ってバウンスしたアドレスを照合する

通知関係の連絡を電子メールで配信するWebサービスでは、無料でサイトが利用できるかわりに広告も表示される、 あるいは定期的に広告を含んだメールを受け取る、というユーザ側が負担すべき部分があります。

しかし、特に携帯電話では多いと思いますが、ユーザがメールアドレスを変更したり、 ドメイン指定拒否の設定解除を忘れていたりして、 配信したメールが到達できないという状態にあるユーザも多々いるのではないでしょうか。

多くのユーザは自分のメールアドレスを変更しても、登録しているサイト側で変更手続きを 忘れてしまっているでしょう。サイト運営側としては登録アドレスの変更もしてほしい所ですが、 メールはバウンスしてしまうので、その旨を通知する手段としてはユーザのログイン後の 画面ぐらいしかなさそうです。

前置きが長くなりましたが、Webサービスの中でbounceHammerが解析した結果を照合する簡単な例を紹介します。 HTTP-APIはブラウザでも動作の確認ができます。

実装するコード参考例(メールアドレス)

 

bounceHammerのHTTP-APIはJSONで出力します。 これはWebサイト側でJavascriptでも処理できるようにするためです。 bounceHammerが出力する解析結果のデータはYAMLでもJSONでも同一の 内容・フィールド名(Key)ですので、既にYAMLを読み込んで照合するコードを書いている場合は、 ほぼ修正する事なく再利用できるでしょう。

APIを使う理由

メールアドレスの照合は、 YAMLファイルでアドレス照合 でも紹介しているように、解析結果のYAMLファイルを読込んで逐一照合する方法もあります。 しかし、Webサービスの画面内に表示させるためだけに大量の解析結果を含むYAMLファイルを 読込ませるのは非効率的です。

そこで、指定したメールアドレスに一致する解析結果だけを取得できるAPIを使うと、 ユーザ毎に必要なデータだけを取得し、必要な部分だけをユーザの画面に表示させる という効率的な照合が可能です。

HTTP-API/SEARCHを使って照合する

最も簡易なAPIを使ったアドレス照合用のサンプルコードは、 bounceHammerのソースアーカイブ/examples/request-to-api.* に同梱しています。

Perl, PHP, Python, Rubyの四種類を用意していますが、JSONを読込める・JSONを読込めるライブラリ がある言語であればなんでも実装できるでしょう。

つまり、Webサイト側がどのような言語で書かれていてもJSONが読込めればアドレス照合機能を実装できる、 というわけです。ここではHTTPベースの API(search)を使ってみます。

#!/usr/local/bin/perl
use strict;
use warnings;
use LWP::UserAgent;
use JSON::Syck;
use Time::Piece;

my $maildomain = 'example.jp'; # Webサイトのメールドメイン
my $bounce = {}; # テンプレートに渡すORページに表示する元データ用
my $message = q(); # 表示する文言
my $siteuser = ユーザデータのオブジェクトを作る;
my $httphost = 'http://192.0.2.25/bouncehammer/a.cgi';
my $useragent = new LWP::UserAgent();
my $response = $useragent->request( HTTP::Request->new(
     GET' => $httphost.'/search/recipient/'.$siteuser->mailaddress() ));
my $metadata = JSON::Syck::Load($response->content()) || [];

foreach my $j ( @$metadata )
{
  if( $j->{senderdomain} eq $maildomain )
  {
    $bounce = {
      'reason' => $j->{reason},
      'date' => Time::Piece->new( $j->{bounced})->cdate() ),
      'from' => $j->{addresser} };
  }
}

$message .= '登録されているメールアドレス' . $siteuser->mailaddress();
$message .= 'は、' . $bounce->{from} . 'から' . $bounce->{date};
$message .= 'に配信した際に' . $bounce->{reason} ' . 'のエラーで';
$message .= '配信できませんでした。';
...
テンプレートに渡す処理またはページの描画など;
                                        

上記のコードでは解析データのaddresser(配信したメールのFromアドレス) を検査しています。これはサイトをたくさん運営していて、ユーザがその複数に登録 している場合、今ログインしているサイトとは別のサイトが配信した結果の解析データ を間違って表示しないようにするためです。

実装するコード参考例(メッセージトークン)

 

Webサイトがひとつ(Fromアドレスも一種類)であれば、前掲のコード例のようにわざわざif() で検査しなくてもよいでしょう。逆にたくさんのサイト・たくさんのFromドメイン・Fromアドレスがある 場合は、foreachで廻すのは合理的ではありませんので、その場合はメッセージトークンを 作って、その値で検索してください。メッセージトークンについての説明は データ構造 の一番下、メッセージトークンの項目をご覧ください。

HTTP-API/SELECTを使って照合する

こではHTTPベースの API(select) を使います。APIで照合するために必要なトークン文字列を sprintf, md5_hex()で予め作成しています。

#!/usr/local/bin/perl
use strict;
use warnings;
use LWP::UserAgent;
use JSON::Syck;
use Digest::MD5;
use Time::Piece;

my $mailfrom = 'info@example.jp'; # Webサイトのメールアドレス
my $bounce = {}; # テンプレートに渡すORページに表示する元データ用
my $message = q(); # 表示する文言
my $siteuser = ユーザデータのオブジェクトを作る;
my $httphost = 'http://192.0.2.25/bouncehammer/a.cgi';
my $token = Digest::MD5::md5_hex(sprintf("\x02%s\x1e%s\x03",
             $mailfrom,$siteuser->mailaddress));
my $useragent = new LWP::UserAgent();
my $response = $useragent->request( HTTP::Request->new(
                'GET' => $httphost.'/select/'.$token ));
my $metadata = JSON::Syck::Load($response->content()) || [];

if( scalar @$metadata )
{
  $bounce = {
    'reason' => $metadata->[0]->{reason},
    'date' => Time::Piece->new($metadata->[0]->{bounced})->cdate(),
    'from' => $metadata->[0]->{addresser} };
}

$message .= '登録されているメールアドレス' . $siteuser->mailaddress();
$message .= 'は、' . $bounce->{from} . 'から' . $bounce->{date};
$message .= 'に配信した際に' . $bounce->{reason} ' . 'のエラーで';
$message .= '配信できませんでした。';

...
テンプレートに渡す処理またはページの描画など;
                                        

上記のコードも、最初に例示したコードとほぼ同じです。多数のWebサイトがあって、 更に多数のFrom(ドメイン・アドレス)があり、それらから配信されるメールのバウンス 記録がひとつのbounceHammerのデータベースに蓄積されている場合は、メッセージトークン で検索をする方が余計なデータベース負荷をかけずにすみます。