手搓一个「本地邮件摘要」工具:零依赖、数据不出电脑

仓库:github.com/aks-666888/... | SkillHub:邮件摘要待办助手 v2.0.0(安全审核中)

一、痛点

周一早上 200+ 封未读,老板的消息混在订阅推送里。我不想把邮件交给任何云端 AI(隐私焦虑 + 数据出境),又受不了逐封翻------所以手搓了一个本地的邮件摘要工具:

  • 邮件只在本机处理,零依赖(仅 Python 标准库)
  • 把一堆邮件变成「高优/中/低」+「待办清单」+「截止日」
  • 可选本地 LLM(Ollama/Hermes)增强语义,失败自动降级规则
  • 一键推送到手机(企业微信/飞书机器人)

二、为什么选本地处理

方案 隐私 成本 离线可用
通用云端 AI 摘要(Superhuman AI、Shortwave AI 等) ❌ 邮件出本机 月费
本地自托管(本文) ✅ 邮件不出电脑 免费
Apple Intelligence(iOS 端) 设备绑定

2026 年的明确趋势是 on-device/local-first。隐私焦虑最尖锐------企业怕客户邮件/商业计划上云。

三、实现要点

3.1 核心数据结构

邮件统一成一份 list,每封是个 dict:

python 复制代码
{
    "from": "老板王总",
    "subject": "【紧急】客户方案请今天下班前确认",
    "date": "2026-08-24",
    "body": "小李,客户对方案提了两点修改意见......",
}

3.2 优先级打分(关键设计:未读≠重要)

python 复制代码
HIGH = ["紧急", "尽快", "请今天", "截止", "请确认", "请处理", "请回复", "asap", "urgent"]
MID  = ["会议", "周报", "复盘", "进度", "提醒", "改期", "报名", "订阅", "通知"]

def score(em):
    s = 0
    text = (em["subject"] + " " + em["body"]).lower()
    has_high = False
    for k in HIGH:
        if k.lower() in text:
            s += 3
            has_high = True
    for k in MID:
        if k.lower() in text:
            s += 1
    em["_has_high"] = has_high   # 高优用「信号词」标记,不用累加分数
    return s

设计取舍:高优不是「分数最高」,而是「含紧急/截止/需行动类信号词」。避免「未读 = 重要」的误判。

3.3 待办与截止日抽取

python 复制代码
TODO_PAT = re.compile(r"请[^\n。]{2,30}(?:一下|一下我|处理|确认|回复|补交|修改|报名|查看)")
DDL_PAT  = re.compile(r"((?:\d{1,2}\s*月\s*\d{1,2}\s*日)|(?:周[一二三四五六日])|(?:今天|明天|后天|本周|下周))")

def todos(em): return [t.strip() for t in TODO_PAT.findall(em["body"])][:3]
def ddls(em):
    text = em["body"] + " " + em["subject"]
    out = []
    for m in DDL_PAT.finditer(text):
        d = m.group(2) or m.group(3)
        if d: out.append(d.strip())
    return list(dict.fromkeys(out))[:2]

3.4 项目分组

优先取方括号标签([项目A] 周报),否则按关键词匹配:

python 复制代码
def project(em, projects):
    m = re.search(r"\[([^\]]+)\]", em.get("subject", ""))
    if m: return m.group(1)
    body = em.get("body", "").lower()
    for kw in projects:
        if kw.lower() in body or kw.lower() in em.get("subject", "").lower():
            return kw
    return "其他"

3.5 三入口设计(不绑架用户)

  • 宿主连接器(零配置,主推):WorkBuddy/Codex/Claude/Hermes 拉邮件 → 转 JSON → 本技能消费
  • IMAP 直连(自托管):配一次授权码,数据完全自控
  • 文本粘贴(兜底):复制邮件正文存 txt

3.6 输出(JSON 契约)

json 复制代码
{
  "total": 6, "high": 3, "mid": 3, "low": 0,
  "emails": [
    {"from":"老板王总","subject":"...","priority":"high",
     "project":"客户","todos":["请在今天下班前确认并回复我"],"ddl":[]}
  ]
}

HTML/Markdown 输出供人看,JSON 给 Agent 框架消费。

四、踩坑

  1. 未读 ≠ 重要:第一版用「未读+时间衰减」打分,结果营销订阅被误判高优。改用信号词后准确率大幅提升。
  2. 正则贪婪匹配 :截止日正则要排除邮件签名/转发链里的日期串,常见做法是先剥 发件人:/签名块再匹配。
  3. 编码 :IMAP 抓 .eml 要强制 utf-8,国内邮箱(QQ/网易)经常返回 GBK。
  4. 降级:LLM 增强失败时(端点挂了/超时)必须降级到规则------不能因为 LLM 不可用就让整个工具瘫痪。

五、成果

  • 已上架 SkillHub「邮件摘要待办助手」v2.0.0(TRACE 评测安全审核中)
  • 计划:v2.1 加 RAG 召回历史邮件(同一项目上下文)

六、关键代码

完整实现 22KB,单文件 digest.py仓库链接,欢迎 Star / Issue。


标签:#Python #效率工具 #邮件处理 #AI #本地化

相关推荐
PBitW1 小时前
Element plus 自定义列顺序 —— 求指点
前端·element
绿岛之北1 小时前
Electron 安全第五章:网络请求安全
前端·electron
深漂的华哥1 小时前
Ruoyi-Vue-Plus(V5.6.2) 开发环境搭建
java·前端·spring boot·后端·spring·ruoyi
YIAN1 小时前
TS 面试必考题:type 与 interface 的 6 大核心区别,90% 的人答不全
前端·typescript
Canace1 小时前
Fable 像素游戏复盘,Vibe Coding 的 10 条工程规则与赛车 Demo 实践
前端·人工智能·游戏开发
xx24061 小时前
智慧园区前端技能
前端
YHL1 小时前
⚛️ React `useState` 深入浅出
前端·react.js·前端框架
喝咖啡的女孩1 小时前
vibe coding一个云书房
前端
计算机魔术师1 小时前
为了考试作弊,AI 模型黑进了 Hugging Face——这已经不是科幻了
前端