文章内容

2021/4/23 15:14:13,作 者: 黄兵

如何使用Python阅读电子邮件

能够创建能够读取您的电子邮件并自动下载附件的应用程序是一种方便的工具。您将学习如何使用内置的imaplib模块以Python列出和阅读您的电子邮件,我们将需要IMAP协议的帮助。

IMAP是电子邮件客户端用于从邮件服务器检索电子邮件的Internet标准协议。与POP3协议不同,POP3协议使用IMAP来下载电子邮件并将其从服务器中删除(然后脱机阅读),而该消息并不保留在本地计算机上,而是保留在服务器上。

首先,我们不需要安装任何东西,本教程中使用的所有模块都是内置模块:

import imaplib
import email
from email.header import decode_header
import webbrowser
import os

# account credentials
username = "youremailaddress@provider.com"
password = "yourpassword"

def clean(text):
    # clean text for creating a folder
    return "".join(c if c.isalnum() else "_" for c in text)

我们已经导入了必要的模块,然后指定了电子邮件帐户的凭据。以后我们将需要该clean()函数来创建没有空格和特殊字符的文件夹。

首先,我们需要连接到IMAP服务器:

# create an IMAP4 class with SSL 
imap = imaplib.IMAP4_SSL("imap.gmail.com")
# authenticate
imap.login(username, password)

由于我是在gmail帐户上进行测试的,因此我使用过imap.gmail.com服务器,请检查此链接,其中包含最常用的电子邮件提供商的IMAP服务器列表。

另外,如果您使用的是Gmail帐户,并且上面的代码会引发错误,表明凭据不正确,请确保您的帐户中使用的安全性较低的应用程序

如果一切正常,那么您已经成功登录了帐户,让我们开始获取电子邮件:

status, messages = imap.select("INBOX")
# number of top emails to fetch
N = 3
# total number of emails
messages = int(messages[0])

我们使用了imap.select()方法来选择一个邮箱(收件箱,垃圾邮件等),我们选择了INBOX文件夹,您可以使用imap.list()方法查看可用的邮箱。

messages变量包含该文件夹(收件箱文件夹)中的邮件总数,并且status只是一条消息,指示我们是否成功接收到该消息。然后,我们将其转换messages为整数,以便进行for循环。

N variable是您要检索的顶级电子邮件的数量,我现在将使用3,让我们遍历每一封电子邮件,提取我们需要的所有内容并完成代码:

for i in range(messages, messages-N, -1):
    # fetch the email message by ID
    res, msg = imap.fetch(str(i), "(RFC822)")
    for response in msg:
        if isinstance(response, tuple):
            # parse a bytes email into a message object
            msg = email.message_from_bytes(response[1])
            # decode the email subject
            subject, encoding = decode_header(msg["Subject"])[0]
            if isinstance(subject, bytes):
                # if it's a bytes, decode to str
                subject = subject.decode(encoding)
            # decode email sender
            From, encoding = decode_header(msg.get("From"))[0]
            if isinstance(From, bytes):
                From = From.decode(encoding)
            print("Subject:", subject)
            print("From:", From)
            # if the email message is multipart
            if msg.is_multipart():
                # iterate over email parts
                for part in msg.walk():
                    # extract content type of email
                    content_type = part.get_content_type()
                    content_disposition = str(part.get("Content-Disposition"))
                    try:
                        # get the email body
                        body = part.get_payload(decode=True).decode()
                    except:
                        pass
                    if content_type == "text/plain" and "attachment" not in content_disposition:
                        # print text/plain emails and skip attachments
                        print(body)
                    elif "attachment" in content_disposition:
                        # download attachment
                        filename = part.get_filename()
                        if filename:
                            folder_name = clean(subject)
                            if not os.path.isdir(folder_name):
                                # make a folder for this email (named after the subject)
                                os.mkdir(folder_name)
                            filepath = os.path.join(folder_name, filename)
                            # download attachment and save it
                            open(filepath, "wb").write(part.get_payload(decode=True))
            else:
                # extract content type of email
                content_type = msg.get_content_type()
                # get the email body
                body = msg.get_payload(decode=True).decode()
                if content_type == "text/plain":
                    # print only text email parts
                    print(body)
            if content_type == "text/html":
                # if it's HTML, create a new HTML file and open it in browser
                folder_name = clean(subject)
                if not os.path.isdir(folder_name):
                    # make a folder for this email (named after the subject)
                    os.mkdir(folder_name)
                filename = "index.html"
                filepath = os.path.join(folder_name, filename)
                # write the file
                open(filepath, "w").write(body)
                # open in the default browser
                webbrowser.open(filepath)
            print("="*100)
# close the connection and logout
imap.close()
imap.logout()

这里要介绍的内容很多,首先要注意的是我们已经使用过range(messages, messages-N, -1),这意味着从上到下,最新的电子邮件具有最高的ID号,第一条电子邮件的ID为1,所以这就是主要原因是,如果您要提取最早的电子邮件地址,可以将其更改为range(N)

其次,我们使用了imap.fetch()方法,该方法使用RFC 822中指定的标准格式按ID提取电子邮件。

之后,我们将fetch()方法返回的字节解析为适当的Message对象,并使用email.header模块中的encode_header()函数将电子邮件地址的主题解码为人类可读的unicode。

在打印电子邮件发件人和主题之后,我们要提取正文消息。我们查看电子邮件是否包含多个部分,这意味着它包含多个部分。例如,电子邮件可以包含text/html内容和text/plain部分,这意味着它具有消息的HTML版本和纯文本版本。

它还可以包含文件附件,我们通过Content-Disposition标题检测到附件,因此将其下载到为该主题命名的每封电子邮件创建的新文件夹下。

msg对象是电子邮件模块的Message对象,还有许多其他字段可提取,在本示例中,我们仅使用FromSubject,编写msg.keys()并查看可提取的字段,例如,您可以获取日期使用msg["Date"]发送消息时的时间。

在为我的测试gmail帐户运行代码后,我得到了以下输出:

Subject: Thanks for Subscribing to our Newsletter !
From: example@domain.com
====================================================================================================
Subject: An email with a photo as an attachment
From: Python Code 
Get the photo now!

====================================================================================================
Subject: A Test message with attachment
From: Python Code 
There you have it!

====================================================================================================

因此,该代码将仅打印text/plain正文消息,它将为每个电子邮件创建一个文件夹,其中包含电子邮件的附件和HTML版本,并且还会在默认浏览器中为提取的每个包含HTML的电子邮件打开HTML电子邮件内容。

转到我的Gmail,我看到了用Python打印的相同电子邮件:


太棒了,我还注意到为每个电子邮件创建的文件夹:


现在,每个文件夹都有HTML消息(如果有)以及电子邮件附带的所有文件。

结论

太棒了,现在您可以使用此食谱构建自己的电子邮件客户端,例如,您可以构建一个GUI程序来读取和解析HTML,就像使用常规浏览器一样,而不是在新的浏览器选项卡上打开每封电子邮件,或者您可能想要每当有新电子邮件发送给您时发送通知,可能性无穷无尽!

不过请注意,我们并未涵盖imaplib模块提供的所有内容,例如,您可以使用imap.search()方法搜索电子邮件并按发件人地址,主题,发送日期等进行过滤。


文章来源:How to Read Emails in Python

分享到:

发表评论

评论列表