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

