У меня была похожая проблема, но мой случай немного отличался:
- Python 3.5 (вопрос с 2011 года, но все еще очень высоко в Google)
- Чтениесообщение напрямую из файла в виде байтовой строки
Теперь классная особенность почтового ящика python 3 заключается в том, что все заголовки автоматически декодируются в строки Unicode-Strings.Однако это приводит к небольшому «несчастью» при работе с неправильными заголовками.Таким образом, следующий заголовок вызвал проблему:
Subject: Re: =?ISO-2022-JP?B?GyRCIVYlMyUiMnE1RCFXGyhC?=
(1/9(=?ISO-2022-JP?B?GyRCNmIbKEI=?=) 6:00pm-7:00pm)
=?ISO-2022-JP?B?GyRCJE4kKkNOJGkkOxsoQg==?=
Это привело к следующему msg['subject']
:
Re: 「コア会議」 (1/9(=?ISO-2022-JP?B?GyRCNmIbKEI=?=) 6:00pm-7:00pm) のお知らせ
Ну, проблема не соответствует RFC 2047 (Должна быть белая строка- пробел после слова в кодировке MIME), как уже описано в ответе Ингмара Хаппа .Поэтому мой ответ вдохновлен его.
Решение 1: Исправьте строку байтов перед фактическим анализом электронной почты.Это казалось лучшим решением, однако я изо всех сил пытался реализовать подстановку Regex в байтовых строках.Поэтому я выбрал решение 2:
Решение 2: Исправьте уже проанализированное и частично декодированное значение заголовка:
with open(file, 'rb') as fp: # read as byte-string
msg = email.message_from_binary_file(fp, policy=policy.default)
subject_fixed = fix_wrong_encoded_words_header(msg['subject'])
def fix_wrong_encoded_words_header(header_value):
fixed_header_value = re.sub(r"(=\?.*\?=)(?=\S)", r"\1 ", header_value)
if fixed_header_value == header_value: # nothing needed to fix
return header_value
else:
dh = decode_header(fixed_header_value)
default_charset = 'unicode-escape'
correct_header_value = ''.join([str(t[0], t[1] or default_charset) for t in dh])
return correct_header_value
Объяснение важных частей:
Я изменил регулярное выражение Ингмара Хаппа, чтобы заменить только неправильные слова в кодировке MIME: (=\?.*\?=)(?=\S)
Демо Debuggex .Поскольку выполнение для всех сильно замедлит анализ (до 150 000 писем).
После применения функции decode_header
к fixed_header
в dh
есть следующие части:
dh == [(b'Re: \\u300c\\u30b3\\u30a2\\u4f1a\\u8b70\\u300d (1/9(', None),
(b'\x1b$B6b\x1b(B', 'iso-2022-jp'),
(b' ) 6:00pm-7:00pm) \\u306e\\u304a\\u77e5\\u3089\\u305b', None)]
Чтобы повторно декодировать экранированные Юникодом последовательности, мы устанавливаем default_charset = 'unicode-escape'
при создании нового значения заголовка.
Теперь correct_header_value
:
Re: 「コア会議」 (1/9(金 ) 6:00pm-7:00pm) のお知らせ'
Надеюсь, это сэкономит кому-то время.
Дополнение: ответ Сандера Штеффана мне не очень помог, потому что я не смог получить исходную ценностьполе заголовка вне класса сообщений.