qmailでメールを携帯に転送して、メール通知に使っておられる方は結構多いんじゃないでしょうか。
ただ、大きなファイルが添付されていると、エラーメールが送信元に戻ってしまいます。
つまり、クライアントが大きなファイルを添付してきた場合、エラーメールがクライアントに戻ってしまうことになります。
やっぱりそれだとマズイです。添付ファイルが勝手に他者に転送されている訳ですからね。
それで、転送する際に添付ファイルを落としてから、転送したほうが無難です。
転送するためのスクリプトをPHPで作ってやることにしました。
インストールされているパッケージは以下の通り。
php php-cli php-common php-gd php-intl php-mbstring php-pear php-pear-Mail-Mime php-pear-Mail-mimeDecode php-process php-xml
php-cli、php-mbstring、php-pear、php-pear-Mail-Mime、php-pear-Mail-mimeDecode
以上が必要パッケージですが、依存性でその他もインストールされるはずです。
PHPは最低でも以下のような設定が必要です。
[Date] date.timezone = Asia/Tokyo [mbstring] mbstring.language = Japanese mbstring.internal_encoding = UTF-8 mbstring.http_input = pass mbstring.http_output = pass mbstring.encoding_translation = Off mbstring.detect_order = auto mbstring.substitute_character = none mbstring.func_overload = 0 mbstring.strict_detection = Off
vpopmailの実行ファイルがあるところにスクリプトを置きます。
#!/usr/bin/php <?php /** * あらかじめ添付ファイルを叩き落として、メッセージだけを転送するスクリプト * * @author Digital Acorn * @created 2015-06-15 */ mb_internal_encoding('UTF-8'); $res = fopen('php://stdin','r'); if (!$res) { exit(0); } $output = ''; $boundary = ''; $attached_deleted = false; // ヘッダー部分でboundaryを探す while($line = fgets($res)) { // content-type句を得る。もしcontent-typeが無いような失礼なメールの場合、 // 全てがoutputに回るはず。そしてboundaryがないので、全部出力される。 if (preg_match('/content-type:\s+multipart\/[a-z]+;/i',$line)) { // mixedでない場合は全て出力 if (!preg_match('/multipart\/mixed/i', $line)) { $output .= $line; while($line = fgets($res)) echo $output .= $line; break; } else { if (!preg_match('/boundary=/i',$line)) { $line .= fgets($res); } $boundary = array(); if (!preg_match('/boundary="*([^"\s]+)"*$/i',$line,$boundary)) { exit(0); } else { $boundary = $boundary[1]; } $output .= $line; break; } } $output .= $line; } if (!empty($boundary)) { // 最初のboundaryまで送る while($line = fgets($res)) { // boundaryを発見 if (strpos($line, $boundary)!==false) { break; } $output .= $line; } while(true) { $saved = array($line); $attached = false; while($line = fgets($res)) { // boundaryが登場するまで回す if (strpos($line, $boundary)!==false) { break; } // content-type句が出てきた if (preg_match('/^content-type/i',$line)) { if (preg_match('/text\/plain|text\/html|multipart\/alternative/i',$line)) { // テキストメッセージ $attached = false; } else { // 添付ファイル $attached = true; $attached_deleted = true; } } if (!$attached) { // テキストメッセージなら保存 $saved[] = $line; } } if (!$attached) { // テキストメッセージなら出力する foreach ($saved as $value) { $output .= $value; } } // 終端のboundaryなら最後まで出力して終了 if (strpos($line, $boundary."--")!==false) { $output .= $line; while($line = fgets($res)) $output .= $line; break; } // もし最後のboundaryが無いような尻切れのメール場合、出力を終了する。 if ($line===false) break; } } require_once('/usr/share/pear/Mail/mimeDecode.php'); // qmailが環境変数に値をセットしてくる // .qmailのあるディレクトリにenv.phpを置いて、そこに転送先を書いてある。 // $mail = "test@example.jp" みたいに。 // 現在のディレクトリ $dir = getenv('PWD'); $mail = ''; @include($dir.'/env.php'); if (empty($mail)) { exit(0); } // 転送前の送り主 $sender = getenv('SENDER'); // メールを受け取ったドメイン名(バーチャルドメインかも) $host = getenv('HOST'); // デコード $params['include_bodies'] = true; $params['decode_bodies'] = true; $params['decode_headers'] = true; $decoder = new Mail_mimeDecode($output); $structure = $decoder->decode($params); $from = mb_convert_encoding($structure->headers['from'], 'UTF-8', 'auto'); $subject = mb_convert_encoding($structure->headers['subject'], 'UTF-8', 'auto'); $date = $structure->headers['date']; // スパム判定なら転送しない if (preg_match('/^\s*\[SPAM\]/', $subject)) { exit; } // ボディが奥の方にある場合があるので、ストラクチャを下がっていく // この方法でいいのか、疑問。text部分が必ず最初に来るのか? if (!($body = @$structure->body)) { if (!($body = @$structure->parts[0]->body)) { if (!($body = @$structure->parts[0]->parts[0]->body)) { $body = 'HTMLだけのメールです'; } } } $body = mb_convert_encoding($body, 'UTF-8', 'auto'); $new_body = <<<END_OF_BODY {$host}メールサーバーです。 サーバーに到着したメールを転送します。 このメールに直接返信しないでください。 END_OF_BODY; $new_body .= ($attached_deleted)?"※ 添付ファイルが削除されました。\n":""; $new_body .= <<<END_OF_BODY ----- Original Message ----- From: $from Date: $date Subject: $subject $body END_OF_BODY; $header = 'From: <postmaster@'.$host.">"; mb_send_mail($mail, "Fw: ".$subject, $new_body, $header); exit(0);
オーナーを変更し、実行権限を付けます。
chown vpopmail.vchkpw /home/vpopmain/bin/mailTransfer chmod 711 /home/vpopmain/bin/mailTransfer
各ユーザーの環境設定ファイルを作ります。
下記例だと、example.jpドメインのfooさんの環境設定です。
<?php $mail = 'example@docomo.ne.jp';
その後、.qmailを編集します。
|spamc |mailTransfer |spamc |tomaildir ./Maildir
こうしておくと、spamassassinの結果で転送をコントロールできます。
スパムだった場合は、転送されずメールボックスには、件名に [SPAM] という接頭子が付いたメールが入ります。
(下の記事の、おまけ部分をインストールしてあることが前提です)
qmail(with smtp auth) + vpopmail + ezmlm-idx + dovecot + qmailadminなサーバ構築
以上です。