Python郵件自動化實戰(zhàn)之發(fā)送附件和智能處理收件箱
引言
在自動化運維和日常辦公中,電子郵件依然是最正式、最廣泛使用的通知和交互手段。無論是定時發(fā)送報表、監(jiān)控報警,還是自動處理用戶請求,郵件自動化都是程序員工具箱中的必備技能。
在Python領(lǐng)域,大多數(shù)開發(fā)者對smtplib發(fā)送郵件較為熟悉,但在郵件接收與處理(尤其是IMAP協(xié)議)方面卻往往力不從心,通常需要編寫大量底層代碼來處理郵件解析、附件下載和搜索條件。本篇文章將深入淺出,不僅講解如何使用smtplib發(fā)送帶附件的復(fù)雜郵件,更將重點引入強大的第三方庫——imap_tools,手把手教你如何優(yōu)雅地讀取和處理收件箱郵件,實現(xiàn)真正意義上的郵件自動化閉環(huán)。
夯實基礎(chǔ) —— 使用smtplib發(fā)送帶附件的郵件
SMTP(Simple Mail Transfer Protocol)是推送郵件的協(xié)議。Python的smtplib模塊封裝了其底層細(xì)節(jié),而email庫則負(fù)責(zé)構(gòu)建符合MIME標(biāo)準(zhǔn)的郵件內(nèi)容。
核心概念:MIMEMultipart
要發(fā)送帶附件的郵件,我們不能使用簡單的MIMEText對象。因為郵件包含獨立的兩部分:正文和附件。這時需要用到MIMEMultipart,它是一個容器,可以將不同的MIME部分組合在一起。
一個標(biāo)準(zhǔn)的帶附件郵件結(jié)構(gòu)如下:
MIMEMultipart(混合類型)
- MIMEText(純文本或HTML正文)
- MIMEBase / MIMEApplication(附件)
實戰(zhàn):發(fā)送帶Excel附件的HTML郵件
下面的示例演示了如何連接QQ郵箱的SMTP服務(wù)器,發(fā)送一封包含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 = '你的授權(quán)碼' # QQ郵箱需使用授權(quán)碼,非登錄密碼
def send_email_with_attachment(receiver, subject, html_content, attachment_path):
"""
發(fā)送帶附件的HTML郵件
"""
# 創(chuàng)建一個混合類型的郵件對象
msg = MIMEMultipart()
msg['From'] = formataddr(('自動化發(fā)送者', 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:
# 創(chuàng)建附件對象 (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} 未找到,郵件將無附件發(fā)送。")
# 3. 發(fā)送郵件
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"郵件發(fā)送成功至 {receiver}")
except Exception as e:
print(f"發(fā)送失敗: {e}")
# 使用示例
if __name__ == '__main__':
html_body = """
<h2>月度數(shù)據(jù)報告</h2>
<p>您好,</p>
<p>本月銷售數(shù)據(jù)請見附件。</p>
<p><strong>請注意:</strong> 此郵件由系統(tǒng)自動發(fā)送,請勿回復(fù)。</p>
"""
send_email_with_attachment(
receiver='target@example.com',
subject='【自動化】2024年5月銷售報表',
html_content=html_body,
attachment_path='./report.xlsx' # 假設(shè)當(dāng)前目錄有該文件
)
注意事項:
- 使用
.starttls()時端口通常為587;若使用SSL,則端口為465并改用smtplib.SMTP_SSL。 - 對于Gmail、QQ等郵箱,務(wù)必使用授權(quán)碼而非郵箱密碼,以確保安全性。
進階突破 —— 使用imap_tools智能處理收件箱
發(fā)送郵件只是自動化的一半。如何自動讀取郵件、下載附件或根據(jù)規(guī)則自動回復(fù),才是真正的難點。標(biāo)準(zhǔn)庫imaplib雖然功能強大,但使用起來較為繁瑣。這里推薦使用基于imaplib封裝的高階庫——imap_tools,它提供了簡潔的查詢語法和對象化的郵件屬性。
安裝與基礎(chǔ)連接
首先,安裝這個輕量級且無外部依賴的庫:
pip install imap-tools
基礎(chǔ)連接使用上下文管理器(with語句),確保連接自動關(guān)閉:
from imap_tools import MailBox
# 連接IMAP服務(wù)器(QQ郵箱IMAP地址:imap.qq.com)
with MailBox('imap.qq.com').login('your_qq@qq.com', '你的授權(quán)碼', initial_folder='INBOX') as mailbox:
print("登錄成功,當(dāng)前文件夾:收件箱")
# 后續(xù)操作...
強大的查詢語法(AND/OR/NOT)
imap_tools的核心優(yōu)勢在于其查詢構(gòu)造器。它模仿了SQLAlchemy的語法,告別了復(fù)雜的IMAP搜索字符串。
基本查詢示例:
from imap_tools import MailBox, AND, OR, NOT
with MailBox('imap.qq.com').login('your_qq@qq.com', '授權(quán)碼', 'INBOX') as mailbox:
# 1. 查詢未讀郵件
unread_emails = mailbox.fetch(AND(seen=False))
# 2. 查詢特定發(fā)件人且包含附件的郵件
specific_emails = mailbox.fetch(AND(from_='boss@company.com', subject='報告'))
# 3. 復(fù)雜查詢:來自某個域,或者是緊急郵件
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對象提供了直觀的屬性來訪問郵件內(nèi)容。以下是一個自動下載所有未讀郵件附件的腳本:
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', '授權(quán)碼', 'INBOX') as mailbox:
# 獲取所有未讀郵件
# fetch 返回一個生成器,支持分頁和排序,這里設(shè)置 reverse=True 讓最新的郵件先出現(xiàn)
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 是附件的二進制數(shù)據(jù) (bytes)
with open(file_path, 'wb') as f:
f.write(att.payload)
print(f" 已下載附件: {filename}")
# 處理完后,可以將郵件標(biāo)記為已讀(默認(rèn)fetch時mark_seen=True),或移動到其他文件夾
# 將郵件移動到 "Processed" 文件夾
mailbox.move([msg.uid], 'PROCESSED')
else:
# 無附件郵件,直接標(biāo)記為已讀,也可以不做任何操作
# 如果不希望在fetch時自動標(biāo)記已讀,可以在fetch參數(shù)中設(shè)置 mark_seen=False
pass
if __name__ == '__main__':
download_attachments_from_inbox()
代碼解析:
msg.attachments返回一個由MailAttachment對象組成的列表,每個對象包含filename、payload(二進制)、content_type等屬性。mailbox.move([msg.uid], 'PROCESSED')演示了如何將處理完的郵件移動到指定文件夾,實現(xiàn)收件箱歸零。fetch方法的limit參數(shù)可以有效防止一次性處理大量郵件導(dǎo)致的性能問題。
郵件自動回復(fù)機器人雛形
結(jié)合發(fā)送和接收,我們可以構(gòu)建一個簡單的自動應(yīng)答機器人:當(dāng)收到特定主題的郵件時,自動回復(fù)預(yù)設(shè)內(nèi)容。
import smtplib
from email.mime.text import MIMEText
from imap_tools import MailBox, AND
# 發(fā)送函數(shù) (簡化版)
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', '授權(quán)碼')
msg = MIMEText('感謝您的來信,我們已經(jīng)收到您的請求,會盡快處理。', 'plain', 'utf-8')
msg['From'] = 'your_qq@qq.com'
msg['To'] = to_addr
msg['Subject'] = f'RE: {original_subject} [自動回復(fù)]'
smtp_server.send_message(msg)
smtp_server.quit()
# 主監(jiān)控邏輯
def auto_responder():
with MailBox('imap.qq.com').login('your_qq@qq.com', '授權(quán)碼', 'INBOX') as inbox:
# 查找未讀的、主題包含"咨詢"的郵件
for msg in inbox.fetch(AND(seen=False, subject='咨詢')):
# 發(fā)送自動回復(fù)
send_reply(msg.from_, msg.subject)
print(f"已回復(fù): {msg.from_}")
# 標(biāo)記為已讀并添加自定義標(biāo)志
inbox.flag([msg.uid], ['ANSWERED'], True)
綜合實戰(zhàn):監(jiān)控郵箱并自動備份附件
假設(shè)你有一個需求:每天定時檢查收件箱,將當(dāng)天收到的所有郵件的Excel附件下載下來,并將下載記錄發(fā)送給管理員。
完整流程:
- 使用
imap_tools連接IMAP,查詢當(dāng)天日期范圍內(nèi)的郵件。 - 遍歷郵件,下載
.xlsx附件。 - 所有附件下載完成后,調(diào)用
smtplib發(fā)送一封匯總郵件給管理員。
這部分代碼融合了上述所有知識點,是郵件自動化的典型應(yīng)用場景。通過結(jié)合操作系統(tǒng)的定時任務(wù)(如Linux Crontab或Windows任務(wù)計劃程序),即可實現(xiàn)無人值守的自動化處理。
常見問題與避坑指南
授權(quán)碼 vs 密碼:幾乎所有主流郵箱(QQ、163、Gmail)在開啟SMTP/IMAP服務(wù)后,都需要使用生成的授權(quán)碼作為密碼登錄,直接使用網(wǎng)頁登錄密碼會報錯。
IMAP文件夾名稱:默認(rèn)收件箱是INBOX。其他文件夾(如“已發(fā)送”、“歸檔”)的名稱可能因郵箱服務(wù)商而異,例如QQ郵箱的“已發(fā)送”可能是&XfJT0ZAB4這種編碼形式。建議先使用mailbox.folder.list()打印所有文件夾名稱。
附件編碼:att.payload返回的是原始二進制數(shù)據(jù),直接寫入文件即可。如果遇到附件名亂碼,可以使用att.filename,該屬性通常已經(jīng)被imap-tools處理過。
性能考量:如果需要處理海量郵件,務(wù)必使用fetch的limit和bulk參數(shù)。設(shè)置bulk=True可以減少與服務(wù)器的交互次數(shù),但會占用更多內(nèi)存。
到此這篇關(guān)于Python郵件自動化實戰(zhàn)之發(fā)送附件和智能處理收件箱的文章就介紹到這了,更多相關(guān)Python郵件自動化內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python獲取網(wǎng)頁數(shù)據(jù)的五種方法
在 Python 中,爬蟲用于自動化獲取網(wǎng)頁數(shù)據(jù),你可以使用多種方法來抓取網(wǎng)頁內(nèi)容,具體使用哪種方法取決于網(wǎng)頁的結(jié)構(gòu)、內(nèi)容類型以及你所需的精確度,以下是常見的 5 種獲取網(wǎng)頁數(shù)據(jù)的方式,需要的朋友可以參考下2025-01-01
Python實現(xiàn)批量提取Excel數(shù)據(jù)
在數(shù)據(jù)處理和分析的過程中,Excel 是一種廣泛使用的數(shù)據(jù)存儲格式,本文將詳細(xì)介紹如何使用 pandas、openpyxl 和 xlrd 三種庫來批量提取 Excel 數(shù)據(jù),并提供相應(yīng)的示例代碼,需要的可以參考下2024-12-12
一文帶你掌握Python性能分析工具Pyflame火焰圖的實戰(zhàn)指南
你是否曾經(jīng)遇到過Python程序運行緩慢,卻不知道問題出在哪里,Pyflame就是為解決這個問題而生的利器,下面小編就和大家詳細(xì)講講Pyflame的具體使用吧2025-12-12
django-celery-beat搭建定時任務(wù)的實現(xiàn)
本文主要介紹了django-celery-beat搭建定時任務(wù)的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-03-03
Python使用pandas導(dǎo)入xlsx格式的excel文件內(nèi)容操作代碼
這篇文章主要介紹了Python使用pandas導(dǎo)入xlsx格式的excel文件內(nèi)容,基本導(dǎo)入是在Python中使用pandas導(dǎo)入.xlsx文件的方法是read_excel(),本文結(jié)合示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-12-12
Python xlwt庫處理整數(shù)格式的陷阱與最佳實踐
在使用 Python 進行數(shù)據(jù)處理并導(dǎo)出到 Excel 時,xlwt 是一個經(jīng)典且廣泛使用的庫,本文將深入探討 xlwt 處理整數(shù)時的核心機制,分析常見陷阱,并提供一套完整的解決方案,希望對大家有所幫助2026-01-01

