HOME >> 書籍・人物 >> 山崎はるかのメモ


メール到着で自動的にCGIを実行

- .forwardでPHPを起動する -

△メモエリアにもどる

Hatena bookmark Yahoo! bookmark


はじめに

メール到着と同時に、ただちにCGI(Perlやruby、PHP)を実行したい場合がある。
たとえば、到着したメールを すべてデータベースに入れたり、あるいは、掲示板に表示したりなど。

 これを実装するには、SendmailやPostfixの場合は  .forward に パイプ処理を書く。qmailの場合は .qmail に書く。
それを ユーザーディレクトリに置いておけば、メール到着と同時に 指定したプログラムが実行される。

ただ 書籍やネットの記述では 「そのようにして プログラムを実行できる」と書いてあるだけで、具体的に 到着したメールの中味をどう処理するのか、までは述べられていないことが多い。(少なくとも 私自身は まだ お目にかかったことがない)

なので、当メモにて、もうちょっと具体的なソースを書いておくことにする。

 

環境

OSは FreeBSD6.2 ・・・なのだが 別に 他のOSでも たいして変わらんと思う。
MTAは Sendmail または Postfix
CGIプログラムは、わかりやすく PHPを用いる。

なお サンプルソースの縮小のためPEARを用いているが、ごらんの通り、これはメールヘッダーの分割化に使用しているだけなので、なくても代替方法は すぐにおわかりかと思う。
念のため、PEAR を使用しない場合の 代替ソースを コメントで書いた。

.forward を書く

メール到着の イベント(キュー)は、.forward で検出する。
.forward は 本来「メール転送」に用いるファイルであり、通常は このファイルの中に転送先アドレスを書くわけだが、そのメール転送先を「プログラム」にすることで、プログラムにメール内容を送り込んでしまうわけである。

.forward
"| /usr/local/bin/php -q /usr/home/hoge/mail.php"

ごらんのとおり mail.php スクリプトを、CGIモードで起動する。
なので いちいち フルパスで記述している。

Linux では、

"| /usr/bin/php -q /usr/home/hoge/mail.php"

になる場合も 多かろう。
念のため find / -name php で場所を調べといたほうがよい。

いずれにせよ、実行権限を持たせたファイルであれば、PerlであろうがCGIであろうが、これで動作させることができる。


実行プログラム を書く

.forward から転送されたメールは、対象プログラムの STDIN(標準入力)に入る。
プログラムは、標準入力からメール全体を取得するところから はじまる。

ほとんどの場合 ネットで取引されるメールは 7bit文字コードのプレーンで書かれているので、そのまま .eml 拡張子で保存すれば OutlookExpress  で読める eml 形式 となる。

ただ この状態では、ヘッダー部分と本文が一体化しているばかりか、日本国内の場合 メールの題名(Subject)は ISO-2022-JP で、7bit にエンコードされたままなので 読めたものではない。
また 本文も、多くの場合はJISコードなので、PHPでそのまま取り扱うのは苦しい。

そこでヘッダーと本文に分け、それぞれ 処理を行う例を 次に示す。

mail.php  (パーミッション705)
<?php
require_once("Mail/mimeDecode.php"); // PEAR MimeDecode → # pear install Mail_Mime してるか確認

mb_language('ja');
mb_internal_encoding("utf-8");

// メール取得
if ( ($stdin=fopen("php://stdin",'r')) == true ){
	while( !feof($stdin) ){
		$line .= fgets($stdin,4096);
	}
}
fclose($stdin);

// この時点で $line に メール全体がとれてるので、eml形式で そのまま保存することもできる
// $fp = fopen("file1.eml","w");
// fputs($fp,$line);
// fclose($fp);


// PEARを使用しない場合
// ヘッダー分離
//$head = substr($line,0,strpos($line,"\n\n"));
//$m_headers = split('\n',$head);

// 本文抽出
//$m_body = trim(strstr($line,"\n\n"));
// 文字コンバート
//$m_body = mb_convert_encoding( $m_body, "UTF-8", "JIS" );




// PEAR を使った処理
 $decoder = & new Mail_mimeDecode( $line ); // MIMEを分解
 $parts = $decoder->getSendArray();
 list( $recipients, $headers, $body ) = $parts;

// メールの内容 (タイトル・送信者・メール本文)
$subject = mb_decode_mimeheader( $headers['Subject'] ) ;
$from = mb_decode_mimeheader( $headers['From'] ) ;
$m_body = trim(mb_convert_encoding( $body, "UTF-8""JIS" ));

?>

 

おしまいに

上記サンプルでは、到着したメールの 題名・送信者名・本文を取得するところまで処理してある。

PEARを使用しない場合と、使用した場合を それぞれ分けて記述している。
(PEARを使用しない例を コメントアウトしている。この処理の場合は 題名・送信者の単離処理をしていない)

ここから あとの応用は、それぞれに おまかせする。

(2007/11/16・山崎はるか)


■メモエリアに戻る