EC studio EC studio 技術ブログ

PHPで日本語メールを送る - 基本編に引き続き、
今回は応用編をお送りします。

基本編で解説したmb_send_mailを使えば
シンプルなメールを送るには十分な機能がありますが、
それ以上に複雑なこと、例えばHTMLメールや添付ファイルを
使ったメールにはmb_send_mailは使えません。

mail関数を使ってヘッダにガリガリとメールの仕様に
そって書けば送れるのですが、それではあまりに
大変なので、ライブラリを使います。

ライブラリを使った日本語メール送信

PHPで複雑なメールを送るのに使えるスタンダードな
ライブラリとしては、PEAR::MailPHPMailerが有名です。
(ただし、両ライブラリとも日本語メールには対応していないので、
そのままでは文字化けしてしまいます)

PEAR::MailはPHPの公式ライブラリのPEARで採用されていますし、
PHPMailerXOOPSSymfonyなど有名なオープンソースの
プロジェクトで採用されるなど、どちらも十分な実績がある
メールライブラリです。

PEAR::Mailの方がPEARに採用されているだけあって
良く取り上げられることが多く、また日本語での
紹介記事も多いのですが、私個人としては
PHPMailerの方をオススメします。

理由としては、PHPMailerの方が圧倒的にカンタンで
使いやすい
からです。

例えば、添付メールを送るコードを見比べてみると、
PEAR::Mailでは

  1. //ライブラリ読み込み
  2. require_once("Mail.php");
  3. require_once("Mail/mime.php");
  4.  
  5. //言語設定、内部エンコーディングを指定する
  6. mb_language("japanese");
  7.  
  8. //日本語添付メールを送る
  9. $to = "kawamura@example.com"; //宛先
  10. $subject = "例の件について"; //題名
  11. $body = "資料を送ります"; //本文
  12. $from = "masaki@example.com"; //差出人
  13. $fromname = "山本 正喜"; //差し出し人名
  14. $attachfile = "./file.zip"; //添付ファイルパス
  15.  
  16. $mail = Mail::factory("mail");
  17.  
  18. $body = mb_convert_encoding($body,"JIS","EUC-JP");
  19.  
  20. $mime = new Mail_Mime("\n");
  21. $mime->setTxtBody($body);
  22.  
  23. //添付ファイル追加
  24. $mime->addAttachment($attachfile,"application/octet-stream");
  25.  
  26. $body_encode = array(
  27.   "head_charset" => "ISO-2022-JP",
  28.   "text_charset" => "ISO-2022-JP"
  29. );
  30.  
  31. $body = $mime->get($body_encode);
  32.  
  33. $headers = array(
  34.   "To" => $to,
  35.   "From" => mb_encode_mimeheader(mb_convert_encoding($fromname,"JIS","EUC-JP"))."<".$from.">",
  36.   "Subject" => mb_encode_mimeheader(mb_convert_encoding($subject,"JIS","EUC-JP"))
  37. );
  38.  
  39. $header = $mime->headers($headers);
  40.  
  41. $return = $mail->send($to,$header,$body);
  42. if (PEAR::isError($return)){
  43.     echo("メールが送信できませんでした エラー:".$return->getMessage());
  44. }

こう書きます。

。。。。。
もう、何ですかこれは? という感じですね。

いえ、メールの仕様に沿ってしっかりとクラス化
されているので、確かにメールの仕様を理解してる人には
わかりやすいと思いますが・・・。

このライブラリを使うには、メールのヘッダ構造や
MIMEのルールなどを知る必要があり、ただ添付メールを
送りたいというだけの開発者にはまわりくどすぎます。
(引数の渡し方もいちいち複雑!)

一方、PHPMailerでは

  1. //ライブラリ読み込み
  2. require("./phpmailer/class.phpmailer.php");
  3.  
  4. //言語設定、内部エンコーディングを指定する
  5. mb_language("japanese");
  6.  
  7. //日本語添付メールを送る
  8. $to = "kawamura@example.com"; //宛先
  9. $subject = "例の件について"; //題名
  10. $body = "資料を送ります"; //本文
  11. $from = "masaki@example.com"; //差出人
  12. $fromname = "山本 正喜"; //差し出し人名
  13. $attachfile = "./file.zip"; //添付ファイルパス
  14.  
  15.  
  16. $mail = new PHPMailer();
  17. $mail->CharSet = "iso-2022-jp";
  18. $mail->Encoding = "7bit";
  19.  
  20. $mail->AddAddress($to);
  21. $mail->From = $from;
  22. $mail->FromName = mb_encode_mimeheader(mb_convert_encoding($fromname,"JIS","EUC-JP"));
  23. $mail->Subject = mb_encode_mimeheader(mb_convert_encoding($subject,"JIS","EUC-JP"));
  24. $mail->Body  = mb_convert_encoding($subject,"JIS","EUC-JP");
  25.  
  26. //添付ファイル追加
  27. $mail->AddAttachment($attachfile);
  28.  
  29. if (!$mail->Send()){
  30.     echo("メールが送信できませんでした。エラー:".$mail->ErrorInfo);
  31. }

こう書けます!

いいですねー。シンプルです。

送りたいメールのパラメータ一つ一つに、
クラスのメソッドやプロパティが対応しており、
とても直感的でわかりやすいです。

※補足
Bodyだけmb_encode_mimeheaderがないのは、
本文はヘッダではないからです。

ただ、以下の点をなんとかしたいところです。

・日本語を使う場合CharSetやEncodingを指定する必要あり
・$mail->From = $from など、プロパティに値を
 直接入れたくない (しかも一文字目が大文字)
・毎回mb_encode_mimeheadermb_convert_encodingが面倒
・addCcやaddBccはあるのに、宛先はaddToではない。(addAddress)
・とても長い題名のメールが文字化けする

というわけで、気に入らないならラッパークラスを作りましょう。

PHPMailerの日本語ラッパークラス JPHPMailer

JPHPMailer - ここからダウンロード (PHP4/PHP5 両対応)

PHPMailer本体が別途必要です。

JPHPMailerでPHPMailerを改良したのは次の点です。

・CharSetやEncodingの設定を不要に
・addAddress()をaddTo()へ (addAddressも使えます)
・From,Subject,Bodyなど、プロパティを直接扱うものを
 メソッドを通して設定するように
・エラーメッセージの取得をgetErrorMessage()メソッドで。
・mb_*関連の変換が不要に。(引数でそのまま渡すだけ)
・題名が長いメールでも文字化けが起きないように。

このラッパークラスを使うと、先ほどの添付メールの例では

  1. //ライブラリ読み込み
  2. require("./jphpmailer.php");
  3.  
  4. //言語設定、内部エンコーディングを指定する
  5. mb_language("japanese");
  6.  
  7. //日本語添付メールを送る
  8. $to = "kawamura@example.com"; //宛先
  9. $subject = "例の件について"; //題名
  10. $body = "資料を送ります"; //本文
  11. $from = "masaki@example.com"; //差出人
  12. $fromname = "山本 正喜"; //差し出し人名
  13. $attachfile = "./file.zip"; //添付ファイルパス
  14.  
  15.  
  16. $mail = new JPHPMailer();
  17.  
  18. $mail->addTo($to);
  19. $mail->setFrom($from,$fromname);
  20. $mail->setSubject($subject);
  21. $mail->setBody($body);
  22.  
  23. //添付ファイル追加
  24. $mail->addAttachment($attachfile);
  25.  
  26. if (!$mail->send()){
  27.     echo("メールが送信できませんでした。エラー:".$mail->getErrorMessage());
  28. }

こう書けます。

ずっと自然になりました。
何よりmb_*がきっちり隠蔽されてるところがポイントです。

HTMLメールを送る場合は、

  1. //ライブラリ読み込み
  2. require("./jphpmailer.php");
  3.  
  4. //言語設定、内部エンコーディングを指定する
  5. mb_language("japanese");
  6.  
  7. //日本語HTMLメールを送る
  8. $to = "kawamura@example.com"; //宛先
  9. $subject = "例の件について"; //題名
  10. $htmlbody = "<b>資料</b>を送ります"; //HTML本文
  11. $altbody = "資料を送ります"; //代替テキスト本文
  12. $from = "masaki@example.com"; //差出人
  13. $fromname = "山本 正喜"; //差し出し人名
  14.  
  15.  
  16. $mail = new JPHPMailer();
  17.  
  18. $mail->addTo($to);
  19. $mail->setFrom($from,$fromname);
  20. $mail->setSubject($subject);
  21. $mail->setHtmlBody($htmlbody);
  22. $mail->setAltBody($altbody);
  23.  
  24. if (!$mail->send()){
  25.     echo("メールが送信できませんでした。エラー:".$mail->getErrorMessage());
  26. }

こうなります。

代替テキスト付きHTMLメールもカンタンに送ることができます。

※代替テキストは、メールソフトがHTML表示に
対応していない場合に代わりに表示されるテキストです。

-----------------------------------------------

長くなってしまいました。

JPHPMailerは今回の為に簡単に作ったものなので、
必要な機能があれば自由にカスタマイズしてください。
(ライセンスはLGPLです)

PEAR::MailPHPMailerなど、PHPには優れたライブラリが
多数あるのですが、今回の様に日本語が使えなかったり、
それぞれのクラスで設計思想が違うのでメソッド名や
引数の渡し方などが気に入らなかったりするものです。

そういう時は、自分好みにクラスを継承したラッパーを
作ってあげるとぐっと使い勝手が良くなります。

こういうちょっとしたカスタマイズを覚えると、
様々なライブラリを自由に取り入れる事が
できるようになるので、是非挑戦してみてください!


関連した記事:

この記事へのコメント

はじめまして。個人でPHPの勉強をしています。
JPHPMailerありがたく使わせて頂きます!

ひとつわからなかったことがあるのですが、
どうして題名と差出人名だけ、
mb_convert_encodingの第三引数が他と違う指定になっているのでしょうか?

UTF-8環境で動かそうと思ったので、
$in_enc=”UTF-8″としたら動くかなと思ったんですが、
そのときにこの2つの項目で引っかかってしまったので、
ちょっと気になりました。

特別な意味があるのかなぁと思ったので、
もしよろしければ教えてください!

投稿者: ayp | 2007/08/30 木曜日 21:14:36

コメントありがとうございます。

ご指摘していただいた箇所ですが、特に意味はなく修正し忘れていました箇所でした、、。
JPHPMailerを作った時に、内部エンコーディングを変更しやすいようにしようと後でin_encを足したのですが、全てのメソッドに反映されていなかった様です。

修正してアップしました。

JPHPMailerは思ったよりも大きな反響をいただけたので、バージョンアップ版を作成しようと思っていますのでご期待ください!

投稿者: Masaki | 2007/09/01 土曜日 12:02:08

参考にさせてもらっています。

クラスに関して長いことさぼっていて、今日はじめてまともに勉強したので、とんちんかんな事を書いているかも知れませんが質問します。

外部メールサーバーをSMTP認証で使用しているのですが、PHPMailerを利用したときは、送れるのですが、JPHPMailerを利用したときはエラーになります。

親クラスのメンバ変数は子クラスでは特に宣言しなくても使えると理解しているのですが、何か間違っているのでしょうか?

もしよかったら、ご教示ください。

投稿者: 偽青 | 2007/11/22 木曜日 2:37:51

とても助かりました
phpでのメール送信はやっていましたが、このページのおかげでやりたいことを5分程度ですぐにできました。
大変有益な情報をありがとうございます。

投稿者: 匿名 | 2008/05/17 土曜日 17:52:26

こちらのJPHPMailerをちょこっとだけカスタマイズして、CakePHPで使えるようにしてみました。ありがとうございます。
一応LGPLとして配布していますが、なにか問題等ありましたらご連絡ください。
http://blog.tofu-kun.org/080528155319.php

投稿者: zaru | 2008/05/28 水曜日 16:01:15

>zaruさん

おお~、ありがとうございます。
全然問題ありません! :)

投稿者: Masaki | 2008/06/04 水曜日 12:31:04

貴重なClassご提供ありがとうございます。
またご丁寧な解説非常に助かります。
質問させていただきたいのですが、
BCCを数多く指定したいときや添付を複数つけるとき
はどのような方法があるのでしょうか。
ご回答頂ければ幸いです。
よろしくお願いいたします。

投稿者: Pavo | 2008/09/07 日曜日 1:57:45

とても参考になりました。
ところで、添付ファイル名ですが、これを日本語に変換して添付するなんてできないでしょうか?
Perlの時の自作のスクリプトではできていたので、ヘッダー的にはできるのですが、PHPMailerにはそのような関数が追加されてないかな?と、思ったもので。。。

投稿者: ともあき | 2008/09/10 水曜日 17:53:56

>Pavoさん

addBccなどを複数回呼び出せばokです。
addXXXというメソッドは、どんどん追加されていきます。
添付ファイルもできると思います

投稿者: Masaki | 2008/10/16 木曜日 19:56:07

>ともあきさん

おそらく、addAttachmentをオーバーライドすればできそうですね。
addAddressなどと同様に内部でencodeMimeheaderをたたけばできるのではないかと思います。

PHPMailerもバージョンアップしているようで、JPHPMailerの次期バージョンを作ろうかと思ってますので、その時に機能追加してみます!

投稿者: Masaki | 2008/10/16 木曜日 19:58:02

http://q.hatena.ne.jp/1202147708
のような現象に私もなっていますが、
何か解決方法ってありますか?
特定の環境だと件名の途中で改行が入っているのか、
20文字のマルチバイト文字くらいの件名で全然長くないのに、
件名が途中で途切れてしまってます。

versionは0.11のJPHPMailerをUTF-8で使用しています。
よろしくお願いします。

投稿者: となり | 2008/12/09 火曜日 11:37:26

function encodeSubjectMimeHeader($string,$charset=null,$linefeed=”\n”){

のように$linefeedを”\n”にするとひとまず解決しました。
環境によってはMTA側で\n→\r\nにされ、また、
\r\nは→\r\r\nにされるって記事を見かけましたが、
それが原因だったのでしょうか。

投稿者: となり | 2008/12/11 木曜日 18:34:32

いつも活用させていただいています。

画像を添付してもThunderbirdのメーラでは
ファイルは無事届くものの、
画像として認識してくれないので調べてみたら
デフォルトではMimeTypeは["application/octet-stream"]になって
いるので['image/jpeg']にしないとだめなんですね。

$mail->addAttachment($filePath,’img.jpg’,'base64′,’image/jpeg’);

投稿者: となり | 2009/01/22 木曜日 16:00:56

まだ仕事に必要かどうかはわかりませんが、PHPの勉強をしていて、メール送信部分でここにたどり着きました。

わかりやすかった上に、簡単にHTMLメールが送信できたので喜んでいました。
ありがとうございました。

しかし、HTML文章中に画像がついている場合は画像が表示されないんですね。
またいろいろなところを検索してがんばりたいと思います。

投稿者: まーぼー | 2009/04/14 火曜日 10:23:59

大変参考にさせていただきました。
おかげさまで添付ファイル付きメールを送信するプログラムを実装することができました。
ありがとうございます。

投稿者: maito | 2010/03/04 木曜日 10:10:34

お役に立てて良かったです!

投稿者: 山本 正喜 | 2010/03/05 金曜日 9:05:27

このblogはとてもひつよですからこのblogの英語ぶぶんをほしです。えいごでこのblogはありますか。

投稿者: アリグ | 2010/03/27 土曜日 13:08:35

私も同じような目的で、JPHPMailerと同じような派生クラスを昨日作ったところでした。。。
件名等でmb_encode_mimeheaderを使い、74 文字を越えて文字化けしていたところで引っ掛かり、ここにたどり着きました。
とてもとても参考になりました。
助かります・・・。
本当にありがとうございます。

すいません。一点だけ、お時間あったら伺いたいのですが、

>>$mail->From = $from など、プロパティに値を 直接入れたくない (しかも一文字目が大文字)

とあります。「1文字目が大文字」というのはよろしくないのでしょうか?
理由をご教授いただけたら幸いです。

投稿者: キタノ | 2010/04/16 金曜日 18:10:14

お役にたててよかったです!
「1文字目が大文字」というのはコーディング規約によると思いますが、
あまり一般的ではないように思います・・・^^;
プロパティ名は全部小文字のものが多いかと思います。

投稿者: 山本 正喜 | 2010/06/04 金曜日 11:31:22

こちらのラッパー参考にさせていただいています。
現在組み込み中なのですが、文字コードUTF-8で設定すると、
件名の部分が”=?iso-2022-jp?”から始まる文字化けした文字列になってしまいます。
ラッパークラスの$in_encをUTF-8にしたり、ラッパー自体をUTF-8で保存したりなどしてみたのですが、
うまく修正できません。
なにか対応方法はないでしょうか?

投稿者: slyman | 2010/07/21 水曜日 12:48:32

追記:=?iso-2022-jp?から?=までの間の文字列をbase64デコードした後SJIS変換すると本来の件名が取得できます。メールヘッダに詳しくない為現在調査中なのですが、これが正しい動作なのでしょうか?ThunderBirdやOutlookでは件名が取得できないのですが。

投稿者: slyman | 2010/07/21 水曜日 16:02:06

たぶん二重にMIMEエンコードされているのだと思います。
Subjectまわりのコードを追いかけていってもらえれば・・・

PHPMailerのバージョンが上がったことも関係あるかもしれません。

この記事はだいぶ内容古くなってしまったので、
また新しく書こうと思います・・・

投稿者: 山本 正喜 | 2010/09/27 月曜日 12:27:32

jphpmailer.php 使わせていただいています。
わかりやすい API で、大変ありがたいです。

ところで、 jphpmailer.php の require を、こちらでは require_once に書き換えて使わせていただいていますが、問題ないでしょうか。
二重に require されたときに、クラス定義が重複してしまい、エラーになりそうだったので、そのようにしました。

何か意図がありましたらご教示ください。

よろしくお願いします。

投稿者: AC | 2010/10/20 水曜日 18:35:39

はい、問題ありません。
requireの方がrequire_onceよりコストが低いので使っています。

投稿者: 山本 正喜 | 2011/01/05 水曜日 17:46:54

==参考になれば==

Thunderbirdで件名の一部が文字化けした場合。
$mail->Subject = mb_encode_mimeheader(mb_convert_encoding($_POST['subject'],”JIS”, “UTF-8″));I

$mail->Subject = mb_encode_mimeheader($_POST['subject']);

で行けました。

http://d.hatena.ne.jp/deeeki/20080806/mailsubjecterror

参考まで

投稿者: テスター | 2011/03/21 月曜日 17:06:49

すごく参考になるサイトで大変助かっております。

ちなみに日本語の添付ファイルを送ることはできるのでしょうか?
自分のところで試してみたところ文字化けを起こしてしまい、
うまくいきませんでした。
アドバイスいただけると助かります。

よろしくお願いします。

投稿者: Saru | 2011/07/05 火曜日 16:20:02

大変参考になって助かっております。
少し気になった点があって、phpMailerの5.1では、$mail->SetFrom() で設定したメールアドレスに “Return-Path” も設定されるのですが、jphpmailerの方ではその設定が無いので、常にデフォルトの”Return-Path”が設定されてしまいます。

function setFrom(……..
の最後の方に

if (empty($this->Sender)) {
$this->Sender = $from;
}
を加えておくと”Return-Path”も反映されました。

私のテスト環境は SuSE11.3+Postfix+PHP5.3.5ですが
今のところうまく行っています。

投稿者: jean | 2011/07/27 水曜日 1:13:37

はじめまして。静岡県は静岡市に在住しております MC6800 と申します。
PHP にてフォームメールを組みたいと考え、Google さんを利用して参考文献を
色々探していた中、幸運にもこちらのページへ訪れる事が出来た次第でございます。

この度こちらの記事を参考に無事にフォームメールを組む事が叶いまして、とても
嬉しく感謝いたしております。
ちょっと手を加えさせていただいて、差出人名と題名と本文に半角カタカナ文字を
使えるようにしてしまいましたが。^^;;

おかげさまで本当に参考になりました。重ねて御礼申し上げます。
ありがとうございます。m(__)m

投稿者: MC6800 | 2011/08/13 土曜日 2:00:33
投稿者
人気のエントリー
カテゴリー
最近のエントリー
アーカイブ
Copyright© ChatWork, All Rights Reserved. secured by ESET.