ホームページ制作 オフィスオバタ

PHP mail()関数で日本語を文字化けさせずに送信する

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」に変換してやればよさそうです。

それがこちらです。

<?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変換をしてみる(注:失敗例)

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も文字化けしなくなりました。
かなりしんどかったですが、無事解決することができました。

メールを文字化けさせないポイント

この3つが大事であることをよくよく学びました。

mail送信関数にはmb_send_mail()というものもあります。
ただ、うまく送信できない。文字コード変換がかえって大変などの理由からmail関数のみでやってみました。

これでmail関数だけでそれなりにメール送信ができることがわかりました。
また一つ良い経験をいたしました。

モバイルバージョンを終了