PHPからメール送信することは可能です。
メールフォームなどに入力された内容をメールで送信することはよくあることです。
PHPには「mail関数」と呼ばれる、メールを送信する仕組みが標準で備わっています。
これを使えば割と簡単にメール送信できます。
ただ、よく文字化けします。
とくに日本語はよく化けます。
何とかならないものか四苦八苦しながらも対処いたしましたので、忘備録として記録いたします。
mail()関数とはこのような関数です
基礎情報として、mail()関数について記述します。
といっても以下のように記述するだけです。
mail( [送信先メールアドレス], [メールタイトル], [本文], [送信元メールアドレス]);
例えば、以下のように記述します。
mail(“sousin@office-obata.com”, “メールタイトル文”, ”本文 テキストテキスト・・・”, “moto@officeobata”);
※メールアドレスは実在しないものです。
なんだ簡単じゃないかと思い、さっそく実験してみました。
実験①:特に何も考えずmail送信してみました。
PHPでメール送信するだけならば、フォームを使わなくてもできます。
テスト用に以下のプログラムを作成しテストしてみました。
<?php
// 宛先
$to = "sousin@office-obata.com";
// 送信元
$from = "From: テスト送信者<moto@office-obata.com>";
// メールタイトル
$subject = "メール送信テスト①";
// メール本文
$body = <<< EOM
メール本文
■特殊文字
①②③
㈱㌔髙
テキストテキストテキストテキストテキストテキストテキスト
テキストテキストテキストテキストテキストテキストテキスト
テキストテキストテキストテキストテキストテキストテキスト
テキストテキストテキストテキストテキストテキストテキスト
EOM;
// メール送信
mail($to, $subject, $body, $from);
?>
実際に受信してみた結果がこちらです。
OUTLOOKで受信したら特に問題はなかったのですが、Thunderbirdでメール受信してみたところ、「差出人」と「件名」が文字化けしました。
なんとなく理由は想像がつきます。
OUTLOOKは文字コードが「Shift-JIS」ベースですが、Thunderbirdは「UTF-8」
テスト用のPHPは日本語の文字コードを「Shift-JIS」で組んでおります。
Thunderbirdは日本語部分のデフォルトが「UTF-8」です。
なのでOUTLOOKでは文字化けせず、Thunderbirdは文字化けしたのだと思われます。
ちなみに、
メールの受信確認をする際は、OUTLOOKとThunderbirdの2つを使うと、問題点の検出がやりやすいです。
OUTLOOKだけでチェックすると、特定メーラー文字化けを見逃しがちです。
実験②:差出人、件名をUTF-8にしてみました
差出人、件名が文字化けしたので、ならばその2つを「UTF-8」に変換してみました。
<?php
// 宛先
$to = "sousin@office-obata.com";
// 送信元
$from = "From: テスト送信者<moto@office-obata.com>";
// メールタイトル
$subject = "メール送信テスト②";
// メール本文
$body = <<< EOM
メール本文
■特殊文字
①②③
㈱㌔髙
テキストテキストテキストテキストテキストテキストテキスト
テキストテキストテキストテキストテキストテキストテキスト
テキストテキストテキストテキストテキストテキストテキスト
テキストテキストテキストテキストテキストテキストテキスト
EOM;
// 文字コードをUTF-8に変換
$from = mb_convert_encoding($from, 'UTF-8', 'SJIS-win');
$subject = mb_convert_encoding($subject, 'UTF-8', 'SJIS-win');
// メール送信
mail($to, $subject, $body, $from);
?>
その結果がこちらです。
なるほど。一方を直せば反対側がだめになるパターンです。
この場合、どうすればよいのでしょうか?
実験③:メールヘッダーを付け加えてみた。
そもそもベースの文字コードが違うメーラーの場合、Shift-JIS、UTF-8のどちらを使用しても、かならずどちらかのメーラーは文字化けします。
このような場合、どうすればよいのでしょうか?
ググって調べて見たところ、以下のような対策が必要だということがわかりました。
- メールヘッダーに文字コードを記述するとメーラーは、メールヘッダーに記述された文字コードで表示される。
なるほど、表示する文字コードを事前に指定すれば良い。
ということがわかりました。
しかし、ここで疑問がわきました。
メールヘッダーってなに?PHPのmail関数でどうやって指定するの?
ちなみに、以前こんな記事も書いていました。
そういえば、PHPから送信するときにメールヘッダーを指定していないと思いました。
しかし、どうやって指定すればよいかわからなかったため、ググってさらに調べました。
その結果対応してみたものが、以下のコードになります。
<?php
// 宛先
$to = "sousin@office-obata.com";
// 送信元
$from = "From: テスト送信者<moto@office-obata.com>";
// メールタイトル
$subject = "メール送信テスト③";
// メール本文
$body = <<< EOM
メール本文
■特殊文字
①②③
㈱㌔髙
テキストテキストテキストテキストテキストテキストテキスト
テキストテキストテキストテキストテキストテキストテキスト
テキストテキストテキストテキストテキストテキストテキスト
テキストテキストテキストテキストテキストテキストテキスト
EOM;
// 文字コードをUTF-8に変換
$from = mb_convert_encoding($from, 'UTF-8', 'SJIS-win');
$subject = mb_convert_encoding($subject, 'UTF-8', 'SJIS-win');
// PHPの文字コードをUTF-8に指定
mb_internal_encoding("utf-8");
//headerを設定
$header = array();
$header['MIME-Version'] = "1.0";
$header['Content-Type'] = "text/plain; charset=UTF-8";
$header['Content-Transfer-Encoding'] = "8bit";
$header['From'] = $from;
//headerを編集
$set_header = array();
foreach ($header as $key => $val)
{
$set_header[] = $key . ': ' . $val;
}
// ヘッダーを1文に結合
$send_header = implode("\n", $set_header);
// メール送信
mail($to, $subject, $body, $send_header);
?>
急に複雑になりました。
要は、いままで「送信元情報」を設定していた部分にメールヘッダー情報を記述します。
メールヘッダーはむつかしくてよくわからないので、固定記述でコピペです。
その結果がこちらです。
さらにひどくなりました・・・・。
今度は本文も文字化けしました。
ただ、件名はどちらも正しく表示されています。
ひどいなりにも、一歩前進です。
まずは本文の文字化けを何とかします。
実験④:本文の文字化けを直す
メールヘッダーを記述したらなぜ本文が文字化けしたのか?
ちょっと焦る感じの現象ですが、冷静になって考えたら理由がわかります。
- メールヘッダーには記載文字コードはUTF-8と記述した
- 本文はもともと文字化けしていなかったのでShift-JISのまま
なんか理由が見えてきました。
これは本文を「UTF-8」に変換してやればよさそうです。
それがこちらです。
<?php
// 宛先
$to = "sousin@office-obata.com";
// 送信元
$from = "From: テスト送信者<moto@office-obata.com>";
// メールタイトル
$subject = "メール送信テスト④";
// メール本文
$body = <<< EOM
メール本文
■特殊文字
①②③
㈱㌔髙
テキストテキストテキストテキストテキストテキストテキスト
テキストテキストテキストテキストテキストテキストテキスト
テキストテキストテキストテキストテキストテキストテキスト
テキストテキストテキストテキストテキストテキストテキスト
EOM;
// 文字コードをUTF-8に変換
$from = mb_convert_encoding($from, 'UTF-8', 'SJIS-win');
$subject = mb_convert_encoding($subject, 'UTF-8', 'SJIS-win');
$body = mb_convert_encoding($body, 'UTF-8', 'SJIS-win');
// PHPの文字コードをUTF-8に指定
mb_internal_encoding("utf-8");
//headerを設定
$header = array();
$header['MIME-Version'] = "1.0";
$header['Content-Type'] = "text/plain; charset=UTF-8";
$header['Content-Transfer-Encoding'] = "8bit";
$header['From'] = $from;
//headerを編集
$set_header = array();
foreach ($header as $key => $val)
{
$set_header[] = $key . ': ' . $val;
}
// ヘッダーを1文に結合
$send_header = implode("\n", $set_header);
// メール送信
mail($to, $subject, $body, $send_header);
?>
実験③との違いは、本文をUTF-8に変換を追加したのみです。
結果はこちら。
本文の文字化けが直りました。
文字コード変換は当たりでした。
残るは、差出人部分を何とかすればOKです。
しかしメールヘッダーをつけているのに、差出人だけなぜ文字化けするのでしょうか?
そして化けているのはOUTLOOKだけです。
考えてもよくわからなかったので、さらにググって調べました。
そしたら、次のようなことがわかりました。
- 差出人はメールヘッダー内に記述されるため、MIME変換しなければならない。
なるほど、差出人名はメールヘッダー内だから、文字コード指定していても文字化けしていたようです。
でも疑問がわきました。
MIME変換って何?
実験⑤:差出人名をMIME変換をしてみる(注:失敗例)
PHPでMIME変換をググってみたら、あっさり疑問は解決しました。
mb_encode_mimeheader()というMIME変換してくれる関数がPHPにはありました。
差出人をこの関数を通せばMIME変換してくれます。
早速差出人をMIME変換する記述に書き換えてみました。
<?php
// 宛先
$to = "sousin@office-obata.com";
// 送信元
$from = "テスト送信者<moto@office-obata.com>";
// メールタイトル
$subject = "メール送信テスト⑥";
// メール本文
$body = <<< EOM
メール本文
■特殊文字
①②③
㈱㌔髙
テキストテキストテキストテキストテキストテキストテキスト
テキストテキストテキストテキストテキストテキストテキスト
テキストテキストテキストテキストテキストテキストテキスト
テキストテキストテキストテキストテキストテキストテキスト
EOM;
// 文字コードをUTF-8に変換
//$from = mb_convert_encoding($from, 'UTF-8', 'SJIS-win');
$from = mb_encode_mimeheader($from);
$subject = mb_convert_encoding($subject, 'UTF-8', 'SJIS-win');
$body = mb_convert_encoding($body, 'UTF-8', 'SJIS-win');
// PHPの文字コードをUTF-8に指定
mb_internal_encoding("utf-8");
//headerを設定
$header = array();
$header['MIME-Version'] = "1.0";
$header['Content-Type'] = "text/plain; charset=UTF-8";
$header['Content-Transfer-Encoding'] = "8bit";
$header['From'] = $from;
//headerを編集
$set_header = array();
foreach ($header as $key => $val)
{
$set_header[] = $key . ': ' . $val;
}
// ヘッダーを1文に結合
$send_header = implode("\n", $set_header);
// メール送信
mail($to, $subject, $body, $send_header);
?>
差出人部分のUTF-8変換をやめ、MIME変換してみました。
その結果がこちらです。
Thunderbird側は問題ありませんでしたが、OUTLOOK側が変な文字列になりました。
何がいけないのでしょうか?
PHPの記述を見直していたら、気づきました。
送信元メールアドレスごとMIME変換していました。
送信元情報は、
$from = "テスト送信者<moto@office-obata.com>";
というように、日本語名とメールアドレスをまとめて気記述していました。
でもMIME変換は日本語部分だけでよいのではないかと思いました。
そこで送信元名と送信元メールアドレスを分離して記述することにしました。
実験⑥:差出人名をMIME変換をしてみる(成功例)
送信元情報を分割し、日本語名だけをMIME変換するように直しました。
それがこちらです。
<?php
// 宛先
$to = "sousin@office-obata.com";
// 送信元
$from = "moto@office-obata.com";
// 送信者名
$from_name = "テスト送信者";
// メールタイトル
$subject = "メール送信テスト⑦";
// メール本文
$body = <<< EOM
メール本文
■特殊文字
①②③
㈱㌔髙
テキストテキストテキストテキストテキストテキストテキスト
テキストテキストテキストテキストテキストテキストテキスト
テキストテキストテキストテキストテキストテキストテキスト
テキストテキストテキストテキストテキストテキストテキスト
EOM;
// 文字コードをUTF-8に変換
//$from_name = mb_convert_encoding($from_name, 'UTF-8', 'SJIS-win');
$from_name = mb_encode_mimeheader($from_name);
$subject = mb_convert_encoding($subject, 'UTF-8', 'SJIS-win');
$body = mb_convert_encoding($body, 'UTF-8', 'SJIS-win');
// PHPの文字コードをUTF-8に指定
mb_internal_encoding("utf-8");
//headerを設定
$header = array();
$header['MIME-Version'] = "1.0";
$header['Content-Type'] = "text/plain; charset=UTF-8";
$header['Content-Transfer-Encoding'] = "8bit";
$header['From'] = "${from_name}<${from}>";
//headerを編集
$set_header = array();
foreach ($header as $key => $val)
{
$set_header[] = $key . ': ' . $val;
}
// ヘッダーを1文に結合
$send_header = implode("\n", $set_header);
// メール送信
mail($to, $subject, $body, $send_header);
?>
日本語部分だけをMIME変換し後から結合します。
その結果がこちらです。
OUTLOOKもThunderbirdも文字化けしなくなりました。
かなりしんどかったですが、無事解決することができました。
メールを文字化けさせないポイント
- メールヘッダーを正しく記述すること。
- そして日本語部分を正しい文字コードに変換すること。
- 差出人日本語名はMIME変換すること。
この3つが大事であることをよくよく学びました。
mail送信関数にはmb_send_mail()というものもあります。
ただ、うまく送信できない。文字コード変換がかえって大変などの理由からmail関数のみでやってみました。
これでmail関数だけでそれなりにメール送信ができることがわかりました。
また一つ良い経験をいたしました。