QA@IT

PHP メール送信でたまに文字化け 詳細コード有

6136 PV

いつも参考にさせていただいております。
下記、質問させてください。

PHPでメールを送信するプログラムを作成し、既に運用中なのですが、1ヶ月に数回の頻度でメール本文が文字化けした状態で送られてきてしまいます。
ほとんどの場合は正常に送信され、意図的には文字化けさせられない状態です。

このメール送信プログラムは、Webページのお問い合わせフォームで使用されていて、不特定多数の環境もバラバラな一般ユーザーからメールが送信されるというものです。

Webページのブラウザ出力文字コードと、PHPファイル自体の文字コードはどちらも「EUC-JP」ですが、メールは「shift-jis」で送信しています。
その為に行っている「EUC-JP」から「shift-jis」への変換に失敗する場合があり、それが原因で文字化けしているのでは・・・と想像していますが、具体的にどう対処すべきかわからないでいます。

##############################################################

以下がそのPHPプログラムの抜粋です。
PEARのメール送信クラスを使用しています。
mb_convert_encodingでの変換元文字コードの明示的記載など、できる限り調べた内容を盛り込んではいるのですが、まだ不備があるのだと思います。
何かお気づきの点があれば、どうかご教授ください。

補足ですが、このメール送信プログラムは運用にのってから4年が経ちます。
そして文字化けの問題が発生し始めたのは今年に入ってからです。
なので、最近になって増えたスマートフォン端末からの送信が関係しているのでは・・・とも想像しています。

どうぞよろしくお願い致します。

//メール送信処理開始
require_once("Mail.php");
require_once("Mail/mime.php");

// POSTパラメータ取得
// 送信先アドレス
$address = $_POST["address"];
// 前画面でユーザーがフィームに手入力したメール本文になる内容
$message = $_POST["message"];

$mailtext = htmlspecialchars_decode($message);
$mailtext .= "\n以上がメールの本文です。";

$mime = new Mail_mime();
$mime->setTxtBody(mb_convert_encoding($mailtext, "shift-jis", "EUC-JP,auto"));

$html_param['head_charset'] = "shift-jis";
// text_encodingは変換後の文字コード
$html_param['text_encoding'] = "shift-jis";
// text_charsetは変換前の文字コード
$html_param['text_charset'] = "shift-jis";
$body = $mime->get($html_param);

$header['From'] = mb_encode_mimeheader("自分の名前").'<'.ADMINISTRATOR_MAILADDRESS.'>';
$header['To'] = $address;
$header['Reply-To'] = $address;
$header['Subject'] = mb_encode_mimeheader("メールの件名");
$header = $mime->headers($header);

// SMTP設定(定数を格納しています)
$smtp_params['host'] = SMTP_SERVER_ADDRESS;
$smtp_params['port'] = SMTP_SERVER_PORT;
$smtp_params['auth'] = false;
$mail = Mail::factory("smtp", $smtp_params);
// メール送信
$ret = $mail->send($address, $header, $body);

if(PEAR::isError($ret)) {
    //die("エラーメッセージ:".$ret->getMessage());
} else {
}           
  • これで送られてくるメールの Subject, Content-Type ヘッダーの値は実際にはどのようになりますか? (Subject はどのように MIME エンコードされた値になっていますか) -

回答

大昔の記憶なんであれですが、internalencodingかえてやらないといけなかった気がします。
サンプルコード
(スクリプトファイルがSJIS、 ISO-2022-JPへ変換の例)

    // メール送信処理開始
    require_once("Mail.php");
    require_once("Mail/mime.php");

    // POSTパラメータ取得
    // 送信先アドレス
    $address = $_POST["address"];
    // 前画面でユーザーがフィームに手入力したメール本文になる内容
    $message = $_POST["message"];

    $mailtext = htmlspecialchars_decode($message);
    $mailtext .= "\n以上がメールの本文です。";


    $subject = "メールの件名";
    $fromName = "自分の名前";
    $from = ADMINISTRATOR_MAILADDRESS;


    $original = mb_internal_encoding();
    mb_internal_encoding( "ISO-2022-JP" );


    $from = "\"". mb_encode_mimeheader(mb_convert_encoding( $fromName, "ISO-2022-JP", "auto" ) ). "\" <". $from .">";

    $subject = mb_encode_mimeheader( mb_convert_encoding( $subject, "ISO-2022-JP", "auto" ) );
    $mailtext= mb_convert_encoding( $mailtext, "ISO-2022-JP", "SJIS" );

    $headers['From']    = $from;
    $headers['To']      = $address;
    $headers['Subject'] = $subject;
    $headers['Mime-Version'] = "1.0";
    $headers['Content-Type'] = "text/plain; charset=ISO-2022-JP";
    $headers['Content-Transfer-Encoding'] = "7bit";

    // SMTPサーバ設定
    $smtp_params = array(
         'host'      => SMTP_SERVER_ADDRESS,
         'port'      => SMTP_SERVER_PORT,
         'auth'      => false, 
    );


    $mail_object =& Mail::factory("SMTP",$smtp_params);

    $ret=$mail_object->send($recipients, $headers, $mailtext);
    mb_internal_encoding( $original );

    if(PEAR::isError($ret)) {
       //die("エラーメッセージ:".$ret->getMessage());
    } else {
    }  

コンバート前にmb_internal_encodingを変換後の文字コードにしているのがポイントです。
今回だとmb_internal_encoding("SJIS")になるんですかね。最後に元の値に戻すのも忘れずに。

5年位前のコード引っ張り出して提示のコードと併せてみただけで実行してみていないので、
なんかミスってるかもしれませんがとにかくポイントは mb_internal_encoding です。

編集 履歴 (1)
  • ありがとうございます。
    PEARの送信クラスを使用する場合でも「mb_internal_encoding」が必要なんですね。早速試してみます。
    ただ文字化けが発生するのは月に数回程度ですので、納品後しばらく様子をみてみる必要があります。なのでAcceptはもうしばらくお待ちください。
    -
ウォッチ

この質問への回答やコメントをメールでお知らせします。