Как получить расшифровать это имя файла вложения с 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, как это могут сделать почтовые клиенты?

1 ответ

Решение

В этом заголовке есть два раздела 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) персонажей, но в вашем случае они смешиваются вместе. Если вы повторно введете \r\n разделитель значение декодирует правильно:

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

Вы можете использовать регулярное выражение для извлечения частей и повторного введения разделителя:

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'

Конечно, возможно, у вас есть ошибка в том, как вы читаете заголовок в первую очередь. Убедитесь, что вы случайно не уничтожили существующий \r\n разделитель при извлечении encoded_filename значение.

Другие вопросы по тегам