如何对电子邮件地址中的特殊字符进行编码

Hub*_*ast 4 email perl encoding special-characters

电子邮件地址不仅仅包含以下部分:

\n\n
\n

localpart@domain.tld

\n
\n\n

下一行中的完整字符串(包括引号之间的部分、引号本身和尖括号)也是有效地址:

\n\n
\n

“约翰·多伊”<localpart@domain.tld>

\n
\n\n

当我用我自己的名字替换“John Doe”时,我得到一个地址,我可以在我的电子邮件客户端中输入该地址而不会收到任何投诉(请注意 \xc2\xbb \xc3\xb6 \xc2\xab非 ASCII 字符的姓氏):

\n\n
\n

“休伯特·施\xc3\xb6lnast”<localpart@domain.tld>

\n
\n\n

所以看起来(对于像 Thunderbird 这样的标准电子邮件客户端的用户来说),引用部分中的特殊字符似乎是可以的。

\n\n

但是当我使用 cpan-module Email::Valid在 perl 脚本中检查这个完整的电子邮件地址时,我收到一个错误,说这个地址与 rfc822 的规则不匹配,并且这个模块的文档说, rfc822 不允许电子邮件地址的任何部分包含任何非 ASCII 字符。(当我省略字母\xc3\xb6或将其替换为 ascii 字母时,检查表明该地址有效。)

\n\n

显然,任何电子邮件客户端在将电子邮件发送到 smtp 服务器之前都必须对电子邮件地址进行编码,并且在收到新电子邮件并向用户显示标头信息时必须对其进行解码。但我不知道这是怎么做到的,我真的尽力了谷歌搜索。

\n\n

我需要这个编码算法,因为我想编写一个 perl 脚本,它接受任何有效的电子邮件地址(也在引用部分中包含特殊字符),然后将电子邮件发送到这些地址。

\n

ern*_*nix 5

Perl 核心有Encode.pm

\n
#!/usr/bin/perl\nuse strict;\nuse warnings;\nuse Encode;\n\nmy $from_header = decode_utf8 q{From: "Hubert Sch\xc3\xb6lnast" <localpart@domain.tld>};\nprint encode(\'MIME_Header\', $from_header);\n\n1;\n__END__\nFrom: "=?UTF-8?B?SHViZXJ0IFNjaMO2bG5hc3Q=?=" <localpart@domain.tld>\n
Run Code Online (Sandbox Code Playgroud)\n

RFC822/2822 背后有很多要求,导致处理电子邮件变得困难。

\n

RFC2822 还禁止消息中的每一行超过 998 个字符。\n必须通过缩进连续行将长行拆分为多行。

\n

这意味着每当我们在转换特殊字符并在前面添加标题标签之后修改它们时,我们都必须注意行长度。

\n
\n

编辑

\n

从Encode.pm版本2.80开始,MIME-Header编码被重写以符合RFC2047,我上面发布的原始代码现在无法使用。

\n

请参阅: https: //metacpan.org/pod/Encode::MIME ::Header#BUGS

\n

最直接的替代方案是同时使用Email::MIMEEmail::Address::XS,但这些包不在核心中:

\n
#!/usr/bin/perl\nuse strict;\nuse warnings;\nuse utf8;\nuse open qw/:std :encoding(UTF-8)/;\n\nuse Email::Address::XS;\nuse Email::MIME::Header::AddressList;\n\nmy $address = Email::Address::XS->new(\'Hubert Sch\xc3\xb6lnast\' => \'localpart@domain.tld\');\nmy $addr_list = Email::MIME::Header::AddressList->new($address);\n\nprint $addr_list->as_mime_string;\n\n1;\n__END__\n=?UTF-8?B?SHViZXJ0IFNjaMO2bG5hc3Q=?= <localpart@domain.tld>\n
Run Code Online (Sandbox Code Playgroud)\n