Python下载邮件附件自动归档到文件夹 按日期发件人分类
用imaplib下载附件后按发件人、日期、文件类型自动分文件夹存放,杜绝附件乱成一团,配合文件名校重,附完整可运行代码。
场景痛点
上一篇把附件全下到一个文件夹,跑一周就是几百个文件堆在一起,找三个月前某客户的合同得翻半天。实战里需要自动归档:按月份建文件夹、按发件人分子目录、Excel和PDF分开存。脚本一跑,附件自动落到对应位置,目录结构清清楚楚。
用到的库
imaplib、email都是Python标准库,无需pip安装。
# 无需安装,Python3自带
完整代码
# -*- coding: utf-8 -*-
import os
import imaplib
import email
from email.header import decode_header, make_header
from email.utils import parsedate_to_datetime
IMAP_SERVER = "imap.qq.com"
IMAP_PORT = 993
ACCOUNT = "your_account@qq.com"
PASSWORD = "your_imap_auth_code"
BASE_DIR = "./mailbox_archive" # 归档根目录
# 按扩展名分大类
EXT_CATEGORY = {
".pdf": "PDF", ".doc": "Word", ".docx": "Word",
".xls": "Excel", ".xlsx": "Excel", ".csv": "Excel",
".zip": "压缩包", ".rar": "压缩包",
".jpg": "图片", ".jpeg": "图片", ".png": "图片",
}
def decode_str(s):
if not s:
return ""
return str(make_header(decode_header(s)))
def safe_name(name):
for ch in '/\\:*?"<>|':
name = name.replace(ch, "_")
return name or "unknown"
def archive():
os.makedirs(BASE_DIR, exist_ok=True)
mail = imaplib.IMAP4_SSL(IMAP_SERVER, IMAP_PORT)
mail.login(ACCOUNT, PASSWORD)
mail.select("INBOX")
status, messages = mail.search(None, "ALL")
ids = messages[0].split()[-200:]
count = 0
for mid in reversed(ids):
_, data = mail.fetch(mid, "(BODY.PEEK[])")
msg = email.message_from_bytes(data[0][1])
# 取邮件日期,按 年/月 建目录
try:
dt = parsedate_to_datetime(msg.get("Date"))
year_month = dt.strftime("%Y-%m")
except Exception:
year_month = "unknown-date"
# 取发件人邮箱地址
from_raw = decode_str(msg.get("From") or "")
addr = from_raw.split("<")[-1].rstrip(">").strip() or "unknown"
sender_dir = safe_name(addr.split("@")[0])
for part in msg.walk():
filename = part.get_filename()
if not filename:
continue
filename = safe_name(decode_str(filename))
payload = part.get_payload(decode=True)
if payload is None:
continue
# 按扩展名定大类
ext = os.path.splitext(filename)[1].lower()
category = EXT_CATEGORY.get(ext, "其他")
# 目录结构:根目录/年-月/发件人/类别/文件名
target_dir = os.path.join(BASE_DIR, year_month, sender_dir, category)
os.makedirs(target_dir, exist_ok=True)
filepath = os.path.join(target_dir, filename)
i = 1
base, e = os.path.splitext(filepath)
while os.path.exists(filepath):
filepath = f"{base}_{i}{e}"
i += 1
with open(filepath, "wb") as f:
f.write(payload)
count += 1
print(f"归档:{filepath}")
mail.logout()
print(f"\n完成,共归档 {count} 个附件到 {BASE_DIR}")
if __name__ == "__main__":
archive()
代码讲解
parsedate_to_datetime(msg.get("Date")):把邮件头里的Date字符串解析成datetime对象,再格式化成2026-09这种年月目录名。- 目录结构设计:
归档根目录/2026-09/zhangsan/Excel/xxx.xlsx。按时间→发件人→文件类型三层,找文件时先定位月份,再定位谁发的,最后按类型找,比平铺强太多。 from_raw.split("<")[-1].rstrip(">"):From头格式是张三 <zhangsan@xx.com>,把尖括号里的邮箱抠出来,用@前面的部分当发件人目录名。EXT_CATEGORY:扩展名→中文类别映射表,没匹配到的统一进"其他"。想加类型直接往字典里加。- 同名文件自动加序号,和前面几篇一致。
运行结果
跑完后mailbox_archive目录下出现2026-09、2026-08等月份文件夹,每个月份里按发件人用户名再分,发件人目录里按Excel/PDF/图片分类存放。整个归档结构清晰,后续做月度报表直接进对应月份目录。
注意事项
- 邮件日期是发件时间,不是收到时间。跨时区邮件的日期可能差几小时,按月份归档影响不大,按天归档就要注意。
- 发件人目录名取邮箱@前面部分,遇到中文邮箱别名会变成拼音或乱码,建议统一用邮箱前缀。
- 嵌套目录层级别太深,Windows单路径260字符限制,目录太深文件名被截断。三层以内比较稳。
- 重复跑脚本会重复归档(同名文件加序号变成
xxx_1.xlsx)。想增量归档,把已处理的邮件ID记到本地文件,下次跳过。 - 大目录用os.walk遍历慢,归档脚本只跑最近200封,配合定时任务每天跑一次就够。

更新时间:2026-09-14 21:13:26