Python按发件人筛选邮件并下载附件
用imaplib的FROM搜索条件只抓取指定客户/供应商发来的邮件,自动下载他们的附件,避免把广告和无关邮件附件也拉下来,附完整代码。
场景痛点
邮箱里每天几百封邮件,客户A发来的合同附件、供应商B发来的报价表,散在各种推广邮件中间。手动只下载某个人的附件,得靠搜索框翻半天,还容易漏。用imaplib的FROM搜索条件直接在服务器端按发件人过滤,只拉这个人的邮件,附件自动下载,一分钟搞定。
用到的库
imaplib、email都是Python标准库,无需pip安装。
# 无需安装,Python3自带
完整代码
# -*- coding: utf-8 -*-
import os
import imaplib
import email
from email.header import decode_header, make_header
IMAP_SERVER = "imap.qq.com"
IMAP_PORT = 993
ACCOUNT = "your_account@qq.com"
PASSWORD = "your_imap_auth_code"
# 只下载这个发件人发来的邮件附件(支持邮箱地址或姓名)
TARGET_SENDER = "sales@client.com"
SAVE_DIR = "./attachments_by_sender"
def decode_str(s):
if not s:
return ""
return str(make_header(decode_header(s)))
def safe_filename(name):
for ch in '/\\:*?"<>|':
name = name.replace(ch, "_")
return name or "attachment"
def download_from_sender(sender):
os.makedirs(SAVE_DIR, exist_ok=True)
mail = imaplib.IMAP4_SSL(IMAP_SERVER, IMAP_PORT)
mail.login(ACCOUNT, PASSWORD)
mail.select("INBOX")
# 关键:在服务器端按发件人搜索,只返回这个人的邮件
# FROM后面跟邮箱地址或姓名片段,加引号更稳
status, messages = mail.search(None, 'FROM', f'"{sender}"')
if status != "OK":
print("搜索失败")
mail.logout()
return
id_list = messages[0].split()
print(f"来自 {sender} 的邮件共 {len(id_list)} 封")
count = 0
for msg_id in id_list:
status, msg_data = mail.fetch(msg_id, "(BODY.PEEK[])")
msg = email.message_from_bytes(msg_data[0][1])
subject = decode_str(msg.get("Subject"))
for part in msg.walk():
filename = part.get_filename()
if not filename:
continue
filename = safe_filename(decode_str(filename))
payload = part.get_payload(decode=True)
if payload is None:
continue
filepath = os.path.join(SAVE_DIR, filename)
i = 1
base, ext = os.path.splitext(filepath)
while os.path.exists(filepath):
filepath = f"{base}_{i}{ext}"
i += 1
with open(filepath, "wb") as f:
f.write(payload)
count += 1
print(f" 下载:{filename} ({subject})")
mail.logout()
print(f"完成,共下载 {count} 个附件")
if __name__ == "__main__":
download_from_sender(TARGET_SENDER)
代码讲解
mail.search(None, 'FROM', f'"{sender}"'):IMAP原生搜索条件,服务器只返回发件人地址里包含sender字符串的邮件。比把所有邮件拉到本地再用代码过滤快得多,尤其邮件多的时候。FROM匹配是子串匹配:传client.com能命中所有@client.com发来的邮件,传张三能命中发件人姓名里带张三的邮件。- 其他搜索条件可以和FROM组合:
mail.search(None, 'FROM', '"a@b.com"', 'UNSEEN')就表示"这个人发来的未读邮件"。 BODY.PEEK[]:抓取时不把邮件标记为已读,适合做只下载不影响原邮件状态的场景。- 保存目录按发件人单独建一个,多跑几个发件人时附件不会混在一起。
运行结果
脚本跑完后终端打印这个人有多少封邮件、下载了哪些附件,attachments_by_sender文件夹里全是该客户发来的合同、报价、报表,其他邮件一律不碰。
注意事项
FROM匹配的是邮件头里的原始地址,如果发件人用了别名,地址可能和显示的姓名不一致。先把TARGET_SENDER改成对方邮箱地址最准。- 国内邮箱IMAP对搜索条件的支持略有差异,QQ、163都支持FROM;如果搜不到结果,去掉引号或换成部分域名试试。
- 搜中文名发件人时,IMAP搜索字符串要按UTF-8编码,部分老邮箱可能搜不到中文姓名,改用邮箱地址最稳。
- 同一发件人多封邮件可能附件同名,脚本里已经做了加序号防覆盖。
- 想一次筛多个发件人,外层套个循环,对每个地址分别search即可。

更新时间:2026-09-14 21:09:29