Crashing Python модуль электронной почты - PullRequest
3 голосов
/ 31 мая 2019

Модуль электронной почты Python 3.6 аварийно завершает работу с этой ошибкой:

Traceback (most recent call last):
  File "empty-eml.py", line 9, in <module>
    for part in msg.iter_attachments():
  File "/usr/lib/python3.6/email/message.py", line 1055, in iter_attachments
    parts = self.get_payload().copy()
AttributeError: 'str' object has no attribute 'copy'

Сбой может быть воспроизведен с помощью этого файла EML,

From: "xxx@xxx.xx" <xxx@xxx.xx>
To: <xx@xxx.xx>
Subject: COURRIER EMIS PAR PACIFICA 
MIME-Version: 1.0
Content-Type: multipart/mixed;
    boundary="----=_Part_3181_1274694650.1556805728023"
Date: Thu, 2 May 2019 16:02:08 +0200

и этого минимального кода:

from email import policy
from email.parser import Parser
from sys import argv


with open(argv[1]) as eml_file:
    msg = Parser(policy=policy.default).parse(eml_file)

for part in msg.iter_attachments():
    pass

Я полагаю, что это связано с типом содержимого multipart/mixed, а содержимое электронной почты пустое, что приводит к тому, что get_payload возвращает str.Однако я не уверен, если такой EML запрещен стандартом (но у меня много таких примеров), это ошибка в модуле электронной почты, или я неправильно использовал код.

1 Ответ

1 голос
/ 31 мая 2019

Если вы измените политику на strict:

Parser(policy=policy.strict).parse(eml_file)

, парсер вызовет email.errors.StartBoundaryNotFoundDefect, описанный в документах как:

StartBoundaryNotFoundDefect - Начальная граница, указанная в заголовке Content-Type, так и не была найдена.

Если вы анализируете сообщение с помощью policy.default и затем просматриваете его defects, оно содержит два дефекта:

[StartBoundaryNotFoundDefect(), MultipartInvariantViolationDefect()]

MultipartInvariantViolationDefect - Сообщение, заявленное как составное, но не найдено.Обратите внимание, что когда сообщение имеет этот дефект, его метод is_multipart () может возвращать false, даже если его тип содержимого претендует на то, чтобы быть составным.

Следствием StartBoundaryNotFoundDefect является то, что синтаксический анализатор прекращает синтаксический анализ иустанавливает полезную нагрузку сообщения для тела, которое было захвачено до сих пор - в данном случае ничего, поэтому полезная нагрузка представляет собой пустую строку, вызывающую исключение, которое вы видите, когда запускаете свой код.

Возможно, фактчто Python не проверяет, является ли полезная нагрузка list, прежде чем вызвать copy(), это ошибка.

На практике вы должны обрабатывать эти сообщения, либо заключая итерацию вложений в try/except, обуславливая итерацию для содержимого msg.defects, либо анализируя с policy.strict, и отбрасывая все сообщения, сообщающиедефекты.

...