我的知识记录

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-092026-08等月份文件夹,每个月份里按发件人用户名再分,发件人目录里按Excel/PDF/图片分类存放。整个归档结构清晰,后续做月度报表直接进对应月份目录。

注意事项

  • 邮件日期是发件时间,不是收到时间。跨时区邮件的日期可能差几小时,按月份归档影响不大,按天归档就要注意。
  • 发件人目录名取邮箱@前面部分,遇到中文邮箱别名会变成拼音或乱码,建议统一用邮箱前缀。
  • 嵌套目录层级别太深,Windows单路径260字符限制,目录太深文件名被截断。三层以内比较稳。
  • 重复跑脚本会重复归档(同名文件加序号变成xxx_1.xlsx)。想增量归档,把已处理的邮件ID记到本地文件,下次跳过。
  • 大目录用os.walk遍历慢,归档脚本只跑最近200封,配合定时任务每天跑一次就够。

Python下载邮件附件自动归档到文件夹 按日期发件人分类

标签:

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

上一篇:Python自动下载邮件附件 imaplib实战

下一篇:Python批量发送个性化邮件 模板替换姓名