メモ  > C# > .NET Framework 4のメール送信で、長い日本語ファイル名の添付をする方法

.NET Framework 4のメール送信で、長い日本語ファイル名の添付をする方法

.NET Framework 4のSystem.Net.Mail.SmtpClientでメールを送信する際
長い日本語ファイル名の添付でエラーが発生して送信ができない事象が発生しました。
以下がその時のエラー内容となります。

System.IO.IOException: 転送接続にデータを書き込めません: 既存の接続はリモート ホストに強制的に切断されました。。 ---> System.Net.Sockets.SocketException: 既存の接続はリモート ホストに強制的に切断されました。
   場所 System.Net.Sockets.NetworkStream.Write(Byte[] buffer, Int32 offset, Int32 size)

パケットキャプチャをしたところ、原因はメール内容にLF改行が含まれていたせいとなります。(bare LF問題)
なぜ、LF改行が存在していたかというと、長い日本語ファイル名の添付ファイルが原因でした。
こちらのサイトに詳しく記載されておりますのでご参照ください。
.NET Framework 4 のメール送信で、長い日本語ファイル名の添付に失敗する原因を追ってみた
Attachment.PrepareForSendingがSystem.Net.Mail.Attachmentの
プライベートなメンバ変数nameの値を利用して再変換をかけているので
リフレクションを利用してエンコード済みの文字列に値を書き換えることで解決しました。

MailMessage msg = new MailMessage();

string filePath = @"C:\あかさたなはまやらわあかさたなはまやらわ.txt";

System.Net.Mail.Attachment at = new System.Net.Mail.Attachment(filePath);

// ファイル名をRFC2047形式にエンコード
string fileName = new System.IO.FileInfo(filePath).Name;
fileName = System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(fileName));
fileName = string.Format("=?{0}?B?{1}?=", System.Text.Encoding.UTF8.BodyName, fileName);

// エンコード後文字列をSystem.Net.Mail.Attachmentのプライベートなメンバ変数nameに代入
System.Type t = typeof(System.Net.Mail.Attachment);
t.InvokeMember("name", System.Reflection.BindingFlags.Public
                     | System.Reflection.BindingFlags.NonPublic
                     | System.Reflection.BindingFlags.Instance
                     | System.Reflection.BindingFlags.SetField,
                null,
                at,
                new object[] { fileName });
msg.Attachments.Add(at);

実行結果

Content-Type: application/octet-stream; name="=?utf-8?B?44GC44GL44GV44Gf44Gq44Gv44G+44KE44KJ44KP44GC44GL44GV44Gf44Gq44Gv44G+44KE44KJ44KPLnR4dA==?="

関連するページ

メモ  > PHP > 変数関連
メモ  > JavaScript > 文字列関連
メモ  > Android > Galaxy S2 LTE(SC-03D)の電池アイコンを変更する
メモ  > Java > 文字列関連
メモ  > Java > java.text.MessageFormat