質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.64%

PHPのメール送信で差出人名に空白を使いたいです

解決済

回答 3

投稿

  • 評価
  • クリップ 0
  • VIEW 3,710

qwe001

score 103

PHP 5.6.22 です
今回メール送信機能をフレームワークなしでPHPで作ることになりました。
以下のようにメールを送信する機能の実装は完了しましたが。。。

<?php
mb_language("Japanese");
mb_internal_encoding("UTF-8");

$from_email = 'aa@example.com';
$from_name = 'あいうえお';
$headers = 'From: ' . mb_encode_mimeheader(mb_convert_encoding($from_name, 'ISO-2022-JP', 'AUTO')) . '<' . $from_email . '>';

$toUser = $_SESSION['email'];
$subjectToUser = 'タイトル';
$messageToUser =<<<USER
{$_SESSION['first_name']}様

メール本文
USER;

if($_SESSION){ mb_send_mail($toUser, $subjectToUser, $messageToUser, $headers); }

// メール内容
// 差出人:あいうえお<aa@example.com>
// 件名:タイトル
// 本文:○○様...etc
?>

差出人名に空白をつけると、ヘッダー情報が本文に流れ込んできます。
一体何が原因なのでしょうか。

<?php
mb_language("Japanese");
mb_internal_encoding("UTF-8");

$from_email = 'aa@example.com';
$from_name = 'あい うえお';
$headers = 'From: ' . mb_encode_mimeheader(mb_convert_encoding($from_name, 'ISO-2022-JP', 'AUTO')) . '<' . $from_email . '>';

$toUser = $_SESSION['email'];
$subjectToUser = 'タイトル';
$messageToUser =<<<USER
{$_SESSION['first_name']}様

メール本文
USER;

if($_SESSION){ mb_send_mail($toUser, $subjectToUser, $messageToUser, $headers); }

// メール内容
// 差出人:あい うえ<>
// 件名:タイトル
// 本文:=?ISO-2022-JP?B?JUgbKEI=?=<aa@example.com>...etc
?>
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

+1

mb_convert_encoding()mb_encode_mimeheader()の文字コード問題についてたいへんよくまとまっているページがありますのでご参照ください。
mb_encode_mimeheaderの都市伝説を検証する - CPA-LABテクニカル

重要なのは、mb_internal_encoding()で設定する(あるいはphp.iniで設定する)文字コードと、mb_encode_mimeheader()に渡す文字列の文字コードは一致していなくてはダメ、ということです。

なので、

<?php
    mb_language("Japanese");
    mb_internal_encoding("UTF-8");            //mb_internal_encodingにUTF-8を指定するんなら、

    $from_email = 'nobody@example.com';
    $from_name = 'なんだかすごくすごく長いおまけにシフトジスが嫌いなツとか表とか入っているやらしいなまえでしかも長すぎて化けやすそうなアレがあれななまえのテスト';
    $from_encoded = mb_convert_encoding($from_name, 'UTF-8', 'AUTO');    // mb_encode_mimeheaderに渡す前にUTF-8に変換しなくてはダメ
    var_dump($from_encoded);
    $headers = 'From: ' . mb_encode_mimeheader($from_encoded) . '<' . $from_email . '>';

    var_dump($headers) ;
?>


は、ソースファイルの文字コードがUTF-8だろうがSHIFT-JISだろうが文字化けしませんが、

<?php
    mb_language("Japanese");
    mb_internal_encoding("UTF-8");            //mb_internal_encodingにUTF-8を指定するんなら、

    $from_email = 'nobody@example.com';
    $from_name = 'なんだかすごくすごく長いおまけにシフトジスが嫌いなツとか表とか入っているやらしいなまえでしかも長すぎて化けやすそうなアレがあれななまえのテスト';
    $from_encoded = mb_convert_encoding($from_name, 'ISO-2022-JP', 'AUTO');    // mb_encode_mimeheaderに渡す前にUTF-8に変換しなくてはダメ
    var_dump($from_encoded);
    $headers = 'From: ' . mb_encode_mimeheader($from_encoded) . '<' . $from_email . '>';

    var_dump($headers) ;
?>


だと文字化けしてしまいます。

追記

上記のような長いFromだと、エンコードした際には複数行になってしまいます。
これは、RFC2822あたりの、「一行の長さは78文字以下であるべきである」に割と忠実で、これ自体が問題ではないです。
たとえば上記のコードであればエンコード後のFromは

From: =?ISO-2022-JP?B?GyRCJEokcyRAJCskOSQ0JC8kOSQ0JC9EOSQkJCokXiQxJEslNyVVGyhC?=
 =?ISO-2022-JP?B?GyRCJUglOCU5JCw3eSQkJEolRCRIJCtJPSRIJCtGfiRDJEYkJCRrGyhC?=
 =?ISO-2022-JP?B?GyRCJGQkaSQ3JCQkSiReJCgkRyQ3JCskYkQ5JDkkLiRGMj0kMSRkGyhC?=
 =?ISO-2022-JP?B?GyRCJDkkPSQmJEolIiVsJCwkIiRsJEokSiReJCgkTiVGJTklSBsoQg==?=<nobody@example.com>


のようになります。
このように長いヘッダーフィールドは、RFC2047の規定により、複数の 'encoded-word' を含むある特定のヘッダフィールドを表示する時は、隣接する 'encoded-word' を分離するあらゆる 'linear-white-space' は無視されることになっています。

ですので、通常であればこれは一つのFromヘッダとして認識されるべきです。

しかしながら、一部のUnix/Linux系のメールサーバ(MTA)では、行末改行コードにLFのみを期待していて、かつLFがきたらCR+LFに変換する、という大きなお世話をするものがあります。
(手元で調べてみたところqmail、postfixなどがそれにあたるようです)

もしそのような環境であれば、上記の複数行Fromは最初の行だけがヘッダとしてみなされ、次の行には空行が入ってしまうため、それ以降の行が本文として認識されるような事態になります。

これはとてもよろしくないので、もしそういう環境なら、
preg_replace()などで改行コードをLFにして渡すしかないでしょう(RFC違反っぽいのであんまり好ましくないけど)

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/10/13 21:34

    返信が遅くなり申し訳ありません。頂いておりますコードにて期待通りの結果を得ることができました!
    また、78文字を超えると問題が発生するということ、目から鱗でした。
    そのような状況は全く想定していなかったですので、教えて頂くまで気づくことは一生涯なかったと思います。文字コードの違いもいまいちよくわかっておらず、とりあえずメールだしISO-2022-JP使っといたらいいんじゃないの? と思っていたのですが、そのような仕様があったとは…大変勉強になりました。非常にわかりやすく、詳細に書いていただいたこちらの回答をベストアンサーとさせて頂きます。皆様ありがとうございました。またよろしくお願いいたします。

    キャンセル

+1

$from_email = 'aa@example.com';
$from_name = 'あい うえお';
$headers = 'From: ' . mb_encode_mimeheader($from_name, 'ISO-2022-JP') . ' <' . $from_email . '>';

これで検証しましたが、うまく行きました。

mb_encode_mimeheaderはinternal encodingから第二引数に指定された文字に変換しますので、
mb_convert_encodingは不要です。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

質問者さんのコードでは正しくヘッダ符号化できていません。この点はshi_ueさんのご回答のやりかたが正しいと思います。

mb_internal_encoding('UTF-8');
$from_email = '……';
$from_name = '……';
$headers = 'From: ' . mb_encode_mimeheader($from_name, 'ISO-2022-JP') . ' <' . $from_email . '>';


次に、ご質問の点

差出人名に空白をつけると、ヘッダー情報が本文に流れ込んできます。 

ですが、上のようにコードを直しても、$from_nameがだいたい20数文字を超えると再発するのではないかと思います。ひらがなの文字数を増やしてご確認ください (空白の有無は関係ないと思います)。

次のように変更するとどうでしょうか。

mb_internal_encoding('UTF-8');
$from_email = '……';
$from_name = '……';
$headers = 'From: ' . mb_encode_mimeheader($from_name, 'ISO-2022-JP', 'B', "\n") . ' <' . $from_email . '>';


mb_encode_mimeheader()に4番めの引数として"\n"を与えています。

先日、既定値の"\r\n"が問題を起こしていたと思しい例を見かけましたので、それと同様かと。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.64%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る