メール受信をトリガにしてスクリプトを起動させる

少し古い技術ですが、前にこんなことしたなと振り返りながら、復習の意味を込めてまとめてみます。
スクリプトはperlです。

# やりたいこと
- メールを受信したタイミングで内容を解析してjson形式で保存する
- `procmail`を使います

# 準備
## 環境

```sh
#cat /etc/redhat-release
CentOS release 6.5 (Final)
```

※postfixはすでに入っているので割愛

```sh
# which postfix
/usr/sbin/postfix
```

## procmailをインストール

```sh
yum -y install procmail
```

## postfixの設定にprocmailを使うことを伝える
`main.cf`ファイルに下記の内容を追加します。

```sh
#mailbox_command = /some/where/procmail
#mailbox_command = /some/where/procmail -a "$EXTENSION"
# 以下を追加
mailbox_command = /usr/bin/procmail
```

## `.forward`、`.procmailrc`の設定
今回はユーザごとに設定することにしました
ユーザのホームディレクトリに、`.forward`と`.procmailrc`を追加します。

```sh:.forward
"|IFS=' ' && exec /usr/bin/procmail -f- || exit 75 #~/Maildir/"
```

```sh:.procmailrc
MAILDIR=$HOME/Maildir/
DEFAULT=$MAILDIR
LOGFILE=$MAILDIR/procmail.log

:0
* ^To: .*trigger
| /home/user/script/receive_mail.pl
```

今回は trigger@example.com にメールを送った時に処理をする記述です。
`.procmailrc`の記述は下記に詳しく記述があります。
http://www.jaist.ac.jp/~fjt/procmail.html

## receive_mail.pl の内容
受信したメールを受け取り、タイトルやメッセージそれから添付ファイルを解析しています。
※環境によってはそのままでは動きません。
※保存先を環境によって変えて下さい。

```pl:receive_mail.pl
#!/usr/bin/perl

use strict;

use Email::MIME;
use Email::MIME::XPath;
use Email::MIME::ContentType;
use JSON::XS;
use Time::Piece;
use Encode;
use Image::Magick;

=memo

"(time)_$$/body" preserves it here.

Some images are preserved by "(time)_$$/file_1,file_2,...".

Please change $DIR to a suitable directory.

=cut

my $MAIL = join '', <STDIN>;

my $DIR = '/home/user/received_data';
my $time = time();

my $mail = Email::MIME->new($MAIL) or die "error - $!";

# MessageID
my $id = $mail->header('Message-Id');

# Subject
my $subject = $mail->header('Subject');

# image rotate check.
my $image_rotate;
if( $subject =~ m/\{imagerotate\}/ ) {
	$image_rotate = 1;
	$subject =~ s/\{imagerotate\}//;
}

# From
my $from = do {
	$mail->header('From') =~ /([^<]+\@(?:[-a-z0-9]+\.)*[a-z]+)/;
	$1
};

# Body
my ($body_data) = $mail->xpath_findnodes('//*[@content_type=~"^text"][1]');
if( ! $body_data ) {
	($body_data) = $mail->xpath_findnode('//*[@content_type=~"^html"][1]');
}

my $body = '';
if( $body_data ) {
	$body = Encode::decode(
		parse_content_type($body_data->content_type)->{attributes}->{charset},
		$body_data->body,
	);
}

# Make dir
my $local_time_piece = localtime();
my $target_dir = $DIR. '/' .$local_time_piece->date;
if( not -d $target_dir ) {
	umask(0);
	mkdir( $target_dir, 0777 ) or die $!;
}

my $image_parts = [];
@$image_parts = $mail->xpath_findnodes('//*[@content_type=~"^image/"]');

my $file_array = [];
for( my $i = 0; $i < scalar @$image_parts; $i++ ) {
	my $image_data = $image_parts->[$i];

	my $filename = int(rand(1000)). $image_data->filename;

	my $image_dir = "$target_dir\/". $time;
	if( not -d $image_dir ) {
		umask(0);
		mkdir( $image_dir, 0777 ) or die $!;
	}


	my $save_file = "$image_dir\/$filename";
	open( FH, ">$save_file" );
	print FH $image_data->body;
	close FH;

	# create thumb.
	my $image = Image::Magick->new();
	$image->Read( $save_file );
	
	# image rotate.
	if( $image_rotate ) {
		$image->Rotate(degrees=>-90,crop=>1);
	}
	
	# size check.
	if( $image->Get('width') lt $image->Get('height') ) {
		$image->Scale(geometry=>350);
	} else {
		$image->Scale(geometry=>425);
	}
	# out put
	$image->Write( $image_dir. '/thumb_'. $filename );

	# create thumb for mobile.
	my $mobile_image = Image::Magick->new();
	$mobile_image->Read( $save_file );
	
	# image rotate.
	if( $image_rotate ) {
		$mobile_image->Rotate(degrees=>-90,crop=>1);
	}
	
	# size check.
	if( $mobile_image->Get('width') lt $mobile_image->Get('height') ) {
		$mobile_image->Scale(geometry=>180);
	} else {
		$mobile_image->Scale(geometry=>240);
	}
	# out put
	$mobile_image->Write( $image_dir. '/mobile_thumb_'. $filename );

	push( @$file_array, $filename );

}

# create json
my $json_hash = {};
$json_hash->{'message_id'} = $id;
$json_hash->{'subject'}    = $subject;
$json_hash->{'from'}       = $from;
$json_hash->{'body'}       = $body;
if( scalar @$file_array ) {
 $json_hash->{'file_array'} = $file_array;
}

# data dump
my $out_file_name = "$target_dir\/". $time. '.json';
open( my $FH, ">$out_file_name" ) or die "file open error - $!";
print $FH JSON::XS->new->utf8->encode ($json_hash);
close $FH;
chmod (0666 , $out_file_name);


1;

```

権限を変更しておきます。

```sh
chmod 755 receive_mail.pl
```

完了したら、いよいよメールを受信してみます。

# メールを受信してみる
メールを実際に受信してみます。
デコメ形式やHTMLメール形式でも対応しています。

受信がうまくいくと、下記のような感じで保存されます。

```sh
$ tree
.
`-- 2015-11-09
    |-- 1447039295
    |   |-- 166__.JPG
    |   |-- mobile_thumb_166__.JPG
    |   `-- thumb_166__.JPG
    `-- 1447039295.son
```

こんな感じでデータを取得できました。

jsonの中身はこんな感じになっています。

```json
{"file_array":["166__.JPG"],"body":"こんにちはー\r\n\r\n\r\n","message_id":"<AAAAAAAAA-BBBBB-CCCCC-DDDDD-EEEEEEEEE@example.com>","from":"xxxx@example.com","subject":"てすとだよー"}
```

# まとめ
今回はメールを受信して内容を整形して保存しただけですが、
あるワードを検出すると返信があるとか、そういうことも出来ます。

以上になります！