Mail::Box

メールの内容というのは大切な財産でありまして、ネタになったり昔を思い出して懐かしいなぁ、思ったり。そんなメールのデータをDBに保存するのにパーサを探そう、とCPAN様に伺いますと上記のモジュールが出てきました。簡単に使い方を。

とりあえずインスタンスを作ります。useしてインスタンスを作るのはMail::BoxではなくMail::Box::Managerらしいので注意です。


メッセージを取り出すにはmessageかmessagesメソッドを使います。返ってくる値はMail::Box::Mbox::Messageインスタンスです。messageは配列のように番号を指定してアクセスします。対してmessagesメソッドはすべての値をリストで返します。全件処理をするのにこのmessagesメソッドを使います。


メールの中には添付ファイルがあるものがあります。こういうメールはMultipartと言うらしく、Multipartだとパースの流れが少し違います。そのMultipartを検出するにはisMultipartメソッドを使います。


Multipartの場合にpartsメソッドを使うとMail::Message::Partインスタンスのリストが返されます。(私の場合は)添付がある場合はJPEG画像ひとつだけと決まっているので、本文、JPEGのファイル内容(HTMLメール)の順に値が返されました。


JPEGの様にファイルの実態があるものには名前があるはずです。その名前はヘッダの中にあるみたいなのでヘッダから取り出します。専用のメソッドは無いようなのでgetメソッドで'Content-Location'を引数に指定し、ファイル名を取り出します。

そしてdecodedメソッドを使い、本文を取り出します。画像だった場合には先ほどの取得したファイル名でopenし、binmodeしておいたファイルハンドルをprintメソッドの引数にして、ファイルに書き出します。


あとはfromやtimestampメソッドを使って必要なデータを取り出して好きなように煮るなる焼くなりします。

以下ソース。

use Mail::Box::Manager;

my $folder = Mail::Box::Manager->new->open(folder => 'm.txt');

for my $mes ($folder->messages)
{
	print @{$mes->sender};
	print scalar localtime $mes->timestamp;
	
	if ($mes->isMultipart)
	{
		for ($mes->parts)
		{
			if (my $filename = $_->get("Content-Location"))
			{
				open my $fh, ">$filename" or die;
				binmode $fh;
				$_->decoded->print($fh);
				
				print "append file found! : $filename";
			}
			else
			{
				print +($_->parts)[0]->body;
			}
		}
	}
	else
	{
		print $mes->decoded;
	}
}

とりあえずMultipartのパターンが決まっていて、単純にデータを吐くだけの簡単なものなので、詳しく知りたい方はMail::Box::以下のドキュメントを見てください。これらをDBのINSERTに向ければDBでメールを運用できそうです。
いままで独自のパーサ書いていたんですけれどもCPANモジュール使うと面倒くさくないし、ソースも見やすいですね。