电子邮件地址是否打算成为全世界唯一的ASCII码?
没有; 其实恰恰相反。电子邮件地址 是 ASCII只。它们 旨在 成为Unipre,而我们正在那里。这只是一个缓慢的过渡。
在现代电子邮件中,电子邮件地址分为两部分:1
DNS主机名(位于后面的部分
@)和该主机上的邮箱(位于之前的部分
@)。它们受完全不同的标准支配,因为DNS必须为HTTP和除电子邮件之外的所有其他方式工作。
DNS的上一次更新是在1987年的RFC
1035中,它规定了ASCII的受限子集(以及不区分大小写)。
但是,RFC
5890中指定的IDNA(应用程序国际化域名)允许应用程序有选择地将Unipre字符集的很大一部分映射到DNS名称,以呈现给用户。
因此,您不能拥有域名
dómain.com。但是您 可以 拥有域名
xn--dmain-0ta.com。并且许多应用程序会接受
dómain.com用户输入并自动进行翻译,然后接受
xn--dmain-0ta.com网络并将其显示为
dómain.com。2
在Python中,一些用于互联网协议的库会自动为您IDNA编码域名;否则不会。如果没有,则可以手动进行操作,如下所示:
>>> 'dómain.com'.enpre('idna')b'xn--dmain-0ta.com'请注意,在3.x中,这是a
bytes,而不是a
str;如果您需要
str,则可以随时执行以下操作:
>>> 'dómain.com'.enpre('idna').depre('ascii')'xn--dmain-0ta.com'邮箱名称由SMTP定义,最近一次在RFC 5321和RFC
5322中定义,这清楚地表明,如何解释地址的“本地部分”完全取决于接收主机。例如,大多数电子邮件服务器使用不区分大小写的名称。许多允许“加标签”(例如,
shule@gmail.com并且
shule+so@gmail.com是同一邮箱);一些(例如gmail)忽略所有点;等等
问题是SMTP从未指定标头使用什么字符集。传统的SMTP服务器仅是7位ASCII,因此直到最近,实际上,您只能在标题中使用ASCII,因此在邮箱名称中也只能使用ASCII。
RFC
6530和相关提案中指定的EAI(电子邮件地址国际化)允许在SMTP会话中协商UTF-8。在UTF-8会话中,标头以及这些标头中的地址被解释为UTF-8。(主机名的IDNA编码不是必需的,但仍然允许。)
太好了,但是如果您的客户端,服务器,收件人的服务器或任何中继服务器在此过程中不讲SMTPUTF8,该怎么办?为了处理这种情况,每个拥有UTF-8邮箱的人也都对该邮箱使用ASCII名称。理想情况下,该消息将与消息一起发送,并且当链中的最后一个SMTPUTF8程序遇到第一个非SMTPUTF8程序时,将切换为ASCII替换。更常见的是,它只是收到一条错误消息,然后将其传播回用户以进行手动处理。3
这个想法是,最终,Internet上的大多数主机都将使用SMTPUTF8,因此您可以使用SMTPUTF8,
úßerñame@dómain.com但是与此同时,您的服务器上
dómain.com有
úßerñame并且
ussernyame作为同一邮箱的别名。任何无法处理SMTPUTF8的人都将看到您(并且必须引用您)为
ussernyame。(实际上,他们的邮件客户端会将您视为
ussernyame@xn--dmain-0ta.com,但它可以修复最后一部分;如果在运输过程中丢失了第一部分,它将无能为力。)
截至2018年中,大多数主机不讲SMTPUTF8,许多客户端库也不讲。
从Python
3.5(4)开始,标准库
smtplib支持
SMTPUTF8。如果您正在使用高级
sendmail功能:
如果
SMTPUTF8mail_options中包含且服务器支持,则 from_addr 和 to_addrs 可能包含非ASCII字符。
因此,您要做的是这样的:
try: server.sendmail([fromaddr], [toaddr], msg, mail_options=['SMTPUTF8'])except SMTPNotSupportedError: server.sendmail([fromaddr_ascii], [toaddr_ascii], msg)
(从理论上讲,最好使用来检查EHLO响应
has_extn,但在实践中,只需尝试似乎更平稳即可。随着服务器生态系统和/或将来的改进,这种情况可能会改变
smptlib。)
你从哪里得到的是
fromaddr_ascii和
toaddr_ascii?这取决于您的程序。在DNS部分,您只使用IDNA,但是对于邮箱部分,则没有这样的规则。您必须知道邮箱的备用ASCII邮箱名称。也许你问用户。也许您有一个数据库,其中存储了具有EAI和传统地址的联系人。也许您只担心一个特定的域,并且知道它使用了可以实施的某些规则。
1.实际上,addr-spec由两部分组成;一个 地址 是一个地址规格的加上可选的显示名称和注释。但是没关系。
2.有一些例外。例如,如果键入
http://staсkoverflow.com,则浏览器可能警告您,西里尔小写Es代替拉丁小写Cee可能是劫持尝试。或者,如果您尝试导航到
http://dómain.com,则错误页面可能会告诉您该域不存在的错误页面
xn--dmain-0ta.com,因为这对于调试更有用。
3.这是希望随着时间的推移会变得更好的事情之一,但是可能直到变得无所谓后,它才能变得不够好……
4.如果您使用的是Python
3.4或2.7,该怎么办?那么您就没有SMTPUTF8支持。升级,而不是寻找第三方库
smtplib,或者编写您自己的SMTP代码。



