none
メール送信で日本語のファイル名で添付すると文字化けする

    質問

  • お世話になっております。

    メール送信プログラムを作成していて問題が発生しております。

    ※VS2010、.netFramework4で実装

     

    下記のようなプログラムで送信すると文字化けが起こります。

     

    var file = new Attachment( @"C:\Users\hoge\Pictures\テスト用の長めのファイル名です.pdf");

    var message = new MailMessage();
    message.To.Add(new MailAddress( "hoge@foo.co.jp" ));
    message.From = new MailAddress( "test@foo.co.jp" );
    message.Subject = "test";
    message.Body = "test";
    message.Attachments.Add( file );

    var smtp = new SmtpClient( "mail.foo.co.jp" );
    smtp.Send( message );

     

    送信されてくる添付ファイル名は

    =_utf-8_B_44OG44K544OI55So44Gu6ZW344KB44Gu.dat

    こんな感じになります。

     

    どうもエンコードの問題だと思うのですが、対応方法がわからず苦慮しております。

    どなたか解決方法を知っている方がいればご教授いただければ幸いです。

     

     

    2011年10月24日 7:40

回答

すべての返信

  • 以下などが参考になると思います。

    JISコード(JIS-2022-JP)でメールを送信するには?[2.0のみ、C#、VB]
    http://www.atmarkit.co.jp/fdotnet/dotnettips/696jismail/jismail.html

    SmtpClientクラスを使ってメールを送信する
    http://dobon.net/vb/dotnet/internet/smtpclient.html

     


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    2011年10月24日 8:19
    モデレータ
  • 返信ありがとうございます。

     

    私の書き方に問題があったのですが

    Subjectなどの文字列に関しては、上げていただいたサイトのように自前でBase64にエンコードした実装をしてまして

    改行などによる文字化けは回避できています。

     

    しかし添付ファイル名だけは、同様の方法を取ってもエンコードされた文字列を

    更にエンコードされているような感じでメーラで表示されてしまいます。

    2011年10月24日 9:45
  • エンコーディングやメーラーには何を使っているかぐらいの情報は書きましょ
    う。

    UTF-8 と iso-2022-jp の場合ですが、以下のページが参考になりませんか?

    SmtpClient でメール送信
    http://surferonwww.info/BlogEngine/post/2010/09/07/Sending-mail-by-using-SmtpClient.aspx

    このように FileName が設定してあると Windows Mail ではこちらを使うよう
    です。

    disposition.FileName =
      EncodeMailHeader(System.IO.Path.GetFileName(file), enc);

     

     

    2011年10月24日 12:44
  • 返信ありがとうございます。

     

    エンコードは、UTF-8でメーラはOutlookです。

    メーラはそれ以外でも同様の状態のようです。

    現在、メール送信を試せる環境にないので明日、試してみます。

    2011年10月24日 13:46
  • アドバイス頂きましてありがとうございました。

    なんとか回避できましたので結果の記載しておきます。

    ※解決ってほど納得行く感じではないですが

     

    private void button1_Click( object sender, EventArgs e )
    {
        var filepath = @"C:\Users\hoge\Pictures\テスト用の長めのファイル名です.pdf";
        var fs = new System.IO.StreamReader( filepath );

    // ファイル名を使用するコンストラクタだと2重にエンコードがかかるのでストリームの方で
        var file = new Attachment( fs.BaseStream, MediaTypeNames.Application.Octet );

        var disposition = file.ContentDisposition;
        var enc = System.Text.Encoding.GetEncoding( "utf-8" );
        disposition.FileName = EncodeMailHeader( "テスト用の長めのファイル名です.pdf", enc );

        var message = new MailMessage();

        message.To.Add(new MailAddress( "hoge@foo.co.jp" ));
        message.From = new MailAddress( "test@foo.co.jp" );
        message.Subject = "test";
        message.Body = "test";
        message.Attachments.Add( file );


        var smtp = new SmtpClient( "mail.foo.co.jp" );
        smtp.Send( message );
    }

    private string EncodeMailHeader( string str, Encoding enc )
    {
        var ret = System.Convert.ToBase64String( enc.GetBytes( str ) );
        ret = string.Format( "=?{0}?B?{1}?=", enc.BodyName, ret );
        return ret;
    }

     

    どうもこちらのブログを拝見すると.netFramework4だけ起こる現象みたいです。

    http://d.hatena.ne.jp/do_aki/20110513/1305257394

     

    AttachmentクラスのNameプロパティに値が入らないようにして

    ContentDispositionクラスのFileNameプロパティにファイル名を入れておけば回避できるっぽいです。

     

    2011年10月25日 9:27
  • > どうもこちらのブログを拝見すると.netFramework4だけ起こる現象みたいです。

    こちらで検証した限りでは、確かに ,NET 3.5 と .NET 4 では以下のように改行の
    有無が異なりますが、正しい形式で正しく改行されるので、長い日本語のファイル
    名も正しく取得できます。

    メーラーは Windows メールしか試してませんが、形式は正しいので、たぶん他の
    メーラーでも正しくファイル名を取得できると思います。

    <.NET 3.5>

    Content-Type: application/octet-stream;
     name="=?utf-8?B?5pel5pys6Kqe44Gu6ZW344GE5ZCN5YmN44Gu44OU44O844OH44Kj44O844Ko44OV44OV44Kh44Kk44Or44Gn44GZLnBkZg==?="
    Content-Transfer-Encoding: base64

     

    <.NET 4>

    Content-Type: application/octet-stream;

     name="=?utf-8?B?5pel5pys6Kqe44Gu6ZW344GE5ZCN5YmN44Gu44OU44O844OH44Kj44O8?=

     =?utf-8?B?44Ko44OV44OV44Kh44Kk44Or44Gn44GZLnBkZg==?="

    Content-Transfer-Encoding: base64

    Content-Disposition: attachment

     

    以下が検証に使ったコードです。

    ちなみに、コメントアウトした部分をもとにもどして ContentDisposition.FileName
    を設定すれば、そちらの方が使われるようになります。

    private void button1_Click(object sender, EventArgs e)
    {
        System.Text.Encoding enc = System.Text.Encoding.GetEncoding("utf-8");
    
        string mailAddress = this.userName + "@" + this.host;
    
        MailAddress to = new MailAddress(mailAddress, EncodeMailHeader("日本花子", enc));
        MailAddress from = new MailAddress(mailAddress, EncodeMailHeader("日本太郎", enc));
    
        MailMessage mailMessage = new MailMessage(from, to);
    
        mailMessage.Subject = textBox1.Text;
        mailMessage.Body = textBox2.Text;
    
        string file = @"C:\Users\PapikoPC\Documents\Personal\日本語の長い名前のピーディーエフファイルです.pdf";
    
        Attachment data = new Attachment(file, MediaTypeNames.Application.Octet);
    
        //ContentDisposition disposition = data.ContentDisposition;
        //disposition.FileName = EncodeMailHeader("別のファイル名.pdf", enc);
        mailMessage.Attachments.Add(data);
    
        SmtpClient smtpClient = new SmtpClient();
        smtpClient.Host = host;
        smtpClient.Port = portSmtp;
    
        try
        {
            smtpClient.Send(mailMessage);
            MessageBox.Show("Your mail was sent.");
        }
        catch (SmtpException ex)
        {
            SmtpStatusCode status = ex.StatusCode;
            MessageBox.Show("SmtpException: " + ex.Message + "\nSmtpStatusCode: " + status.ToString());
        }
        catch (Exception ex)
        {
            MessageBox.Show("Exception: " + ex.Message);
        }
        finally
        {
            mailMessage.Dispose();
        }
    }
    
    private string EncodeMailHeader(string str, System.Text.Encoding enc)
    {
        string ret = System.Convert.ToBase64String(enc.GetBytes(str));
        ret = string.Format("=?{0}?B?{1}?=", enc.BodyName, ret);
        return ret;
    }
    
    

    2011年10月25日 15:19
  • > どうもこちらのブログを拝見すると.netFramework4だけ起こる現象みたいです。

    こちらで検証した限りでは、確かに ,NET 3.5 と .NET 4 では以下のように改行の
    有無が異なりますが、正しい形式で正しく改行されるので、長い日本語のファイル
    名も正しく取得できます。

    メーラーは Windows メールしか試してませんが、形式は正しいので、たぶん他の
    メーラーでも正しくファイル名を取得できると思います。

    <.NET 3.5>

    Content-Type: application/octet-stream;
     name="=?utf-8?B?5pel5pys6Kqe44Gu6ZW344GE5ZCN5YmN44Gu44OU44O844OH44Kj44O844Ko44OV44OV44Kh44Kk44Or44Gn44GZLnBkZg==?="
    Content-Transfer-Encoding: base64

     

    <.NET 4>

    Content-Type: application/octet-stream;

     name="=?utf-8?B?5pel5pys6Kqe44Gu6ZW344GE5ZCN5YmN44Gu44OU44O844OH44Kj44O8?=

     =?utf-8?B?44Ko44OV44OV44Kh44Kk44Or44Gn44GZLnBkZg==?="

    Content-Transfer-Encoding: base64

    Content-Disposition: attachment

    どっちにしてもRFC違反なんですね(--;
    2011年10月26日 0:56
  • 返信ありがとうございます。

     

    記載していただいたコードをそのままコピーして実行させていただいたのですが

    こちらではやはり添付ファイル名は、おかしな状態になってしまいます。

    ターゲットフレームワークを3.5にすると現象は回避できました。

     

    メールヘッダは下記のようになっています。

    <.NET 4>

    Content-Type: application/octet-stream;
     name="=?utf-8?B?PT91dGYtOD9CPzQ0T0c0NEs1NDRPSTU1U280NEd1NlpXMzQ0S0I0NEd1?=\
    "

     =?utf-8?B?NDRPVjQ0S2g0NEtrNDRPcjVaQ040NEduPz0NCiA9P3V0Zi04P0I/NDRH?=\
    \
     =?utf-8?B?WkxuQmtaZz09Pz0=?="
    Content-Transfer-Encoding: base64
    Content-Disposition: attachment

     

    <.NET 3.5>

    Content-Type: application/octet-stream; name="=?utf-8?B?44OG44K544OI55So44Gu6ZW344KB44Gu44OV44Kh44Kk44Or5ZCN44Gn44GZLnBkZg==?="
    Content-Transfer-Encoding: base64

     

    .NET Framework4のバージョンは

    4.0.30319 SP1Rel

    がインストールされています。

     

    2011年10月26日 0:56
  • 4.0.30319 RTMRel

    であれば現象が発生しないことを確認しました。

     

    どうもSP1をあてると発生するっぽいです。

    2011年10月26日 2:15
  • > .NET Framework4のバージョンは
    > 4.0.30319 SP1Rel
    > がインストールされています。

    それは Visual Studio 2010 のヘルプのバージョン情報で表示されたものです
    よね。そうであれば、自分の環境も同じです。

    いろいろ設定を変えて試してみましたが、問題は再現できませんでした。一体、
    何が違うのでしょうね。

     

    2011年10月26日 13:56
  • >それは Visual Studio 2010 のヘルプのバージョン情報で表示されたものです
    よね。

    その通りです。

     

    本当に何が違うのでしょうね?

    こちらは、チームの他メンバーも同様の現象が発生するので

    自分だけってわけでは無いのですが・・・

    2011年10月27日 4:38
  • 開発マシーンではない別の PC でプログラムを動かしたら問題を再現できました。

    で、その PC に以下の Connect のページにある Hotfix KB2183292 を適用すると
    問題は解決しました。

    https://connect.microsoft.com/VisualStudio/Downloads/DownloadDetails.aspx?DownloadID=30226


    ファイル名の二重エンコーディングの問題は、去年、米国の MSDN フォーラムで
    も報告されており(以下のページ参照)、原因が .NET Framework 4 のバグであ
    ることは Microsoft も認識しているようです。

    Bug in System.Net.Mail? (.NET 4)
    http://social.msdn.microsoft.com/Forums/en-US/netfxnetcom/thread/67414337-19a6-4128-b1a0-212404cc2cb1

    その時の MSFT の人の回答(2010/6/23 付け)では、次のリリースを待つか、短
    い名前にするしかないということでした。

    とは言え、現実に問題ない PC があるのは確かですので、何らかの更新プログラ
    ムがリリースされていて、問題が発生しない PC には適用されているはずと思っ
    て調べたら、以下の Connect のページに、Hotfix KB2183292 によってファイル
    名の二重にエンコーディングの問題も解決されるとの話がありました。

    Cannot send E-Mails with large attachments
    http://connect.microsoft.com/VisualStudio/feedback/details/544562/cannot-send-e-mails-with-large-attachments-system-net-mail-smtpclient-system-net-mail-mailmessage

    で、その Hotfix をダウンロードしてインストールしたら問題が出なくなったと
    いうことです。

    Hotfix KB2183292 は、更新プログラム KB2468871 に含まれているらしいのです
    が(以下のページ参照)、それはインストール済みだったにもかかわらず、何故
    かそれではダメでした。

    .NET Framework 4 用の更新プログラム
    http://support.microsoft.com/kb/2468871

    2011年10月28日 12:26
  • ありがとうございます。

    既知の問題だったのですね

    そこまで探し当てられませんでした。

     

    本当に助かりました。

    2011年10月31日 0:16