Python邮件自动化实战之发送附件和智能处理收件箱

 更新时间:2026年03月12日 08:50:07   作者:MarkHD  
这篇文章主要介绍了Python中邮件自动化的核心技能,涵盖发送和接收邮件两大模块,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下

引言

在自动化运维和日常办公中,电子邮件依然是最正式、最广泛使用的通知和交互手段。无论是定时发送报表、监控报警,还是自动处理用户请求,邮件自动化都是程序员工具箱中的必备技能。

在Python领域,大多数开发者对smtplib发送邮件较为熟悉,但在邮件接收与处理(尤其是IMAP协议)方面却往往力不从心,通常需要编写大量底层代码来处理邮件解析、附件下载和搜索条件。本篇文章将深入浅出,不仅讲解如何使用smtplib发送带附件的复杂邮件,更将重点引入强大的第三方库——imap_tools,手把手教你如何优雅地读取和处理收件箱邮件,实现真正意义上的邮件自动化闭环。

夯实基础 —— 使用smtplib发送带附件的邮件

SMTP(Simple Mail Transfer Protocol)是推送邮件的协议。Python的smtplib模块封装了其底层细节,而email库则负责构建符合MIME标准的邮件内容。

核心概念:MIMEMultipart

要发送带附件的邮件,我们不能使用简单的MIMEText对象。因为邮件包含独立的两部分:正文和附件。这时需要用到MIMEMultipart,它是一个容器,可以将不同的MIME部分组合在一起。

一个标准的带附件邮件结构如下:

MIMEMultipart(混合类型)

  • MIMEText(纯文本或HTML正文)
  • MIMEBase / MIMEApplication(附件)

实战:发送带Excel附件的HTML邮件

下面的示例演示了如何连接QQ邮箱的SMTP服务器,发送一封包含HTML样式的正文,并附带一个Excel文件的邮件。

import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
from email.utils import formataddr

# 邮件配置
SMTP_SERVER = 'smtp.qq.com'
SMTP_PORT = 587  # TLS端口
SENDER_EMAIL = 'your_qq@qq.com'
SENDER_PWD = '你的授权码'  # QQ邮箱需使用授权码,非登录密码

def send_email_with_attachment(receiver, subject, html_content, attachment_path):
    """
    发送带附件的HTML邮件
    """
    # 创建一个混合类型的邮件对象
    msg = MIMEMultipart()
    msg['From'] = formataddr(('自动化发送者', SENDER_EMAIL))
    msg['To'] = receiver
    msg['Subject'] = subject

    # 1. 添加HTML正文
    msg.attach(MIMEText(html_content, 'html', 'utf-8'))

    # 2. 处理附件
    try:
        with open(attachment_path, 'rb') as f:
            # 创建附件对象 (MIMEBase)
            part = MIMEBase('application', 'octet-stream')
            part.set_payload(f.read())
            # 编码为Base64
            encoders.encode_base64(part)
            # 添加头部信息,声明此为附件
            filename = attachment_path.split('/')[-1]  # 获取文件名
            part.add_header(
                'Content-Disposition',
                f'attachment; filename="{filename}"'
            )
            msg.attach(part)
    except FileNotFoundError:
        print(f"附件 {attachment_path} 未找到,邮件将无附件发送。")

    # 3. 发送邮件
    try:
        server = smtplib.SMTP(SMTP_SERVER, SMTP_PORT)
        server.starttls()  # 启用TLS加密
        server.login(SENDER_EMAIL, SENDER_PWD)
        server.sendmail(SENDER_EMAIL, receiver, msg.as_string())
        server.quit()
        print(f"邮件发送成功至 {receiver}")
    except Exception as e:
        print(f"发送失败: {e}")

# 使用示例
if __name__ == '__main__':
    html_body = """
    <h2>月度数据报告</h2>
    <p>您好,</p>
    <p>本月销售数据请见附件。</p>
    <p><strong>请注意:</strong> 此邮件由系统自动发送,请勿回复。</p>
    """
    send_email_with_attachment(
        receiver='target@example.com',
        subject='【自动化】2024年5月销售报表',
        html_content=html_body,
        attachment_path='./report.xlsx'  # 假设当前目录有该文件
    )

注意事项

  • 使用.starttls()时端口通常为587;若使用SSL,则端口为465并改用smtplib.SMTP_SSL
  • 对于Gmail、QQ等邮箱,务必使用授权码而非邮箱密码,以确保安全性。

进阶突破 —— 使用imap_tools智能处理收件箱

发送邮件只是自动化的一半。如何自动读取邮件、下载附件或根据规则自动回复,才是真正的难点。标准库imaplib虽然功能强大,但使用起来较为繁琐。这里推荐使用基于imaplib封装的高阶库——imap_tools,它提供了简洁的查询语法和对象化的邮件属性。

安装与基础连接

首先,安装这个轻量级且无外部依赖的库:

pip install imap-tools

基础连接使用上下文管理器(with语句),确保连接自动关闭:

from imap_tools import MailBox

# 连接IMAP服务器(QQ邮箱IMAP地址:imap.qq.com)
with MailBox('imap.qq.com').login('your_qq@qq.com', '你的授权码', initial_folder='INBOX') as mailbox:
    print("登录成功,当前文件夹:收件箱")
    # 后续操作...

强大的查询语法(AND/OR/NOT)

imap_tools的核心优势在于其查询构造器。它模仿了SQLAlchemy的语法,告别了复杂的IMAP搜索字符串。

基本查询示例

from imap_tools import MailBox, AND, OR, NOT

with MailBox('imap.qq.com').login('your_qq@qq.com', '授权码', 'INBOX') as mailbox:
    
    # 1. 查询未读邮件
    unread_emails = mailbox.fetch(AND(seen=False))
    
    # 2. 查询特定发件人且包含附件的邮件
    specific_emails = mailbox.fetch(AND(from_='boss@company.com', subject='报告'))
    
    # 3. 复杂查询:来自某个域,或者是紧急邮件
    complex_query = OR(
        from_='@important.com',
        subject='URGENT'
    )
    for msg in mailbox.fetch(complex_query):
        print(msg.subject)
    
    # 4. 日期范围查询:近3天的邮件
    from datetime import date, timedelta
    three_days_ago = date.today() - timedelta(days=3)
    recent_mails = mailbox.fetch(AND(date_gte=three_days_ago))

解析邮件并下载附件

MailMessage对象提供了直观的属性来访问邮件内容。以下是一个自动下载所有未读邮件附件的脚本:

import os
from imap_tools import MailBox, AND

DOWNLOAD_DIR = './attachments'

def download_attachments_from_inbox():
    # 确保下载目录存在
    os.makedirs(DOWNLOAD_DIR, exist_ok=True)
    
    with MailBox('imap.qq.com').login('your_qq@qq.com', '授权码', 'INBOX') as mailbox:
        # 获取所有未读邮件
        # fetch 返回一个生成器,支持分页和排序,这里设置 reverse=True 让最新的邮件先出现
        for msg in mailbox.fetch(AND(seen=False), reverse=True, limit=50):  # 限制处理50封,防止过载
            print(f"处理邮件: {msg.subject} 来自: {msg.from_}")
            
            # 检查是否有附件
            if msg.attachments:
                for att in msg.attachments:
                    # att 是 MailAttachment 对象
                    filename = att.filename
                    # 可以按文件类型过滤
                    if filename.endswith(('.xlsx', '.pdf', '.docx')):
                        file_path = os.path.join(DOWNLOAD_DIR, filename)
                        # att.payload 是附件的二进制数据 (bytes)
                        with open(file_path, 'wb') as f:
                            f.write(att.payload)
                        print(f"  已下载附件: {filename}")
                
                # 处理完后,可以将邮件标记为已读(默认fetch时mark_seen=True),或移动到其他文件夹
                # 将邮件移动到 "Processed" 文件夹
                mailbox.move([msg.uid], 'PROCESSED')
            else:
                # 无附件邮件,直接标记为已读,也可以不做任何操作
                # 如果不希望在fetch时自动标记已读,可以在fetch参数中设置 mark_seen=False
                pass

if __name__ == '__main__':
    download_attachments_from_inbox()

代码解析

  • msg.attachments 返回一个由 MailAttachment 对象组成的列表,每个对象包含 filenamepayload(二进制)、content_type 等属性。
  • mailbox.move([msg.uid], 'PROCESSED') 演示了如何将处理完的邮件移动到指定文件夹,实现收件箱归零。
  • fetch 方法的 limit 参数可以有效防止一次性处理大量邮件导致的性能问题。

邮件自动回复机器人雏形

结合发送和接收,我们可以构建一个简单的自动应答机器人:当收到特定主题的邮件时,自动回复预设内容。

import smtplib
from email.mime.text import MIMEText
from imap_tools import MailBox, AND

# 发送函数 (简化版)
def send_reply(to_addr, original_subject):
    smtp_server = smtplib.SMTP('smtp.qq.com', 587)
    smtp_server.starttls()
    smtp_server.login('your_qq@qq.com', '授权码')
    
    msg = MIMEText('感谢您的来信,我们已经收到您的请求,会尽快处理。', 'plain', 'utf-8')
    msg['From'] = 'your_qq@qq.com'
    msg['To'] = to_addr
    msg['Subject'] = f'RE: {original_subject} [自动回复]'
    
    smtp_server.send_message(msg)
    smtp_server.quit()

# 主监控逻辑
def auto_responder():
    with MailBox('imap.qq.com').login('your_qq@qq.com', '授权码', 'INBOX') as inbox:
        # 查找未读的、主题包含"咨询"的邮件
        for msg in inbox.fetch(AND(seen=False, subject='咨询')):
            # 发送自动回复
            send_reply(msg.from_, msg.subject)
            print(f"已回复: {msg.from_}")
            
            # 标记为已读并添加自定义标志
            inbox.flag([msg.uid], ['ANSWERED'], True)

综合实战:监控邮箱并自动备份附件

假设你有一个需求:每天定时检查收件箱,将当天收到的所有邮件的Excel附件下载下来,并将下载记录发送给管理员。

完整流程

  • 使用imap_tools连接IMAP,查询当天日期范围内的邮件。
  • 遍历邮件,下载.xlsx附件。
  • 所有附件下载完成后,调用smtplib发送一封汇总邮件给管理员。

这部分代码融合了上述所有知识点,是邮件自动化的典型应用场景。通过结合操作系统的定时任务(如Linux Crontab或Windows任务计划程序),即可实现无人值守的自动化处理。

常见问题与避坑指南

授权码 vs 密码:几乎所有主流邮箱(QQ、163、Gmail)在开启SMTP/IMAP服务后,都需要使用生成的授权码作为密码登录,直接使用网页登录密码会报错。

IMAP文件夹名称:默认收件箱是INBOX。其他文件夹(如“已发送”、“归档”)的名称可能因邮箱服务商而异,例如QQ邮箱的“已发送”可能是&XfJT0ZAB4这种编码形式。建议先使用mailbox.folder.list()打印所有文件夹名称。

附件编码att.payload返回的是原始二进制数据,直接写入文件即可。如果遇到附件名乱码,可以使用att.filename,该属性通常已经被imap-tools处理过。

性能考量:如果需要处理海量邮件,务必使用fetchlimitbulk参数。设置bulk=True可以减少与服务器的交互次数,但会占用更多内存。

到此这篇关于Python邮件自动化实战之发送附件和智能处理收件箱的文章就介绍到这了,更多相关Python邮件自动化内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Python统计时间内的并发数代码实例

    Python统计时间内的并发数代码实例

    这篇文章主要介绍了Python统计时间内的并发数代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-12-12
  • 在阿里云服务器上配置CentOS+Nginx+Python+Flask环境

    在阿里云服务器上配置CentOS+Nginx+Python+Flask环境

    这篇文章主要介绍了在阿里云服务器上配置CentOS+Nginx+Python+Flask环境的教程,值得一提的是这里的方案用Nginx作反向代理而使用Gunicorn作wsgi服务器,需要的朋友可以参考下
    2016-06-06
  • Python实现文字pdf转换图片pdf效果

    Python实现文字pdf转换图片pdf效果

    当我们把word转化为pdf,wps默认转化为文字pdf,而图片pdf要会员。所以本文将通过Python语言实现文字pdf转换图片pdf,需要的可以参考一下
    2022-04-04
  • python并发爬虫实用工具tomorrow实用解析

    python并发爬虫实用工具tomorrow实用解析

    这篇文章主要介绍了python并发爬虫实用工具tomorrow实用解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-09-09
  • pytorch Dataset,DataLoader产生自定义的训练数据案例

    pytorch Dataset,DataLoader产生自定义的训练数据案例

    这篇文章主要介绍了pytorch Dataset, DataLoader产生自定义的训练数据案例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-03-03
  • Python3实现自定义比较排序/运算符

    Python3实现自定义比较排序/运算符

    这篇文章主要介绍了Python3实现自定义比较排序/运算符,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-02-02
  • 教你用Python pygame设置窗口标题和图标

    教你用Python pygame设置窗口标题和图标

    今天给大家带来的是关于Python的相关知识,文章围绕着用Python pygame设置窗口标题和图标展开,文中有非常详细的介绍及代码示例,需要的朋友可以参考下
    2021-06-06
  • jupyter重新下载与安装实践

    jupyter重新下载与安装实践

    文章主要介绍了如何通过conda卸载Jupyter,并在需要时重新安装,同时,还提到了如何为不同的Python环境安装Jupyter内核,以便在Jupyter Notebook中使用不同的环境
    2026-03-03
  • 五个Python命令使用的小妙招分享

    五个Python命令使用的小妙招分享

    平常在使用python命令过程中,基本上都是用来安装python库时才使用到在控制台的python命令。然而,python命令还有更多的妙用,本文就来为大家详细讲讲
    2022-07-07
  • 快速进修Python指南之面向对象高级篇

    快速进修Python指南之面向对象高级篇

    这篇文章主要为大家介绍了Java开发者如何快速进修Python指南之面向对象高级使用示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-12-12

最新评论