PHPコーディング
SMTPソケットをオープンしてメール送信(ソケットオープン)
2010年01月20日
PHPからメールを送信するには色々な方法があります。
手っ取り早く日本語メールを送信するには【mb_send_mail】があります。
添付ファイルやhtmlメールを送信するには、【mail】を使ってヘッダなど書かけば可能です。
しかし、この【mail】関数、いちいちSMTPソケットを開いたり閉じたりするので、メールマガジン、ステップメールを配信するのには不向きのようです。
その上、sendmailやqmailなどがインストールされていて、PHPから使えないとメールが送信できないそうです。
更に更に、処理が重たいのです。
ソケットのオープン・クローズも制御するには直接ソケットをオープンしてメールを送信しなければいけないようです。
もちろんその辺りの無料のツールも出回ってます。有名どころではPEAR::Mail_Mime。
利用してもいいのですが、なにかあったとき自分でちゃっちゃと直せないと困るので、自分で書いてみることにしました。
大まかな流れは、
1. ソケットオープン
2. メール送信
3. ソケットクローズ
です。
メールマガジンやステップメール配信の場合は2を繰り返します。
まずはソケットオープンです。
$smtp = "smtp.domain.xxx";
$port = 587;
メール送信時にも認証が必要になってから、ポート番号は587のことが多くなってます。
$id = "mail_id";
$pw = "smtp_pw";
$sock = @fsockopen($smtp, $port);
でオープンできます。
成功したら、
@fputs($sock, "EHLO ".$port."\r\n");
認証が必要になってからコマンドはEHLO。
ここでサーバーが色々な情報を返してきます。
そのうちの1つが、利用可能な認証方式。
250-AUTH PLAIN LOGIN DIGEST-MD5 CRAM-MD5 NTLM
の形式で返ってきます。
利用できる認証方式は、PLAIN、LOGIN、DIGEST-MD5、CRAM-MD5、NTLM。
それぞれの認証方式は後にして、ここで問題が発生です。
while (!feof($sock)) {
$result = @fgets($sock, 128);
$num = preg_match("/^250-AUTH /i", $result);
if(0 < $num){
$login_method = str_replace("250-AUTH ", "", $result);
}
}
として、サーバーから返された文字列を取得しようとしたのですが、どうやら無限ループに陥っているようで、タイムアウトになってしまいます。
調べていくと、【feof($sock)】でfalseが返ってきていないようです。【fsockopen】でオープンしたストリームでも使えるのに・・・なぜ?PHPのバグ??それとも終了しないとeofが返ってこないのか???
仕方ないので、別の方法に切替です。
while ($result = @fgets($sock, 128)) {
$num = preg_match("/^250-AUTH /i", $result);
if(0 < $num){
$login_method = str_replace("250-AUTH ", "", $result);
}
}
で一応解決です。
でも、ものすごく時間がかかってしまいます。
時間がかかっているのは、【$result = @fgets($sock, 128)】の部分です。
文字列が返ってくる場合は早いのですが、falseが返ってくるのに時間がかかっています。
PHPのマニュアルを読むと、【feof】関数はタイムアウトになったときもfalseを返すとのこと。
そこで、タイムアウトまでの時間を短くし、処理時間の短縮を試みました。
【stream_set_timeout】でタイムアウトまでの時間を設定できます。
タイムアウトになったら【stream_get_meta_data】で値が取得できます。
stream_set_timeout ($sock, 5); //タイムアウトまでの時間を5秒に設定
while (!feof($sock)) {
$result = @fgets($sock, 128);
$info = stream_get_meta_data($sock);
if($info['timed_out'] == true){ //タイムアウトになったらこの値がtrueになる
break;
}
$num = preg_match("/^250-AUTH /i", $result);
if(0 < $num){
$login_method = str_replace("250-AUTH ", "", $result);
}
}
5秒ではなくもっと小さな値にすればもっと早くなります。
これで解決!のようです。動かしているうちまた不都合が見つかるかもしれませんが。
長くなったので、smtp認証はまた次回。
手っ取り早く日本語メールを送信するには【mb_send_mail】があります。
添付ファイルやhtmlメールを送信するには、【mail】を使ってヘッダなど書かけば可能です。
しかし、この【mail】関数、いちいちSMTPソケットを開いたり閉じたりするので、メールマガジン、ステップメールを配信するのには不向きのようです。
その上、sendmailやqmailなどがインストールされていて、PHPから使えないとメールが送信できないそうです。
更に更に、処理が重たいのです。
ソケットのオープン・クローズも制御するには直接ソケットをオープンしてメールを送信しなければいけないようです。
もちろんその辺りの無料のツールも出回ってます。有名どころではPEAR::Mail_Mime。
利用してもいいのですが、なにかあったとき自分でちゃっちゃと直せないと困るので、自分で書いてみることにしました。
大まかな流れは、
1. ソケットオープン
2. メール送信
3. ソケットクローズ
です。
メールマガジンやステップメール配信の場合は2を繰り返します。
まずはソケットオープンです。
$smtp = "smtp.domain.xxx";
$port = 587;
メール送信時にも認証が必要になってから、ポート番号は587のことが多くなってます。
$id = "mail_id";
$pw = "smtp_pw";
$sock = @fsockopen($smtp, $port);
でオープンできます。
成功したら、
@fputs($sock, "EHLO ".$port."\r\n");
認証が必要になってからコマンドはEHLO。
ここでサーバーが色々な情報を返してきます。
そのうちの1つが、利用可能な認証方式。
250-AUTH PLAIN LOGIN DIGEST-MD5 CRAM-MD5 NTLM
の形式で返ってきます。
利用できる認証方式は、PLAIN、LOGIN、DIGEST-MD5、CRAM-MD5、NTLM。
それぞれの認証方式は後にして、ここで問題が発生です。
while (!feof($sock)) {
$result = @fgets($sock, 128);
$num = preg_match("/^250-AUTH /i", $result);
if(0 < $num){
$login_method = str_replace("250-AUTH ", "", $result);
}
}
として、サーバーから返された文字列を取得しようとしたのですが、どうやら無限ループに陥っているようで、タイムアウトになってしまいます。
調べていくと、【feof($sock)】でfalseが返ってきていないようです。【fsockopen】でオープンしたストリームでも使えるのに・・・なぜ?PHPのバグ??それとも終了しないとeofが返ってこないのか???
仕方ないので、別の方法に切替です。
while ($result = @fgets($sock, 128)) {
$num = preg_match("/^250-AUTH /i", $result);
if(0 < $num){
$login_method = str_replace("250-AUTH ", "", $result);
}
}
で一応解決です。
でも、ものすごく時間がかかってしまいます。
時間がかかっているのは、【$result = @fgets($sock, 128)】の部分です。
文字列が返ってくる場合は早いのですが、falseが返ってくるのに時間がかかっています。
PHPのマニュアルを読むと、【feof】関数はタイムアウトになったときもfalseを返すとのこと。
そこで、タイムアウトまでの時間を短くし、処理時間の短縮を試みました。
【stream_set_timeout】でタイムアウトまでの時間を設定できます。
タイムアウトになったら【stream_get_meta_data】で値が取得できます。
stream_set_timeout ($sock, 5); //タイムアウトまでの時間を5秒に設定
while (!feof($sock)) {
$result = @fgets($sock, 128);
$info = stream_get_meta_data($sock);
if($info['timed_out'] == true){ //タイムアウトになったらこの値がtrueになる
break;
}
$num = preg_match("/^250-AUTH /i", $result);
if(0 < $num){
$login_method = str_replace("250-AUTH ", "", $result);
}
}
5秒ではなくもっと小さな値にすればもっと早くなります。
これで解決!のようです。動かしているうちまた不都合が見つかるかもしれませんが。
長くなったので、smtp認証はまた次回。
コメント