考虑Python 3 SMTPD - 收到的数据包含在字符串中。 http://docs.python.org/3.4/library/smtpd.html引用:“和data是包含电子邮件内容的字符串”
事实(对吗?):
因此,输入的电子邮件是纯ASCII(有效的Unicode),因此SMTPD DATA字符串与SMPTD接收的原始字节完全等效。这是对的吗?
因此我的问题是,如果我将SMTPD DATA字符串解码为ASCII,或将DATA字符串转换为字节,这相当于通过SMTP到达的实际电子邮件的字节数?
上下文,(也许是一个更好的问题)是“如何将文件Python 3的SMTPD数据保存为接收的字节?”我担心的是,当DATA经过字符串到字节的转换时,它会以某种方式从通过SMTP到达的原始字节改变。
编辑:似乎Python开发人员认为SMTPD应该返回二进制数据。似乎没有修复...... http://bugs.python.org/issue19662
答案 0 :(得分:4)
如果一个字符串只包含ASCII,它是否与字符串相等?
没有。它在Python 3中不相同:
>>> '1' == b'1'
False
bytes
对象不等于str
(Unicode字符串)对象,其方式类似于整数不等于字符串:
>>> '1' == 1
False
在某些编程语言中,上述比较是正确的,例如,在Python 2中:
>>> b'1' == u'1'
True
Perl中的和1 == '1'
:
$ perl -e "print qq(True\n) if 1 == q(1)"
True
您的问题是为什么更严格的 Python 3行为更可取的一个很好的例子。它迫使程序员面对他们的文本/字节错误概念,而不必等待他们的代码中断某些输入。
- Python 3中的字符串是Unicode。
是肯定的。 Python 3中的Strings are immutable sequences of Unicode code points。
- 电子邮件始终是ASCII。
大多数电子邮件都是以7位消息的形式传输(ASCII范围:十六进制00-7F
)。虽然"virtually all modern email servers are 8-bit clean."即8位内容不会被破坏。并8BITMIME extension制裁了一些8位内容的传递。
换句话说:电子邮件不总是ASCII 。
- 纯ASCII是有效的Unicode。
ASCII是一种字符编码。您可以使用US-ASCII字符编码将解码 某些字节序列转换为Unicode。 Unicode字符串没有关联的字符编码,即,您可以使用任何可以表示相应Unicode代码点的字符编码将编码为字节。
因此,输入的电子邮件是纯ASCII(有效的Unicode),因此SMTPD DATA字符串与SMPTD接收的原始字节完全等效。这是对的吗?
如果输入是在ascii范围内,那么data.decode('ascii', 'strict').encode('ascii') == data
。
虽然Lib/smtpd.py对输入数据进行了一些转换(根据RFC 5321
),但是即使输入是纯ASCII,您获得的data
内容也可能不同。
“我如何将Python 3的SMTPD数据保存为接收的字节?”
我的目标不是找到格式错误的电子邮件,而是将入站电子邮件以精确的二进制/字节格式保存到磁盘。
您链接的错误(smtpd.py should not decode utf-8)使smptd.py非8位清理。
您可以覆盖SMTPChannel.collect_incoming_data
method from smtpd.py
以保存传入的字节。
确实如此。它是UTF-8编码的一个很好的属性。如果您可以使用US-ASCII字符编码将字节序列解码为Unicode,那么您也可以使用UTF-8字符编码对字节进行解码(并且在两种情况下生成的Unicode代码点都相同)。
smptd.py
应该使用latin1
(它解码任何字节序列)或ascii
('strict'错误处理程序在任何非ascii字节上失败)而不是{{ 1}}(它允许一些非ascii字节 - 坏)。
请记住: