如何编码 e-mail-adresses 中的特殊字符
How to encode special characters in e-mail-adresses
E-Mail-Adresses不只包含这部分:
localpart@domain.tld
下一行的完整字符串(包括引号之间的部分、引号本身和尖括号)也是一个有效地址:
"John Doe" <localpart@domain.tld>
当我用自己的名字替换 "John Doe" 时,我得到了一个地址,我可以将其输入 E-Mail-Client 而不会收到任何投诉(注意 »ö« 我的姓是 non-ascii-character):
"Hubert Schölnast" <localpart@domain.tld>
看起来(对于像 Thunderbird 这样的标准 e-mail 客户端的用户来说),好像引用部分中的特殊字符是可以的。
但是当我用 cpan-module Email::Valid 检查 perl-script 中这个完整的 e-mail 地址时,我得到一个错误,说这个地址不符合 rfc822 的规则,并且这个模块的文档说,rfc822 不允许 non-ascii-character 在 e-mail 地址的任何部分。 (当我省略字母 ö 或将其替换为 ascii-letter 时,检查表明地址有效。)
所以显然任何 e-mail 客户端在发送 e-mail 到 smtp-server 之前必须对 e-mail 地址进行编码,并且在收到新的 smtp-server 时必须对其进行解码e-mail 并向用户显示 header-information。但是我不知道这是怎么做到的,我真的用谷歌搜索了。
我需要这个 encoding-algorithm 因为我想写一个 perl-script 接受任何有效的 e-mail-地址(在引用部分也有特殊字符)然后发送 e-mails 到那些地址。
使用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
。
Perl 核心有 Encode.pm
:
#!/usr/bin/perl
use strict;
use warnings;
use Encode;
my $from_header = decode_utf8 q{From: "Hubert Schölnast" <localpart@domain.tld>};
print encode('MIME_Header', $from_header);
1;
__END__
From: "=?UTF-8?B?SHViZXJ0IFNjaMO2bG5hc3Q=?=" <localpart@domain.tld>
背后有很多要求RFC822/2822,这使得处理电子邮件变得困难。
RFC2822 也禁止消息中的每行超过 998 个字符。
必须通过缩进续行来将长行拆分为多行。
这意味着只要我们在 转换特殊字符并在 header 标签之前 之后修改它们,我们就必须注意行的长度。
编辑
从Encode.pm版本2.80开始,MIME-Header编码被重写以符合RFC2047,我上面贴的原始代码现在不能用了。
参见:https://metacpan.org/pod/Encode::MIME::Header#BUGS
最 straight-foward 的选择是同时使用 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' => 'localpart@domain.tld');
my $addr_list = Email::MIME::Header::AddressList->new($address);
print $addr_list->as_mime_string;
1;
__END__
=?UTF-8?B?SHViZXJ0IFNjaMO2bG5hc3Q=?= <localpart@domain.tld>
E-Mail-Adresses不只包含这部分:
localpart@domain.tld
下一行的完整字符串(包括引号之间的部分、引号本身和尖括号)也是一个有效地址:
"John Doe" <localpart@domain.tld>
当我用自己的名字替换 "John Doe" 时,我得到了一个地址,我可以将其输入 E-Mail-Client 而不会收到任何投诉(注意 »ö« 我的姓是 non-ascii-character):
"Hubert Schölnast" <localpart@domain.tld>
看起来(对于像 Thunderbird 这样的标准 e-mail 客户端的用户来说),好像引用部分中的特殊字符是可以的。
但是当我用 cpan-module Email::Valid 检查 perl-script 中这个完整的 e-mail 地址时,我得到一个错误,说这个地址不符合 rfc822 的规则,并且这个模块的文档说,rfc822 不允许 non-ascii-character 在 e-mail 地址的任何部分。 (当我省略字母 ö 或将其替换为 ascii-letter 时,检查表明地址有效。)
所以显然任何 e-mail 客户端在发送 e-mail 到 smtp-server 之前必须对 e-mail 地址进行编码,并且在收到新的 smtp-server 时必须对其进行解码e-mail 并向用户显示 header-information。但是我不知道这是怎么做到的,我真的用谷歌搜索了。
我需要这个 encoding-algorithm 因为我想写一个 perl-script 接受任何有效的 e-mail-地址(在引用部分也有特殊字符)然后发送 e-mails 到那些地址。
使用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
。
Perl 核心有 Encode.pm
:
#!/usr/bin/perl
use strict;
use warnings;
use Encode;
my $from_header = decode_utf8 q{From: "Hubert Schölnast" <localpart@domain.tld>};
print encode('MIME_Header', $from_header);
1;
__END__
From: "=?UTF-8?B?SHViZXJ0IFNjaMO2bG5hc3Q=?=" <localpart@domain.tld>
背后有很多要求RFC822/2822,这使得处理电子邮件变得困难。
RFC2822 也禁止消息中的每行超过 998 个字符。 必须通过缩进续行来将长行拆分为多行。
这意味着只要我们在 转换特殊字符并在 header 标签之前 之后修改它们,我们就必须注意行的长度。
编辑
从Encode.pm版本2.80开始,MIME-Header编码被重写以符合RFC2047,我上面贴的原始代码现在不能用了。
参见:https://metacpan.org/pod/Encode::MIME::Header#BUGS
最 straight-foward 的选择是同时使用 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' => 'localpart@domain.tld');
my $addr_list = Email::MIME::Header::AddressList->new($address);
print $addr_list->as_mime_string;
1;
__END__
=?UTF-8?B?SHViZXJ0IFNjaMO2bG5hc3Q=?= <localpart@domain.tld>