【问题标题】:AttributeError: 'str' object has no attribute 'copy' when parsing Multipart email messageAttributeError:解析多部分电子邮件时,“str”对象没有属性“copy”
【发布时间】:2019-10-16 21:07:48
【问题描述】:

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

我认为这与 Content-Type 为 multipart/mixed 以及电子邮件内容为空有关,这导致 get_payload 返回 str。但是,我不确定,如果标准禁止这样的 EML(但我有很多这样的示例),这是电子邮件模块中的错误,或者我使用代码错误。

【问题讨论】:

  • 我不鼓励您使用 email 模块,因为它即将从 3.8 中弃用并从 3.10 中删除。考虑使用另一个电子邮件模块。来源:python.org/dev/peps/pep-0594/#email-legacy-api
  • 谢谢,我不知道,但是,在您发布的来源中,有以下说明:Substitute: email (non-legacy APIs) 这意味着,据我了解,email 模块仍将被使用,仅包含非旧版内容。无论如何,我不喜欢针对这个单一错误重构我的整个电子邮件解析平台并替换基础解析模块的想法(我什至不确定是否有像@ 987654331@模块)。
  • 确实,我发布的代码使用的是新的email.message.EmailMessage,实际上是旧代码的替代品,所以我使用的代码并没有被弃用。

标签: python email mime multipart eml


【解决方案1】:

如果您将策略更改为strict

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

解析器引发email.errors.StartBoundaryNotFoundDefect,在docs 中描述为:

StartBoundaryNotFoundDefect – 从未找到 Content-Type 标头中声明的起始边界。

如果您使用policy.default 解析消息并检查它是defects,则它包含两个缺陷:

[StartBoundaryNotFoundDefect(), MultipartInvariantViolationDefect()]

MultipartInvariantViolationDefect – 一条消息声称是多部分的,但没有找到子部分。请注意,当消息具有此缺陷时,其 is_multipart() 方法可能会返回 false,即使其内容类型声称是多部分的。

StartBoundaryNotFoundDefect 的结果是解析器终止解析并将消息有效负载设置为到目前为止已捕获的正文 - 在这种情况下,什么都没有,因此有效负载是一个空字符串,导致您的异常当你运行你的代码时会看到。

可以说,Python 在调用 copy() 之前不会检查有效负载是否为 list 是一个错误。

在实践中,您必须通过将附件迭代包装在 try/except 中、根据 msg.defects 的内容调整迭代或使用 policy.strict 解析并丢弃所有报告缺陷的消息来处理这些消息。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-31
    • 1970-01-01
    • 2018-09-10
    • 2021-10-04
    • 2019-12-02
    • 2021-09-25
    相关资源
    最近更新 更多