电子邮件地址不仅仅包含以下部分:
下一行的完整字符串(包括引号之间的部分、引号本身和尖括号)也是有效地址:
“John Doe”<[电子邮件受保护]>
当我用自己的名字替换“John Doe”时,我会得到一个地址,我可以在我的电子邮件客户端中输入该地址而不会收到任何投诉(请注意我姓氏中的“ö”,这是一个非-ascii 字符):
“Hubert Schölnast”<[电子邮件受保护]>
因此(对于 Thunderbird 等标准电子邮件客户端的用户而言),引用部分中的特殊字符似乎是可以的。
但是当我使用 cpan-module Email::Valid 在 perl 脚本中检查这个完整的电子邮件地址时,我收到一个错误,说该地址与 rfc822 的规则不匹配,并且该模块的文档说,rfc822 不允许电子邮件地址的任何部分包含任何非 ASCII 字符。 (当我省略字母 ö 或将其替换为 ascii 字母时,检查表明该地址有效。)
显然,任何电子邮件客户端都必须在将电子邮件发送到 smtp 服务器之前对电子邮件地址进行编码,并且在收到新电子邮件时必须对其进行解码并向用户显示标头信息。但我不知道这是怎么做到的,我真的尽力了谷歌搜索。
我需要这个编码算法,因为我想编写一个 perl 脚本,它接受任何有效的电子邮件地址(也在引用部分中包含特殊字符),然后将电子邮件发送到这些地址。
Perl 核心有
Encode.pm
:
#!/usr/bin/perl
use strict;
use warnings;
use Encode;
my $from_header = decode_utf8 q{From: "Hubert Schölnast" <[email protected]>};
print encode('MIME_Header', $from_header);
1;
__END__
From: "=?UTF-8?B?SHViZXJ0IFNjaMO2bG5hc3Q=?=" <[email protected]>
RFC822/2822 背后有很多要求,导致处理电子邮件变得困难。
RFC2822 还禁止消息中的每一行超过 998 个字符。 必须通过缩进连续行将长行分成多行。
这意味着每当我们在转换特殊字符并在前面添加标题标签之后修改它们时,我们都必须注意行的长度。
参见:
https://metacpan.org/pod/Encode::MIME::Header#BUGS
最直接的替代方案是同时使用Email::MIME
和
Email::Address::XS
,尽管这些包不在核心中:
#!/usr/bin/perl
use strict;
use warnings;
use utf8;
use open qw/:std :encoding(UTF-8)/;
use Email::Address::XS;
use Email::MIME::Header::AddressList;
my $address = Email::Address::XS->new('Hubert Schölnast' => '[email protected]');
my $addr_list = Email::MIME::Header::AddressList->new($address);
print $addr_list->as_mime_string;
1;
__END__
=?UTF-8?B?SHViZXJ0IFNjaMO2bG5hc3Q=?= <[email protected]>
MIME::Words 对地址、主题等进行编码或解码。
例如创建电子邮件时:
#!/usr/bin/perl
use strict;
use warnings;
use utf8;
use MIME::Words qw{ encode_mimeword };
my $encoded = encode_mimeword('Hubert Schölnast');
要将姓名与地址编码,请使用
encode_mimewords
。处理电子邮件时,请使用
decode_mimewords
。
print Email::MIME::Header::AddressList->from_string("Hubert Schölnast <[email protected]>, John Doe <[email protected]>")->as_mime_string
如您所见,此解决方案也适用于多个地址,例如在 CC 标头中。