Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/354.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 压缩的附件会破坏email.message.message.get_payload()_Python_Email_Email Attachments_Mime_Quoted Printable - Fatal编程技术网

Python 压缩的附件会破坏email.message.message.get_payload()

Python 压缩的附件会破坏email.message.message.get_payload(),python,email,email-attachments,mime,quoted-printable,Python,Email,Email Attachments,Mime,Quoted Printable,我经常收到带有附件的电子邮件,这些附件必须提取并保存到磁盘。我基本上做了以下工作(在Python 2.7中): 这种方法适用于我迄今为止收到的所有类型的附件和所有风格的附件,除非附件是ZIP文件,内容传输编码是“可引用打印的”。在这些情况下,写入的ZIP文件比原始文件少一个字节(大约占文件长度的60-80%),并且解压报告如下错误: % unzip -l foo.zip Archive: foo.zip error [foo.zip]: missing 1 bytes in zipfile

我经常收到带有附件的电子邮件,这些附件必须提取并保存到磁盘。我基本上做了以下工作(在Python 2.7中):

这种方法适用于我迄今为止收到的所有类型的附件和所有风格的附件,除非附件是ZIP文件,
内容传输编码
是“可引用打印的”。在这些情况下,写入的ZIP文件比原始文件少一个字节(大约占文件长度的60-80%),并且
解压
报告如下错误:

% unzip -l foo.zip
Archive:  foo.zip
error [foo.zip]:  missing 1 bytes in zipfile
  (attempting to process anyway)
  Length      Date    Time    Name
---------  ---------- -----   ----
   440228  01-00-1980 00:00   foo - bar.csv
---------                     -------
   440228                     1 file

解压后的结果与原始CSV的大小相差约0.01%,最后20-40%左右的文件被篡改


现在,代码可以很好地处理作为“base64”附加的ZIP文件,也可以很好地处理作为“引用的可打印”附加的其他内容(Excel文件、csv文件)。我知道ZIP附件内容是不受损坏的足以让我的普通电子邮件阅读器将其保存到磁盘,并完美地提取原始内容。(是否有可能是真正的电子邮件阅读器在保存附件时执行了一些错误更正,而我的Python没有这样做?)


Python是否存在一个已知的问题,即无法读取以可打印形式发送的ZIP文件?Python的
电子邮件
包中是否还有其他函数我可以尝试正确解读此内容?

本例中的问题是发件人的二进制附件(ZIP文件)编写得不好,因此它们包含
\r\n
序列。也就是说,ZIP格式的文件本身(不是正在压缩的文件)偶尔包含CRLF对。我无法推测这些是如何进入压缩输出的;我不认为任何商业或开源的zippers会在其输出中包含CRLF

根据的规则#4,原始“文本”(在本例中为ZIP附件)中的换行符必须在编码中表示为裸
\r\n
(然后根据解码器的语言环境进行解释)。显然,当断线的确切形式有意义时(例如当它本身是一种编码时),这是非常糟糕的。RFC甚至对包含文字换行符的二进制数据的怪异性进行了评论:

由于文本以外类型的规范表示通常不包括换行符的表示,因此在此类类型的引用可打印编码中不应出现硬换行符(即,旨在对用户有意义并显示给用户的换行符)

所以在RFC的结尾有一个巨大的警告:

对实施者的警告:如果二进制数据以引用的可打印格式编码,则必须注意将CR和LF字符分别编码为“=0D”和“=0A”。特别是,二进制数据中的CRLF序列应编码为“=0D=0A”。否则,如果CRLF被表示为硬换行符,则可能会在具有不同换行约定的平台上错误解码

在编码时,发件人显然没有遵守此警告,因此发件人和我之间的某些邮件传输代理或网关正在确定适合我的区域设置的换行符只是
\n
(通常是这样)

无论如何,我通过将我的
quopri
解码的附件逐字节与附件ZIP文件的原始副本进行比较,发现了这个问题。这两个都是一样的,除了原版中的每个CRLF都只是我解码中的一个LF。由于
\r
显然是有意义的,并且由于QP编码中的每一个换行符都正确地以换行
=
字符开头,因此我仅为来自此发送方的所有QP编码
应用程序
MIME类型编写了以下转换:

if part['Content-Disposition'].startswith('attachment') and \
   part['Content-Transfer-Encoding'] == 'quoted-printable':
    rawContent = part.get_payload(decode=False)
    fixedRawContent = re.sub(r'([^=])\n', r'\1=0D=0A=\n', rawContent)
    decodedContent = quopri.decodestring(fixedRawContent)

通过将每个硬(意外)换行符转换为编码的
\r\n
(然后是我自己的软换行符,这样我就不必担心创建任何过长的换行符),解码功能会尽职尽责地将所说的
\r\n
放入ZIP,然后正确提取。

不要使用引用的可打印,请改用
base-64
。@stovfl谢谢,但我是电子邮件的收件人,而不是发件人。Zip文件是
二进制的
,无法从引用的可打印文件中解码。要求发件人更改为
base64
% unzip foo.zip 
Archive:  foo.zip
error [foo.zip]:  missing 1 bytes in zipfile
  (attempting to process anyway)
error [foo.zip]:  attempt to seek before beginning of zipfile
  (please check that you have transferred or created the zipfile in the
  appropriate BINARY mode and that you have compiled UnZip properly)
  (attempting to re-compensate)
  inflating: foo - bar.csv   bad CRC 4c86de66  (should be a53f73b1)
if part['Content-Disposition'].startswith('attachment') and \
   part['Content-Transfer-Encoding'] == 'quoted-printable':
    rawContent = part.get_payload(decode=False)
    fixedRawContent = re.sub(r'([^=])\n', r'\1=0D=0A=\n', rawContent)
    decodedContent = quopri.decodestring(fixedRawContent)