如何使用 python 解码此附件文件名?

How to get decode this attachment filename with python?

我已经在我的代码中解码了很多电子邮件附件文件名。

但是这个特定的文件名破坏了我的代码。

这是一个最小的例子:

from email.header import decode_header
encoded_filename='=?UTF-8?B?U2FsZXNJbnZvaWNl?==?UTF-8?B?LVJlcG9ydC5wZGY=?='
decoded_header=decode_header(encoded_filename) # --> [('SalesInvoiceQ1|\x04\xb5I\x95\xc1\xbd\xc9\xd0\xb9\xc1\x91\x98', 'utf-8')]
filename=str(decoded_header[0][0]).decode(decoded_header[0][1])

异常:

UnicodeDecodeError: 'utf8' codec can't decode byte 0xb5 in position 16: invalid start byte

别问我怎么做的,Thunderbird 能够将这个文件名解码为:SalesInvoice-Report.pdf

我如何用 python 解码它,就像电子邮件客户端显然能够做到的那样?

header 中有 两个 Encoded-Word 个部分。你必须检测一个结束和一个开始的地方:

>>> print  decode_header(encoded_filename[:28])[0]
('SalesInvoice', 'utf-8')
>>> print  decode_header(encoded_filename[28:])[0]
('-Report.pdf', 'utf-8')

显然这就是 Thunderbird 在这种情况下所做的;将字符串拆分为 =?encoding?data?= 个块。 通常这些应该由\r\n(CARRIAGE RETURN + LINE FEED)字符分隔,但在你的情况下它们被混在一起。如果您 re-introduce \r\n 分隔符值正确解码:

>>> decode_header(encoded_filename[:28] + '\r\n' + encoded_filename[28:])[0]
('SalesInvoice-Report.pdf', 'utf-8')

您可以使用正则表达式来提取部分和 re-introduce 分隔符:

import re
from email.header import decode_header

quopri_entry = re.compile(r'=\?[\w-]+\?[QB]\?[^?]+?\?=')

def decode_multiple(encoded, _pattern=quopri_entry):
    fixed = '\r\n'.join(_pattern.findall(encoded))
    output = [b.decode(c) for b, c in decode_header(fixed)]
    return ''.join(output)

演示:

>>> encoded_filename = '=?UTF-8?B?U2FsZXNJbnZvaWNl?==?UTF-8?B?LVJlcG9ydC5wZGY=?='
>>> decode_multiple(encoded_filename)
u'SalesInvoice-Report.pdf'

当然,可能首先是您在阅读 header 时遇到了错误。确保在提取 encoded_filename 值时不会意外破坏现有的 \r\n 分隔符。