Webシステムを構築していくとぶち当たるのがメール周りの問題。
特に日本語メールはかなりの鬼門で、文字化け、ヘッダー問題などで
苦しむ人が多いと思います。

そんな人達のために開発されたのが、
PHP高機能日本語メール送信ライブラリ・文字化けフリー -
Qdmail - PHP::Mail Library , Quick and Detailed for Multibyte 

PHPでメール周りを検索した人ならまず間違いなくこのあたりに
辿りついていると思います。

私も非常にお世話になり、前々からずっと使っておりました。
しかし、悲しきかな「誰でも簡単に日本語メール送信が使える」ことに特化してしまった
落とし穴というか、汎用さを求めた結果の弊害をお伝えしたいと思います。

実は全く関係ないと思っていたメール周りを改善したら処理が5倍ほど (当社比)
速くなったので、その原因と対策をメモとして残します。
そもそもの発端は、メール周りの不具合を見直している最中でした。
会社の先輩の小山さんの一言。
「メールログにエラー出まくっているけど、これなんなの?」
っていう問いから始まりました。

たしかに/var/log/maillogをviで見てみるとエラーが定期的に出力されています。
まぁ実は前々から原因については気づいていたんですが、さほど気にせず開発をしてました。
(Qdmailを使用し始めてからエラーが出ていたという点まではわかっていた)

で、さすがに放置はまずいから一応エラーだけでも消そう!ということで色々調べた結果
Qdmailはコンストラクタの中でMTAとしてqmailを使っているかどうか?を自動判定していた!

処理としては、PHP上でsystemコマンドを使いqmailかどうかを調べてます。
コマンドの詳細は残念ながら自分にはちょっと理解出来なかったww
ので、実際のソースコードを読むことをおすすめします。

一応、該当のメソッドはこのあたり。

	function isQmail(){
		if(!is_null($this->is_qmail)){
			return $this->is_qmail;
		}
		$this->is_qmail = false;
		$ret = ini_get ( 'sendmail_path' );
		if(false !== strpos($ret,'qmail')){
			$this->is_qmail = true;
		}
		$sendmail_path = ini_get('sendmail_path');
		if(false !== @system($sendmail_path.' -d0.1 < /dev/null > /dev/null',$ret)){
			if(is_array($ret)){
				$ret = reset($ret);
			}
			$code = (int) substr($ret,0,3);
			if( 100 === $code || 111 === $code){
				$this->is_qmail = true;
			}
		}

		return $this->is_qmail ;
	}



で、is_qmailというメンバ変数が

	//----------------------------
	// Line Feed Character & kana
	//----------------------------
	var	$LFC				=  "\r\n";// Notice: CRLF ,If you failed, change to "\n"
	var $LFC_Qmail			=  null;
	var $is_qmail		  =  null;
	var $language			= 'ja';
	var $kana				=  false; // kana header



109行目あたりにあるので、そこを null → false に変えてやればOK!
is_nullでnullかどうかを判定しているので、そもそも下の処理に通らなくしてやろう的な話。

これは送信関係なく、インスタンスが作成されるたびに実行されるため、負荷がかかります。
更に言うと
CakePHPは、コントローラー内でQmailコンポーネントを呼び出すだけで実行されます!
これかなり重要。

今回、自社のサービスページが各コントローラーで処理されていたのですが、この読み込みが
毎回行われていた(そもそも必要な時点だけインスタンスしろって話ですが・・)ので
アクセスしてきた人数xMTAチェックが走っていたわけです。
どおりで遅いわけです・・・表示まで1500msほどかかっていたのが、300msになりました。
1.5秒→0.3秒!体感出来るほどの速さです\(^o^)/
さほど大規模な人数のサービスではないため、この程度で済んでましたが
これが某Y社だとかF社だとかM社だと思うと怖いですねw

そもそもqmail以外を使用している場合はこの処理は意味が無いんですよね・・・
(厳密に言うと、qmailを使っていても必要はない)
自分で使っているメールシステムを把握しているなら尚更です。
これの何が問題かという点についてですが、qmailを使ってなかった場合は、当然エラーが出ます。
それが、/var/log/maillogに記録されるので結果的にログも肥大化するし見にくくなると。

汎用性を高めてくださったおかげで楽に使えるけど、無駄な処理も増えちゃった」という。
別にdisりたいとか悪いと言いたいわけではなくて、ここまで親切に作ってくださったことを感謝してます。

結論:レンタルサーバーなどでどのMTAを利用しているか不明な人以外はis_qmallフラグはfalseに設定!
もし、既に使っている方がいらっしゃったら試してみてください。
といったところで、一緒に調べてくださった小山さん感謝です!

【追記1】
小山さんからはてブでコメント貰いました!
重たい根本の原因は system() 関数が httpd プロセスを fork するからだってことも書いとくと良いんじゃないかにゃー。 2011/06/08


 

ということらしいです!!