python 3 smtplib:当 gnupg 处于活动状态时,二进制附件在烧瓶中编码不正确
python 3 smtplib: binary attachment encodes incorrectly in flask when gnupg is active
我正在尝试使用 python 3.5.2 smtplib 通过 TLS 发送二进制附件。我的平台是 OSX,我正在使用从自制程序安装的 python。
当我收到附件时,编码似乎被篡改了。而不是以此十六进制开头的原始文件:
ffd8 ffe0 0010 4a46 4946 0001 0100 0001
i.e., <FF><D8><FF><E0>^@^PJFIF^@^A^A
我收到的附件的起始十六进制有一些奇怪的 base64 剩余:
5c75 6463 6666 5c75 6463 6438 5c75 6463 6666 5c75 6463 6530 0010 4a46 4946 0001
i.e., \udcff\udcd8\udcff\udce0^@^PJFIF
这是一个失败的最小案例,除了添加了 TLS 逻辑 和 gnupg:
import gnupg
gpg = gnupg.GPG('/path/to/gpg')
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.image import MIMEImage
def send_my_email():
msg = MIMEMultipart()
msg['Subject'] = 'subject'
msg['From'] = 'XXXX@gmail.com'
msg['To'] = 'YYYY@gmail.com'
with open('/tmp/image.jpg', mode='rb') as image_file:
image = MIMEImage(image_file.read())
msg.attach(image)
s = smtplib.SMTP('smtp.gmail.com', 587)
s.starttls()
s.login('XXXX@gmail.com', 'password')
s.send_message(msg)
s.quit()
根据这里的另一个问题,我尝试了这个而不是 send_message()
,但它也失败了:
s.sendmail('XXXX@gmail.com', ['YYYY@gmail.com'], msg.as_string())
我还尝试在初始化 MIMEImage
时显式添加 _subtype='jpg'
,添加 Content-Transfer-Encoding
header,并添加 Content-Disposition
header 和 none 似乎有所作为。
我已经确认我的电子邮件客户端在接收来自其他客户端的 base64 编码附件时没有问题。
我查看了 smtplib 源代码并注意到 smtplib 处理行分隔符的方式看起来有点奇怪,想知道这是否可能相关。 (另见参考:https://bugs.python.org/issue14645)
我是否需要对某些内容进行不同的编码,为我的平台设置一些特殊的内容,或者这是一个小故障?谢谢!
更新:此问题仅在我 运行ning Flask 时存在,在 Flask 之外不会发生。我正在尝试将问题隔离在我的 Flask 环境中。我认为它可能是 flask_mail 但删除它并没有解决问题。当我的系统上的 Flask 运行 时,下面的代码失败,但如果我从同一虚拟环境和相同的 python 二进制文件中的 shell 脚本 运行 它,则不会。由于复杂性,我目前不希望得到任何答案,但会留待后代使用。
更新 2:我已将这个问题缩小到与来自 https://github.com/isislovecruft/python-gnupg/ 的 gnupg 库的交互。我已经更新了我的最小示例以反映这一点。 python-gnupug 中 python 编解码器的 monkey-patch 是造成问题的原因:codecs.register_error('strict', codecs.replace_errors)
这是由于 gnupg 和 smtplib + MIME 之间的不良交互造成的。 gnupg 调用 codecs.register_error('strict', codecs.replace_errors)
,这会干扰其他软件包执行的编码。
我正在尝试使用 python 3.5.2 smtplib 通过 TLS 发送二进制附件。我的平台是 OSX,我正在使用从自制程序安装的 python。
当我收到附件时,编码似乎被篡改了。而不是以此十六进制开头的原始文件:
ffd8 ffe0 0010 4a46 4946 0001 0100 0001
i.e., <FF><D8><FF><E0>^@^PJFIF^@^A^A
我收到的附件的起始十六进制有一些奇怪的 base64 剩余:
5c75 6463 6666 5c75 6463 6438 5c75 6463 6666 5c75 6463 6530 0010 4a46 4946 0001
i.e., \udcff\udcd8\udcff\udce0^@^PJFIF
这是一个失败的最小案例,除了添加了 TLS 逻辑 和 gnupg:
import gnupg
gpg = gnupg.GPG('/path/to/gpg')
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.image import MIMEImage
def send_my_email():
msg = MIMEMultipart()
msg['Subject'] = 'subject'
msg['From'] = 'XXXX@gmail.com'
msg['To'] = 'YYYY@gmail.com'
with open('/tmp/image.jpg', mode='rb') as image_file:
image = MIMEImage(image_file.read())
msg.attach(image)
s = smtplib.SMTP('smtp.gmail.com', 587)
s.starttls()
s.login('XXXX@gmail.com', 'password')
s.send_message(msg)
s.quit()
根据这里的另一个问题,我尝试了这个而不是 send_message()
,但它也失败了:
s.sendmail('XXXX@gmail.com', ['YYYY@gmail.com'], msg.as_string())
我还尝试在初始化 MIMEImage
时显式添加 _subtype='jpg'
,添加 Content-Transfer-Encoding
header,并添加 Content-Disposition
header 和 none 似乎有所作为。
我已经确认我的电子邮件客户端在接收来自其他客户端的 base64 编码附件时没有问题。
我查看了 smtplib 源代码并注意到 smtplib 处理行分隔符的方式看起来有点奇怪,想知道这是否可能相关。 (另见参考:https://bugs.python.org/issue14645)
我是否需要对某些内容进行不同的编码,为我的平台设置一些特殊的内容,或者这是一个小故障?谢谢!
更新:此问题仅在我 运行ning Flask 时存在,在 Flask 之外不会发生。我正在尝试将问题隔离在我的 Flask 环境中。我认为它可能是 flask_mail 但删除它并没有解决问题。当我的系统上的 Flask 运行 时,下面的代码失败,但如果我从同一虚拟环境和相同的 python 二进制文件中的 shell 脚本 运行 它,则不会。由于复杂性,我目前不希望得到任何答案,但会留待后代使用。
更新 2:我已将这个问题缩小到与来自 https://github.com/isislovecruft/python-gnupg/ 的 gnupg 库的交互。我已经更新了我的最小示例以反映这一点。 python-gnupug 中 python 编解码器的 monkey-patch 是造成问题的原因:codecs.register_error('strict', codecs.replace_errors)
这是由于 gnupg 和 smtplib + MIME 之间的不良交互造成的。 gnupg 调用 codecs.register_error('strict', codecs.replace_errors)
,这会干扰其他软件包执行的编码。