【问题标题】:Python Message' object has no attribute 'get_bodyPython Message'对象没有属性'get_body
【发布时间】:2019-06-09 06:26:00
【问题描述】:

我正在尝试搜索电子邮件正文,但遇到了一些问题:

 #!/usr/local/bin/python3
from email.message import EmailMessage
import email
import imaplib
import re
import sys
import logging
import base64
import os
logging.basicConfig(stream=sys.stdout, level=logging.INFO)

###########log in to mailbox########################
user = 'email@company.com'
pwd = 'pwd'

conn = imaplib.IMAP4_SSL("outlook.office365.com")
conn.login(user,pwd)
conn.select("test")
count = conn.select("test")

resp, items = conn.uid("search" ,None, '(OR (FROM "some@email) (FROM "some@email"))')

items = items[0].split()
for emailid in items:
    resp, data = conn.uid("fetch",emailid, "(RFC822)")
    if resp == 'OK':
        email_body = data[0][1]#.decode('utf-8')
        mail = email.message_from_bytes(email_body)

        #get all emails with words "PA1" or "PA2" in subject
        if mail["Subject"].find("PA1") > 0 or mail["Subject"].find("PA2") > 0:
           print (mail)

我在以下行有问题:

body = mail.get_body(preferencelist=('plain', 'html'))

得到:

AttributeError: 'Message' 对象没有属性 'get_body'

【问题讨论】:

  • ^M 可能不是^ + M,而是另一个单个字符:\r。更改您的正则表达式,然后重试。
  • 如果你指的是这个:re.sub(r'=(?:\r)?|<br\s*(?:/\s*)?>|[\r\n]+', '', m) 它不起作用
  • 收到答案后,您不应更新问题以创建新问题。回滚您的更改,接受其中一个答案(如果您确实需要,也可以删除问题;但要意识到反复删除您自己的问题会引发一些问题)并提出一个包含完整详细信息的新问题,并且可能是这个问题的背景链接。

标签: python imaplib


【解决方案1】:

您不应将 MIME 结构转换为字符串,然后将其提供给 message_from_string。相反,请将其保留为 bytes 对象。

from email.policy import default as default_policy
...
items = items[0].split()
for emailid in items:
    resp, data = conn.uid("fetch",emailid, "(RFC822)")
    if resp == 'OK':
        email_blob = data[0][1]
        mail = email.message_from_bytes(email_blob, policy=default_policy)
        if not any(x in mail['subject'] for x in ('PA1', 'PA2')):
            continue

你没有展示你是如何遍历 MIME 结构的,所以我假设你目前根本没有这样做。可能你想要类似的东西

        # continuation for the above code
        body = mail.get_body(preferencelist=('plain', 'html'))
        for lines in body.split('\n'):
            if line.startswith('MACHINE:'):
                result = line[8:].strip()
                break

您的电子邮件正文部分似乎使用Content-Transfer-Encoding: quoted-printable 编码。上面的代码对各种编码都很健壮,因为email 库为您透明地解码封装,从而消除了任何 QP 转义的换行符,就像您问题中的换行符一样。作为记录,quoted-printable 无论如何都可以打破一长串,包括在您尝试提取的值的中间,因此您确实想在尝试提取任何内容之前进行解码。

【讨论】:

  • 我发布了有问题的更新代码,现在得到:AttributeError: 'Message' object has no attribute 'get_body'
  • 等一下,消息应该是 EmailMessage(新样式)而不是旧的 Message 类型。
  • 你确定你真的在使用 Python 3.6 吗?
  • 有什么想法吗?
  • 如@MarkJohnson 的回答中提到的那样,姗姗来迟地更新为import email.policy;不知道我当时是怎么错过的。
【解决方案2】:

解决消息:

AttributeError: 'Message' 对象没有属性 'get_body'

创建 Message 对象时,您需要指定一个策略,否则您将获得默认的 email.policy.Compat32 策略。 get_body() 和其他几个方法在 Python 3.2 中不存在。

创建邮件对象的行应该是:

mail = email.message_from_bytes(data, policy=email.policy.default)

更多信息请访问:

https://docs.python.org/3/library/email.policy.html

【讨论】:

    【解决方案3】:

    如果您可以先从文本中删除所有换行符=^M\n,那么这很简单:

    import re
    
    email_body = open("1.txt").read().replace("=^M\n", "")
    
    matches = re.findall(r"(?<=MACHINE:)\s*(\w+)", email_body)
    
    print(matches)
    print(list(set(matches)))
    

    输出:

    ['p1prog07', 'p2prog06', 'p2prog06', 'p1prog07', 'ldnv260']
    ['p2prog06', 'ldnv260', 'p1prog07']
    

    积极的后视是一个非捕获组,因此正则表达式中唯一捕获的组是您想要的字符串。

    【讨论】:

    • 更好的是,检查电子邮件的内容传输编码并解码您看到的任何编码。这看起来像quoted-printable,但也可能是base64。 QP 编码也可能发生在值的中间。
    • 不,它不会选择所有案例:regex101.com/r/J17eQ2/3,email_body 示例在我发布的链接中:onedrive.live.com/…
    • @xerks 你是对的,MACHINEldnmdsbatchxl01 之间有不同的换行符。这需要更深入地了解文件的编码方式。
    • 感谢@tripleee,我刚刚发布了获取电子邮件正文的代码,不知道应该如何解码?
    • 正确的解码方法是使用 Python email 模块并使用 message_from_bytes 或其他方式读取消息;该模块知道如何即时解码。
    猜你喜欢
    • 2021-09-01
    • 1970-01-01
    • 2023-02-01
    • 2021-02-03
    • 2022-12-09
    • 1970-01-01
    • 2018-05-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多