Email::Stuffer与MIME::Base64编码差异及UTF-8影响解析
问题原因分析
1. 未添加use utf8;的情况
你的源码是UTF-8编码,但Perl默认不会解析源码中的UTF-8字符串字面量,所以$text = 'Ümläut'实际是UTF-8字节组成的字节字符串:
MIME::Base64::encode_base64直接对这些字节编码,得到正确的UTF-8字节Base64结果w5xtbMOkdXQ=。- 但
Email::Stuffer处理邮件头时,会将输入的字节字符串默认按Latin-1解码为Unicode字符(Perl的默认行为),再重新编码为UTF-8字节后做Base64。比如原UTF-8字节0xC3 0x9C(对应Ü)会被解码为Latin-1的Ã和¤两个字符,再编码为UTF-8就变成0xC3 0x83 0xC2 0x9C,最终Base64结果为w4PCnG1sw4PCpHV0,解码后自然出现乱码Ãmläut。
2. 添加use utf8;的情况
use utf8;告诉Perl将源码中的UTF-8字符串字面量解析为Unicode字符串:
print直接输出Unicode字符串时,Perl默认不会将其转换为终端的UTF-8编码,导致终端显示乱码(�)。MIME::Base64::encode_base64处理Unicode字符串时,会将其按Latin-1转换为字节再编码,得到错误的Base64结果3G1s5HV0。- 而
Email::Stuffer会正确将Unicode字符串编码为UTF-8字节后再做Base64,所以得到正确的w5xtbMOkdXQ=,解码后显示正常。
解决方法
要让MIME::Base64和Email::Stuffer编码结果一致,需要统一字符串的编码处理逻辑:
- 必须添加
use utf8;,确保Perl正确解析源码中的UTF-8字面量为Unicode字符。 - 使用
Encode模块的encode_utf8函数,将Unicode字符串转换为UTF-8字节后,再传给MIME::Base64编码。 - 输出时,同样用
encode_utf8将Unicode字符串转换为UTF-8字节,确保终端正确显示。
修正后的代码
use strict; use warnings; use utf8; use Encode qw(encode_utf8 decode_utf8); use Email::Stuffer; use MIME::Base64; my $text = 'Ümläut'; # 将Unicode字符串转为UTF-8字节后编码 my $b64 = encode_base64(encode_utf8($text), ''); print encode_utf8("$text in base64: $b64\n"); # 解码时先Base64解码,再转Unicode字符串 my $decoded = decode_utf8(decode_base64($b64)); print encode_utf8("and back: $decoded\n"); my $stuffer = Email::Stuffer->subject($text); my $dump = $stuffer->as_string(); print encode_utf8("Mail dump:\n---\n$dump\n---\n"); $dump =~ m{^Subject:\s*=\?UTF-8\?B\?(.+)\?=}m; my $encoded_subj = $1; print encode_utf8("in Subject: $encoded_subj\n"); # 邮件头的Base64是UTF-8字节的编码,解码后转Unicode字符串 my $decoded_subj = decode_utf8(decode_base64($encoded_subj)); print encode_utf8("subject decoded: $decoded_subj\n");
预期输出
Ümläut in base64: w5xtbMOkdXQ= and back: Ümläut Mail dump: --- Date: Sat, 7 Oct 2023 16:32:50 -0500 MIME-Version: 1.0 Subject: =?UTF-8?B?w5xtbMOkdXQ=?= --- in Subject: w5xtbMOkdXQ= subject decoded: Ümläut
内容的提问来源于stack exchange,提问作者Robert
相关产品推荐
相关产品推荐

