DOBON.NET DOBON.NETプログラミング掲示板過去ログ

POP3での受信で文字化けしてしまうのですが...

環境/言語:[VB.NET]
分類:[.NET]

「POP3メールサーバーからメールを受信する」を参考にさせていただき、POP3サーバーからメールを受信するプログラムを作成しました。

Receive()のFor文でループしているところで受信したメール本体=msgから、先頭の(メール本体とは関係のない)POP3サーバーからの応答内容と最後の'.'を削除し、その内容をファイルに出力するようにしています。
出力したファイルを見ると、受信したメールの内容(メールのヘッダではなく、本文)によっても処理結果が異なるのですが、メールの本文の「一部」が化けてしまいます。
メールの本文ががすべて化けてしまうとかならまだわかるのですが、メールの本文の内容によって化ける箇所などがまちまちで、全く化けないケースもあります。

NetworkStreamで受信するByte型の配列のサイズを変えてうまくいったようにも見えたのですが(1024とか8192とか固定のサイズから、POPのLIST命令で取得したサイズまでいろいろ試してみました)、いろいろなメールでテストするとその修正でも不十分なようで、うまくいきません。

何か、解決方法や解決のためのヒントなどありましたら、よろしくお願いします。
■No2823に返信(まーくんさんの記事)
ReceiveDataメソッドを次のように直して試していただけますか?

'データを受信する
Private Overloads Shared Function ReceiveData( _
        ByVal stream As NetworkStream, _
        ByVal multiLines As Boolean, _
        ByVal bufferSize As Integer, _
        ByVal enc As Encoding) As String
    Dim data(bufferSize) As Byte
    Dim len As Integer
    Dim msg As String = ""
    Dim ms As New System.IO.MemoryStream

    'すべて受信する
    '(無限ループに陥る恐れあり)
    Do
        '受信
        len = stream.Read(data, 0, data.Length)
        ms.Write(data, 0, len)
        '文字列に変換する
        msg = enc.GetString(ms.ToArray())
    Loop While stream.DataAvailable Or _
        ((Not multiLines Or msg.StartsWith("-ERR")) And _
            Not msg.EndsWith(vbCrLf)) Or _
        (multiLines And Not msg.EndsWith(vbCrLf + "." + vbCrLf))

    ms.Close()

    '"-ERR"を受け取った時は例外をスロー
    If msg.StartsWith("-ERR") Then
        Throw New ApplicationException("Received Error")
    End If
    '表示
    Console.Write(("S: " + msg))

    Return msg
End Function 'ReceiveData
すみません、慌てていてレス記事メールを直接Replyしてしまいました。
改めて、返信ありがとうございます。
以下のコードで早速試してみます。
最近公私共にバタバタしていて、結果報告が遅れるかもしれませんがご了承ください。
ではでは。


> 'データを受信する
> Private Overloads Shared Function ReceiveData( _
> ByVal stream As NetworkStream, _
> ByVal multiLines As Boolean, _
> ByVal bufferSize As Integer, _
> ByVal enc As Encoding) As String
> Dim data(bufferSize) As Byte
> Dim len As Integer
> Dim msg As String = ""
> Dim ms As New System.IO.MemoryStream
>
> 'すべて受信する
> '(無限ループに陥る恐れあり)
> Do
> '受信
> len = stream.Read(data, 0, data.Length)
> ms.Write(data, 0, len)
> '文字列に変換する
> msg = enc.GetString(ms.ToArray())
> Loop While stream.DataAvailable Or _
> ((Not multiLines Or msg.StartsWith("-ERR")) And _
> Not msg.EndsWith(vbCrLf)) Or _
> (multiLines And Not msg.EndsWith(vbCrLf + "." + vbCrLf))
>
> ms.Close()
>
> '"-ERR"を受け取った時は例外をスロー
> If msg.StartsWith("-ERR") Then
> Throw New ApplicationException("Received Error")
> End If
> '表示
> Console.Write(("S: " + msg))
>
> Return msg
> End Function 'ReceiveData

便乗質問ですみません。
前回「SMTPでメール送信にて」で投稿させて頂いたものです。

私も同様の症状でなやんでいます。
管理人さんの書かれた方法(一度MemoryStreamに書き込む)を試して見ましたが、
本文は、正常にエンコードされるのですが、
ヘッダのFromやSubjetの日本語部分は、文字化けしてしまいます。

他に、試すべきことがございましたら、ご教授下さい。
宜しくお願い致します。

■No2854に返信(まーくんさんの記事)
> すみません、慌てていてレス記事メールを直接Replyしてしまいました。
> 改めて、返信ありがとうございます。
> 以下のコードで早速試してみます。
> 最近公私共にバタバタしていて、結果報告が遅れるかもしれませんがご了承ください。
> ではでは。
>
>
>>'データを受信する
>>Private Overloads Shared Function ReceiveData( _
>> ByVal stream As NetworkStream, _
>> ByVal multiLines As Boolean, _
>> ByVal bufferSize As Integer, _
>> ByVal enc As Encoding) As String
>> Dim data(bufferSize) As Byte
>> Dim len As Integer
>> Dim msg As String = ""
>> Dim ms As New System.IO.MemoryStream
>>
>> 'すべて受信する
>> '(無限ループに陥る恐れあり)
>> Do
>> '受信
>> len = stream.Read(data, 0, data.Length)
>> ms.Write(data, 0, len)
>> '文字列に変換する
>> msg = enc.GetString(ms.ToArray())
>> Loop While stream.DataAvailable Or _
>> ((Not multiLines Or msg.StartsWith("-ERR")) And _
>> Not msg.EndsWith(vbCrLf)) Or _
>> (multiLines And Not msg.EndsWith(vbCrLf + "." + vbCrLf))
>>
>> ms.Close()
>>
>> '"-ERR"を受け取った時は例外をスロー
>> If msg.StartsWith("-ERR") Then
>> Throw New ApplicationException("Received Error")
>> End If
>> '表示
>> Console.Write(("S: " + msg))
>>
>> Return msg
>>End Function 'ReceiveData
>
■No2925に返信(きみさんの記事)
> 私も同様の症状でなやんでいます。
> 管理人さんの書かれた方法(一度MemoryStreamに書き込む)を試して見ましたが、
> 本文は、正常にエンコードされるのですが、
> ヘッダのFromやSubjetの日本語部分は、文字化けしてしまいます。

この文字化けとは、エンコードされた文字列ということではなく、まさに文字化けということですか?(もしそうであれば、疑うようなことを聞いてしまい申し訳ありません。)

もし、FromやSubjetをデコードする方法ということであれば、私のサイトで紹介しています。

・メールのサブジェクトをデコードする
http://dobon.net/vb/dotnet/internet/decodemailsubject.html
管理人さん、早速のお返事ありがとうございます。
ご指摘の通りです。
リンクのTipsがずばりでした。

同時に、私が受信メッセージのエンコードについて理解してないことがわかりました。
TIPSに書かれているRFCを熟読いたします。

P.S 元の質問者ではないため、ステータスは変更しません。m(_ _)m

■No2930に返信(管理人さんの記事)
> ■No2925に返信(きみさんの記事)
>>私も同様の症状でなやんでいます。
>>管理人さんの書かれた方法(一度MemoryStreamに書き込む)を試して見ましたが、
>>本文は、正常にエンコードされるのですが、
>>ヘッダのFromやSubjetの日本語部分は、文字化けしてしまいます。
>
> この文字化けとは、エンコードされた文字列ということではなく、まさに文字化けということですか?(もしそうであれば、疑うようなことを聞いてしまい申し訳ありません。)
>
> もし、FromやSubjetをデコードする方法ということであれば、私のサイトで紹介しています。
>
> ・メールのサブジェクトをデコードする
> http://dobon.net/vb/dotnet/internet/decodemailsubject.html
結果報告が大変遅れてしまい、すみません。
取りあえず試した範囲では、問題なく文字化けすることなく処理できました。
ありがとうございました。

ただ、エンコードがquoted-printableのものは当然ながらあのままではダメでした。.NETはBASE64には対応していますが、quoted-printableとなると自力でエンコード・デコードを作成するしかないようですね。(ですよね。)

後、管理人さんに教えていただいたReceiveDataメソッドで1点だけ教えてください。(まだまだ.NETは経験が浅いもので...)
Doループの中の

msg = enc.GetString(ms.ToArray())

ですが、以前のサンプルでは

msg += enc.GetString(data, 0, len)

でした。
改訂版のコードで受信したメールが全行正しく連結されているのは何故なのでしょうか。ご教授ください。

DOBON.NET | プログラミング道 | プログラミング掲示板