メールにファイルを添付してサーバにアップロードするコード

最近、他の方が作ったモノの紹介とかの記事が多かったので、たまにはコードを交えた記事を書いてみる。

今回のネタは、メールに画像ファイルなどを添付して特定のメールアドレスに送ることで、サーバにファイルをアップロードする仕組みについてです。

今回使った環境は、Postfix&PHPですが、メールを受け取った時にスクリプトに渡す方法は、他のメールサーバでもあまり変わらないと思うので、流用はできるかと思います。

まず、メールを受け取るアドレスを用意する為、Unixのユーザを一つ作ります。

# useradd -m hoge
# passwd hoge
# su - hoge
$ maildirmake Maildir
$ vi .forward
"| /usr/bin/php -q /home/hoge/mail.php >>/home/hoge/log 2>&1"

細かい事は色々省いてるので、環境に応じてPostfixの設定は適宜行って下さい。(バーチャルドメイン運用だったらローカルユーザに転送する設定とか、SMTP認証するなら認証パスワードの設定とか…。)<手抜き(^^;

ポイントは.forwardの設定で、これで届いたメールの内容がSTDINに入った状態でスクリプトに渡されるようになります。例の場合は、何かしらエラーがあった場合に後で確認できるように、logというファイルにリダイレクトしています。

で、メールの内容を渡される方のスクリプト(mail.php)を書いていきます。

<?php
require_once 'Mail/mimeDecode.php';
// 受け取ったメール内容を変数に代入
if ( ($stdin=fopen("php://stdin",'r')) === true ){
    while( !feof($stdin) ){
        $mailtext .= fgets($stdin,4096);
    }
}
fclose($stdin);
// デコード方法の指定
$params['include_bodies'] = true;
$params['decode_bodies']  = true;
$params['decode_headers'] = true;
// デコード処理
$decoder = new Mail_mimeDecode($mailtext);
// メールの構造を取得
$mail = $decoder->decode($params);
// 添付ファイルの有無で処理を分岐
if ( count($mail->parts) > 1 ) {
    $body = $mail->parts[0]->body;
    $file = $mail->parts[1]->body;
    $filetype = $mail->parts[1]->ctype_secondary;
    //画像ファイルを所定の場所に保存
    $id = md5(uniqid(rand(),1));
    $image_filename = '/home/hoge/images/'.$id.'.'.$filetype;
    $fp = fopen($image_filename,"w");
    fputs($fp,$file);
    fclose($fp);
    chmod($image_filename,0644);
} else {
    // 添付ファイルが無い場合はbodyを取得するだけ
    $body = $mail->body;
}
// ヘッダ部分を取得して漢字コードを変換する
$headers = $mail->headers;
$from_text = mb_convert_encoding($headers['from'],'utf-8','ISO-2022-JP');
ereg("[0-9a-zA-Z_\.\-]+@[0-9a-zA-Z_\.\-]+",$from_text,$from);
$from = $from[0];
$subject = mb_convert_encoding($headers['subject'],'utf-8','ISO-2022-JP');
$body = mb_convert_encoding($body,'utf-8','ISO-2022-JP');
// デバッグ出力
$output = '';
$output.= "差出人:".$from."\n";
$output.= "件名:".$subject."\n";
$output.= "保存先:".$image_filename."\n";
$output.= "本文:".$body."\n";
echo "$output";
?>

これで、hogeというユーザ宛に添付ファイル付きのメールを送ると、images配下に適当にIDが振られたファイル名で保存されるはずです。
ここでは、受け取ったメールの内容に対して特に処理はせず、"デバッグ出力"のところで内容を出力してるだけですが、ヘッダの内容を使ってDBに格納するとか、折り返し送り元にメールを返信するとか処理を入れれば、色々とメールを使ったサービスが作れますね。(^-^)