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

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

ただいまの
回答率

88.21%

添付ファイル名が文字化けします。

受付中

回答 2

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 8,016

falco

score 7

メールに添付ファイルをつけて配信したいのですが
届いたメールの添付ファイル名が文字化けしています。
どうすれば文字化けが直るのでしょうか?
よろしくお願いいたします。

// 文字コードを ISO-2022-JP に変える
      mb_convert_variables('ISO-2022-JP', 'UTF-8', $body, $filename);

  // 各 mime パートの構築
  $mime = new Mail_mime;
  $mime->setParam('text_charset', 'ISO-2022-JP');
  $mime->setParam('text_encoding', '8bit');
  $mime->setTxtBody($body);
  $mime->addAttachment($file_path // data
                       ,'application/octet-stream'  // content-type
                       ,$filename // attached file name
                       ,false // isfile
                       ,'base64' // encoding
                       ,'attachment' // disposition
                       ,'' // charset
                       ,'' // language
                       ,'' // location
                       ,'base64' // n_encoding
                       ,'base64' // f_encoding
                       ,'' // description
                       ,'ISO-2022-JP' // h_charset
      );

    $subject = "メール:";
  $jis = mb_convert_encoding($subject, 'ISO-2022-JP', 'UTF-8');
  $encsubj = mb_encode_mimeheader($jis, 'ISO-2022-JP', 'B');

  $headers = array(
      'From' => 'hoge@hogehoge.net',
      'To' => $recpts,
      'Subject' => $encsubj );

  $headers = $mime->headers($headers);
  $body = $mime->get();

  // メール送信には SMTP を直接使うのが好き
  $mail = Mail::factory('smtp', array('host' => 'localhost'));
  $mail->send($recpts, $headers, $body);

ファイル名は正しいがファイルが壊れている

ファイルは届くがファイル名が文字化けしている

  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 2

+2

「文字化け」の質問では、実際にどんなふうに化けて見えているのかをわかるようにしていただきたいです。お使いのメールソフトのスクリーンキャプチャを貼り付けるなどするといいと思います。

それはともかく、回答します。

$mime->setParam('text_charset', 'ISO-2022-JP');
$mime->setParam('text_encoding', '8bit');
$mime->setTxtBody($body);

ISO-2022-JPは7ビット符号です[注1]ので、text_encodingは'7bit'であるべきです。

$mime->addAttachment($file_path // data
                     ,'application/octet-stream'  // content-type
                     ,$filename // attached file name
                     ,false // isfile
                     ,'base64' // encoding
                     ,'attachment' // disposition
                     ,'' // charset
                     ,'' // language
                     ,'' // location
                     ,'base64' // n_encoding
                     ,'base64' // f_encoding
                     ,'' // description
                     ,'ISO-2022-JP' // h_charset
    );

Mail_MIMEのマニュアルのaddAttachment()の項に基づき、引数についてコメントします。

  • charsetは「The character set of attachment's content」です。これはファイル名の符号化には関係ありません。設定するとファイルの内容が文字コード変換されてしまいます。ですから''にします。
  • encodingdispositionもファイルの内容の設定です。'base64''attachment'で問題ないです。
  • n_encodingf_encodingはファイル名の符号化に関係があります。それぞれ「Encoding of the attachment's name in Content-Type」、「Encoding of the attachment's filename in Content-Disposition header」です。
    ファイル名の符号化については間違った仕様がなかば一般化してしまっているという事情があり[注2]、それに合わせた設定をしなければなりません。n_encoding'base64' (RFC 2047のB符号化――間違った仕様)、f_encodingnull (RFC 2231符号化) とします。
    補足: RFC2047符号化を設定すると、Mail_mimeは正しく符号化してくれません (マルチバイト文字の途中で折り返されたりします)。でも、もともと間違った仕様なのですから、符号化自体の間違いには目をつぶることにします。
  • h_charsetは「The character set of the headers」です。ファイル名の符号化に使われるのはcharsetではなくこちらです。'ISO-2022-JP'のままでよいです。
$subject = "メール:";
$jis = mb_convert_encoding($subject, 'ISO-2022-JP', 'UTF-8');
$encsubj = mb_encode_mimeheader($jis, 'ISO-2022-JP', 'B');

事前にISO-2022-JPに変換すると正しく符号化できません (マルチバイト文字の途中で折り返されたりする)。次のようにUTF-8の文字列を直接mb_encode_mimeheader()に与えて符号化します[注3]。

$subject = "メール:";
$encsubj = mb_encode_mimeheader($subject, 'ISO-2022-JP', 'B', "\n");

ちなみに、第4引数の"\n"は下記と同じで、Mailを使う場合に必要です。既定値の"\r\n"では、ヘッダの途中に余分な改行が入るなどのトラブルに見舞われることがあります。

マニュアルのParameterの項の「Note」では「(...) if you want to send the generated MIME message using Mail then you have to set eol to "\n"」と書かれています。ですので、Mail_mimeのインスタンス化の際に次のパラメタ設定も行う必要があります。

$mime->setParam('eol', "\n");

修正すべきと思われる点は以上です。

ちなみに、以上の説明では内部エンコーディングとソースコードの文字コードがいずれもUTF-8であることを前提としています。ですが念のため、符号化の処理が正しく動作するよう、最初に次の処理をしておいたほうがいいでしょう。

mb_internal_encoding('UTF-8');

 結果

mb_internal_encoding('UTF-8');                                  // 追加

// 文字コードを ISO-2022-JP に変える
mb_convert_variables('ISO-2022-JP', 'UTF-8', $body, $filename);

// 各 mime パートの構築
$mime = new Mail_mime;
$mime->setParam('eol', "\n");                                   // 追加
$mime->setParam('text_charset', 'ISO-2022-JP');
$mime->setParam('text_encoding', '7bit');                       // 修正
$mime->setTxtBody($body);
$mime->addAttachment($file_path // data
                     ,'application/octet-stream'  // content-type
                     ,$filename // attached file name
                     ,false // isfile
                     ,'base64' // encoding
                     ,'attachment' // disposition
                     ,'' // charset
                     ,'' // language
                     ,'' // location
                     ,'base64' // n_encoding
                     ,null // f_encoding                        // 修正
                     ,'' // description
                     ,'ISO-2022-JP' // h_charset
    );

$subject = "メール: メール: メール: メール: メール";
$encsubj = mb_encode_mimeheader($subject, 'ISO-2022-JP', 'B', "\n", 9); // 修正

$headers = array(
    'From' => 'hoge@hogehoge.net',
    'To' => $recpts,
    'Subject' => $encsubj );

$headers = $mime->headers($headers);
$body = $mime->get();

$mail = Mail::factory('smtp', array('host' => 'localhost'));
$mail->send($recpts, $headers, $body);

 注

[1] RFC 1468.
[2] たとえば moji_memo.「日本語の添付ファイル名のエンコーディング」を参照。
[3] ルーキーの中のひと.「mb_encode_mimeheader()の文字化けについて」.

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/10/09 13:23 編集

    大変細かいご指摘ありがとうございます!
    まったく理解していない部分が多くありました。

    ただ、ご指摘いただいた修正をしても直りません。
    修正をして

    '''
    $mime->addAttachment($file_path // data
    ,'application/octet-stream' // content-type
    ,$filename // attached file name
    ,false // isfile
    ,'base64' // encoding
    ,'attachment' // disposition
    ,'' // charset
    ,'' // language
    ,'' // location
    ,'base64' // n_encoding
    ,null // f_encoding // 修正
    ,'' // description
    ,'ISO-2022-JP' // h_charset
    '''
    をいれるとファイルが壊れます。
    ファイル名は正しく送られます。

    '''
    $mime->addAttachment($file_path ,$filename ); // data
    '''
    にすると

    ファイル名は文字化けしますが
    添付ファイルは正しく送られてきます。

    申し訳ありませんが、御教授よろしくお願いいたします。

    キャンセル

  • 2016/10/09 14:00

    Mail_mimeとMailのバージョンはなんでしょうか。私はMail_mime 1.8.4とMail1.2.0で動作を確認しました。

    キャンセル

0

以下を参考にされてはどうでしょうか。
http://hideohideo.com/archives/916

charsetの指定が必要かもしれません。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/10/08 01:11

    ありがとうございます!
    chersetを ,'ISO-2022-JP' // charset にすると
    ファイル名は文字化けせず届くのですが、
    ファイルが壊れて開きません。

    chersetを 指定しなければファイル名は文字化けしますが
    添付ファイルはちゃんと開きます

    申し訳ありませんが、お力添えください。

    キャンセル

  • 2016/10/20 11:02

    やはりだめです。
    ご提案いただいた方法だと
    ファイル名は正常に文字化けせず添付ファイルがきますが
    ファイルが空です(0kb)となります。

    大変困っています。
    よろしくお願いいたします。

    キャンセル

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

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

関連した質問

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