Email::MIMEでのパースで本文が文字化けする場合
Email::MIMEでメールをパースした情報は各メソッドでデコードされた状態で値を取得できるのですが、メール本文がうまくデコードされない場合もあります。
メール処理をするCGIのプロトタイプを作成してる際にこのケースに遭遇しました。その時はメールのパース以降の処理で試してみたいことがあったので、ちゃんとした原因究明はしてないのですが、そういうレベルで問題ないのなら
- Email::MIMEのbody_rawメソッドで本文を取得
- Encode::Guessでメール本文の文字コードを解析
- Encodeを利用してデコード
という手順で応急処置が可能です。なお、Email::MIMEのbody_rawは対象となるメール本文をデコードしない状態で取得するメソッドです。サンプルを用意してみるとこんな感じになります。
use strict; use warnings; use utf8; use Encode qw(decode encode); use Encode::Guess qw(euc-jp shiftjis 7bit-jis); use Net::POP3; use Email::MIME; my $server = 'mail.example.com'; my $account = 'hoge'; my $password = 'bar'; my $pop3 = Net::POP3->new($server) or die 'can not open account.'; my $count = $pop3->login($account, $password); my $messages = $pop3->list; my $layout = << 'TMPL'; [TITLE] %s [BODY] %s TMPL for my $id ( sort { $a <=> $b } keys %{ $messages } ) { my $mail = join q(), @{ $pop3->get($id) }; my $parsed = Email::MIME->new($mail); print sprintf $layout, encode( 'utf8', $parsed->header('Subject') ), encode( 'utf8', decode('Guess', $parsed->body_raw) ) ; } $pop3->quit; 1;
Perl 5.8.x Unicode関連の情報によるとEnocdeの作者である小飼弾さん自身がEncode::Guessを利用する際の心得として、
- 出来れば使わない
- 使う場合は、データ全部をいっぺんに渡す
- Guessしなかった場合のエラー処理をきちんとする
とされてるそうなので、特に注意してください。