AI真好玩系列-Agent Skill深度调研⑭email-management | AI邮件管理助手

0 阅读1分钟

AI真好玩系列-Agent Skill深度调研⑭email-management | AI邮件管理助手

@[TOC]( AI真好玩系列-Agent Skill深度调研⑭email-management | AI邮件管理助手)

开头碎碎念

宝宝们又来啦~👋 今天给大家介绍一个让我直呼"终于不用再被邮件淹没了"的 Agent Skill——email-management!

你有没有遇到过这种情况:周一早上打开邮箱,500+未读邮件扑面而来,光是分类就要花半小时;老板催你回复客户邮件,你翻遍了收件箱也找不到那封;好不容易写完一封正式邮件,结果忘了加附件就发出去了...😅

更惨的是,每天花2-3小时处理邮件,其中80%都是通知、广告、抄送的无关内容,真正需要你处理的可能就那么十几封。但你不敢不看,因为怕漏掉重要信息...这种"邮件焦虑症"谁懂啊!😭

以前要解决这个问题,你只能靠规则过滤器,但那些规则又笨又死板——标题包含"发票"就归到财务文件夹?那客户问"发票什么时候开"的邮件也归过去了啊!🤦

现在好了,email-management 让 AI Agent 来帮你管邮件!它能理解邮件语义,自动分类、智能回复、批量处理,还能定时发送。关键是它真的"懂"你的邮件,不是那种傻乎乎的关键词匹配!🧠

废话不多说,让我带你从原理到实战,彻底搞懂这个 AI Agent 的邮件管理神器~ 🚀

🌟 项目简介 | Project Introduction

email-management 是 Agent 生态中最热门的邮件管理 Skill,它赋予 AI Agent 读取、分类、起草和发送邮件的能力,支持 Gmail、Outlook 等主流邮箱服务。通过 Google Workspace API 或 SMTP/IMAP 协议连接邮箱,实现了自动分类、智能回复、批量处理、定时发送等核心功能,让 AI 真正成为你的邮件管家。

核心特性一览

特性说明
多邮箱支持支持 Gmail、Outlook、Yahoo、自定义 SMTP 邮箱
邮件读取读取收件箱、已发送、草稿等文件夹的邮件
智能分类基于 LLM 语义理解自动分类邮件
智能回复根据邮件内容和上下文生成回复草稿
批量处理批量归档、删除、标记已读、移动文件夹
定时发送在指定时间自动发送邮件
邮件搜索按发件人、主题、日期、标签等条件搜索
附件处理读取附件信息、下载附件、添加附件
模板管理创建和管理邮件模板,支持变量替换
安全认证OAuth2.0 认证、凭证加密存储

🤔 为什么需要 email-management? | Why email-management?

痛点场景还原

痛点1:邮件太多,根本看不过来

你(周一早上打开邮箱):500封未读??
你:先按重要性排序吧...
邮箱:只能按时间排序哦 😅
你:那我设置规则过滤...
邮箱:规则只能匹配关键词,不能理解内容
你:把包含"紧急"的标红!
邮箱:好的,已经标红了300封...每封都是"不紧急但FYI" 😂
你:......

痛点2:写邮件太费时间

你(写一封商务邮件):
第一步:想措辞... "尊敬的XX" 还是 "Hi XX"?
第二步:写正文... 怎么表达才既专业又友好?
第三步:检查语气... 会不会太生硬?
第四步:加附件... 等等,附件是什么来着?
第五步:检查收件人... 抄送谁?密送谁?
...30分钟后...
你:终于写完了!
同事:你还没回我Slack消息呢
你:我在写邮件啊!
同事:一封邮件写半小时?😅

痛点3:重复性邮件处理效率低下

你(每天的工作):
- 回复10封"收到,谢谢"
- 转发5封周报给领导
- 归档20封系统通知
- 删除15封广告邮件
- 回复3封客户咨询(内容都差不多)
...2小时后...
你:我今天到底干了啥?
你:好像就是在处理邮件...
你:真正的工作还没开始呢 😭

痛点4:跨时区沟通困难

你(中国时间下午5点):该给美国客户发邮件了
你:但他们那边是凌晨5点...
你:现在发过去他们看不到
你:明早发?我可能忘了
你:设闹钟?凌晨5点起来发邮件??
你:为什么没有定时发送功能啊!😤

对比表格

问题传统邮箱客户端规则过滤器email-management
邮件分类手动拖拽关键词匹配语义理解 ✔️
邮件回复手动编写自动回复(模板)智能生成 ✔️
批量处理逐个操作有限支持智能批量 ✔️
定时发送部分支持不支持完整支持 ✔️
上下文理解LLM理解 ✔️
多邮箱管理切换账号不支持统一管理 ✔️
个性化定制有限规则复杂自然语言 ✔️
学习成本低 ✔️

一句话总结:**email-management 让 AI 从"帮你收邮件"变成"帮你管邮件"!**📧

📌 前提条件 | Prerequisites

  1. Python 3.9+Node.js 18+:开发环境
  2. 邮箱账号:Gmail / Outlook / 支持SMTP的邮箱
  3. API 凭证
    • Gmail:Google Cloud 项目 + OAuth2.0 凭证
    • Outlook:Microsoft Azure 应用注册
    • SMTP:邮箱账号 + 应用专用密码
  4. LLM API Key:OpenAI / Anthropic / 其他兼容 API
  5. 基础网络知识:了解 OAuth2.0、SMTP、IMAP 协议基础

支持的邮箱服务

邮箱服务连接方式认证方式支持程度
GmailGoogle Workspace APIOAuth2.0完整支持 ✔️
OutlookMicrosoft Graph APIOAuth2.0完整支持 ✔️
YahooIMAP + SMTP应用密码基本支持
163邮箱IMAP + SMTP授权码基本支持
QQ邮箱IMAP + SMTP授权码基本支持
自定义邮箱IMAP + SMTP账号密码基本支持

注意:Gmail 和 Outlook 推荐使用官方 API,功能更完整、安全性更高。其他邮箱使用 IMAP + SMTP 协议连接。

🔧 核心技术栈 | Core Tech Stack

┌─────────────────────────────────────────────────────────────┐
│                    email-management 技术栈                     │
│                                                             │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐         │
│  │  LLM 层      │  │  协议层      │  │  存储层      │         │
│  │             │  │             │  │             │         │
│  │ OpenAI GPT  │  │ SMTP        │  │ SQLite      │         │
│  │ Anthropic   │  │ IMAP        │  │ Redis       │         │
│  │ Ollama      │  │ Google API  │  │ 文件系统     │         │
│  │ LangChain   │  │ MS Graph    │  │ 加密存储     │         │
│  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘         │
│         │                │                │                  │
│  ┌──────┴────────────────┴────────────────┴──────┐         │
│  │              email-management 核心              │         │
│  │                                               │         │
│  │  ┌──────────┐ ┌──────────┐ ┌──────────┐      │         │
│  │  │ 分类引擎  │ │ 回复引擎  │ │ 调度引擎  │      │         │
│  │  └──────────┘ └──────────┘ └──────────┘      │         │
│  │  ┌──────────┐ ┌──────────┐ ┌──────────┐      │         │
│  │  │ 搜索引擎  │ │ 模板引擎  │ │ 安全引擎  │      │         │
│  │  └──────────┘ └──────────┘ └──────────┘      │         │
│  └───────────────────────────────────────────────┘         │
│                          │                                  │
│  ┌───────────────────────┴───────────────────────┐         │
│  │              Agent 框架适配层                    │         │
│  │                                               │         │
│  │  OpenAI Agents | LangChain | CrewAI | AutoGen │         │
│  └───────────────────────────────────────────────┘         │
└─────────────────────────────────────────────────────────────┘

技术栈详解

层级技术用途
LLMOpenAI GPT-4o / GPT-4o-mini邮件理解、分类、回复生成
LLMAnthropic Claude备选 LLM,长文本理解
LLMOllama (本地模型)隐私敏感场景的本地推理
协议SMTP (Simple Mail Transfer Protocol)发送邮件
协议IMAP (Internet Message Access Protocol)读取邮件
协议Google Workspace API (Gmail API)Gmail 完整操作
协议Microsoft Graph APIOutlook 完整操作
认证OAuth2.0Gmail/Outlook 安全认证
认证App PasswordSMTP 认证
存储SQLite本地缓存和配置存储
存储Redis队列和调度管理
加密AES-256凭证加密存储
框架LangChainAgent 编排
框架CrewAI多 Agent 协作

🔬 核心原理详解 | Core Principles

1. 邮件协议原理

SMTP 协议 - 发送邮件

SMTP(Simple Mail Transfer Protocol)是互联网上发送邮件的标准协议。了解它的原理对于理解 email-management 的邮件发送功能至关重要。

"""
SMTP 协议工作原理详解
SMTP 使用 TCP 端口 25(明文)/ 587(STARTTLS)/ 465(SSL)
通信过程采用命令-响应模式
"""

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
from datetime import datetime

# ============ SMTP 连接和发送的基本流程 ============

def send_email_smtp(
    smtp_server: str,
    smtp_port: int,
    username: str,
    password: str,
    to_addr: str,
    subject: str,
    body: str,
    use_ssl: bool = True
) -> bool:
    """
    通过 SMTP 协议发送邮件

    SMTP 通信流程:
    1. 客户端连接服务器(TCP三次握手)
    2. 服务器发送 220 就绪响应
    3. 客户端发送 EHLO/HELO(身份问候)
    4. 服务器响应 250 支持的扩展
    5. 客户端发送 AUTH LOGIN(认证请求)
    6. 客户端发送用户名和密码(Base64编码)
    7. 客户端发送 MAIL FROM(发件人地址)
    8. 客户端发送 RCPT TO(收件人地址)
    9. 客户端发送 DATA(邮件内容)
    10. 客户端发送 QUIT(断开连接)
    """
    try:
        # 步骤1:建立连接
        if use_ssl:
            # SSL 直连(端口465)- 连接时即加密
            server = smtplib.SMTP_SSL(smtp_server, smtp_port)
        else:
            # STARTTLS(端口587)- 先明文连接再升级加密
            server = smtplib.SMTP(smtp_server, smtp_port)
            server.ehlo()          # 发送 EHLO 问候
            server.starttls()      # 升级为 TLS 加密连接
            server.ehlo()          # 再次发送 EHLO(加密后)

        # 步骤2:登录认证
        server.login(username, password)

        # 步骤3:构建邮件消息
        msg = MIMEMultipart()
        msg['From'] = username       # 发件人
        msg['To'] = to_addr          # 收件人
        msg['Subject'] = subject     # 主题
        msg['Date'] = datetime.now().strftime(
            '%a, %d %b %Y %H:%M:%S +0800'
        )  # 日期

        # 添加邮件正文
        msg.attach(MIMEText(body, 'html', 'utf-8'))

        # 步骤4:发送邮件
        server.sendmail(username, to_addr, msg.as_string())

        # 步骤5:断开连接
        server.quit()

        return True

    except smtplib.SMTPAuthenticationError:
        print("认证失败:用户名或密码错误")
        return False
    except smtplib.SMTPConnectError:
        print("连接失败:无法连接到SMTP服务器")
        return False
    except Exception as e:
        print(f"发送失败:{e}")
        return False


# ============ 带附件的邮件发送 ============

def send_email_with_attachment(
    smtp_server: str,
    smtp_port: int,
    username: str,
    password: str,
    to_addr: str,
    subject: str,
    body: str,
    attachment_path: str
) -> bool:
    """发送带附件的邮件"""
    try:
        # 建立连接
        server = smtplib.SMTP_SSL(smtp_server, smtp_port)
        server.login(username, password)

        # 构建邮件
        msg = MIMEMultipart()
        msg['From'] = username
        msg['To'] = to_addr
        msg['Subject'] = subject

        # 添加正文
        msg.attach(MIMEText(body, 'html', 'utf-8'))

        # 添加附件
        with open(attachment_path, 'rb') as f:
            part = MIMEBase('application', 'octet-stream')
            part.set_payload(f.read())
            encoders.encode_base64(part)  # Base64 编码附件

            # 设置附件文件名(支持中文)
            filename = attachment_path.split('/')[-1]
            part.add_header(
                'Content-Disposition',
                f'attachment; filename="{filename}"'
            )
            msg.attach(part)

        # 发送
        server.sendmail(username, to_addr, msg.as_string())
        server.quit()
        return True

    except Exception as e:
        print(f"发送失败:{e}")
        return False


# ============ 常见 SMTP 服务器配置 ============

SMTP_CONFIGS = {
    "gmail": {
        "server": "smtp.gmail.com",
        "port_ssl": 465,       # SSL 端口
        "port_tls": 587,       # STARTTLS 端口
        "note": "需要开启应用专用密码"
    },
    "outlook": {
        "server": "smtp.office365.com",
        "port_ssl": 587,
        "port_tls": 587,
        "note": "需要开启SMTP AUTH"
    },
    "163": {
        "server": "smtp.163.com",
        "port_ssl": 465,
        "port_tls": 25,
        "note": "需要在邮箱设置中开启SMTP并获取授权码"
    },
    "qq": {
        "server": "smtp.qq.com",
        "port_ssl": 465,
        "port_tls": 587,
        "note": "需要在邮箱设置中开启SMTP并获取授权码"
    }
}
IMAP 协议 - 读取邮件
"""
IMAP 协议工作原理详解
IMAP (Internet Message Access Protocol) 用于从邮件服务器读取邮件
与 POP3 不同,IMAP 允许在服务器上管理邮件,多设备同步
"""

import imaplib
import email
from email.header import decode_header
from typing import List, Dict, Optional


def decode_str(s: str) -> str:
    """解码邮件头部字段(支持中文等编码)"""
    if s is None:
        return ""
    parts = decode_header(s)
    result = []
    for content, charset in parts:
        if isinstance(content, bytes):
            # 使用检测到的编码或默认 UTF-8 解码
            result.append(content.decode(charset or 'utf-8', errors='replace'))
        else:
            result.append(content)
    return ''.join(result)


def read_emails_imap(
    imap_server: str,
    username: str,
    password: str,
    folder: str = "INBOX",
    limit: int = 10,
    search_criteria: str = "UNSEEN"  # 未读邮件
) -> List[Dict]:
    """
    通过 IMAP 协议读取邮件

    IMAP 通信流程:
    1. 客户端连接服务器
    2. 登录认证
    3. 选择文件夹(SELECT)
    4. 搜索邮件(SEARCH)
    5. 获取邮件内容(FETCH)
    6. 关闭连接

    常用搜索条件:
    - ALL:所有邮件
    - UNSEEN:未读邮件
    - FROM "xxx":来自某人的邮件
    - SUBJECT "xxx":主题包含某关键词
    - SINCE "01-Jan-2025":某日期之后的邮件
    - BEFORE "01-Feb-2025":某日期之前的邮件
    """
    emails = []

    try:
        # 步骤1:建立 IMAP 连接
        mail = imaplib.IMAP4_SSL(imap_server)

        # 步骤2:登录
        mail.login(username, password)

        # 步骤3:选择文件夹
        # 常见文件夹:INBOX, Sent, Drafts, Trash, Spam
        # Gmail 特殊标签:[Gmail]/All Mail, [Gmail]/Spam
        status, _ = mail.select(folder)
        if status != 'OK':
            print(f"无法选择文件夹: {folder}")
            return emails

        # 步骤4:搜索邮件
        status, message_ids = mail.search(None, search_criteria)
        if status != 'OK':
            print("搜索失败")
            return emails

        # 获取邮件ID列表(倒序,最新的在前)
        id_list = message_ids[0].split()
        id_list = id_list[-limit:]  # 只取最近的N封

        # 步骤5:逐封获取邮件内容
        for msg_id in id_list:
            # FETCH 命令获取邮件的 RFC822 格式内容
            status, msg_data = mail.fetch(msg_id, '(RFC822)')
            if status != 'OK':
                continue

            # 解析邮件
            raw_email = msg_data[0][1]
            msg = email.message_from_bytes(raw_email)

            # 提取邮件信息
            email_info = {
                "id": msg_id.decode(),
                "from": decode_str(msg.get('From')),
                "to": decode_str(msg.get('To')),
                "subject": decode_str(msg.get('Subject')),
                "date": msg.get('Date'),
                "body": "",
                "attachments": []
            }

            # 解析邮件正文和附件
            if msg.is_multipart():
                # 多部分邮件(HTML + 纯文本 + 附件)
                for part in msg.walk():
                    content_type = part.get_content_type()
                    disposition = str(part.get('Content-Disposition'))

                    if content_type == 'text/plain' and 'attachment' not in disposition:
                        # 纯文本正文
                        charset = part.get_content_charset() or 'utf-8'
                        email_info["body"] = part.get_payload(
                            decode=True
                        ).decode(charset, errors='replace')

                    elif content_type == 'text/html' and 'attachment' not in disposition:
                        # HTML 正文(优先使用HTML)
                        charset = part.get_content_charset() or 'utf-8'
                        email_info["body"] = part.get_payload(
                            decode=True
                        ).decode(charset, errors='replace')

                    elif 'attachment' in disposition:
                        # 附件
                        filename = decode_str(part.get_filename())
                        if filename:
                            email_info["attachments"].append({
                                "filename": filename,
                                "size": len(part.get_payload(decode=True)),
                                "content_type": content_type
                            })
            else:
                # 单部分邮件
                charset = msg.get_content_charset() or 'utf-8'
                email_info["body"] = msg.get_payload(
                    decode=True
                ).decode(charset, errors='replace')

            emails.append(email_info)

        # 步骤6:关闭连接
        mail.close()
        mail.logout()

    except imaplib.IMAP4.error as e:
        print(f"IMAP 错误: {e}")
    except Exception as e:
        print(f"读取邮件失败: {e}")

    return emails


# ============ 常见 IMAP 服务器配置 ============

IMAP_CONFIGS = {
    "gmail": {
        "server": "imap.gmail.com",
        "port": 993,
        "note": "需要开启应用专用密码"
    },
    "outlook": {
        "server": "outlook.office365.com",
        "port": 993,
        "note": "需要开启IMAP访问"
    },
    "163": {
        "server": "imap.163.com",
        "port": 993,
        "note": "需要在邮箱设置中开启IMAP"
    },
    "qq": {
        "server": "imap.qq.com",
        "port": 993,
        "note": "需要在邮箱设置中开启IMAP"
    }
}

2. Gmail API 集成原理

Gmail API 是 Google 提供的官方 RESTful API,相比 IMAP/SMTP 提供了更丰富的功能和更高的安全性。email-management 优先使用 Gmail API 来操作 Gmail 邮箱。

"""
Gmail API 集成详解
通过 Google Workspace API 实现 Gmail 的完整操作
使用 OAuth2.0 进行安全认证
"""

from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
from base64 import urlsafe_b64encode, urlsafe_b64decode
import os
import json
from typing import List, Dict, Optional


# ============ OAuth2.0 认证流程 ============

# Gmail API 需要的权限范围
SCOPES = [
    'https://www.googleapis.com/auth/gmail.readonly',     # 只读权限
    'https://www.googleapis.com/auth/gmail.send',         # 发送权限
    'https://www.googleapis.com/auth/gmail.compose',      # 撰写权限
    'https://www.googleapis.com/auth/gmail.modify',       # 修改权限(标记已读等)
    'https://www.googleapis.com/auth/gmail.labels',       # 标签管理权限
]


def gmail_authenticate(
    credentials_file: str = 'credentials.json',
    token_file: str = 'token.json'
) -> Optional[object]:
    """
    Gmail OAuth2.0 认证流程

    认证步骤:
    1. 检查是否有已保存的 token
    2. 如果 token 有效,直接使用
    3. 如果 token 过期但有 refresh_token,自动刷新
    4. 如果没有 token,打开浏览器让用户授权
    5. 获取授权码,换取 access_token
    6. 保存 token 供后续使用

    首次使用需要在 Google Cloud Console:
    1. 创建项目
    2. 启用 Gmail API
    3. 创建 OAuth2.0 客户端 ID
    4. 下载 credentials.json
    """
    creds = None

    # 步骤1:检查已保存的 token
    if os.path.exists(token_file):
        creds = Credentials.from_authorized_user_file(token_file, SCOPES)

    # 步骤2:如果没有有效凭证,进行认证
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            # 步骤3:token 过期但有 refresh_token,自动刷新
            creds.refresh(Request())
        else:
            # 步骤4:没有 token,打开浏览器授权
            flow = InstalledAppFlow.from_client_secrets_file(
                credentials_file, SCOPES
            )
            creds = flow.run_local_server(port=0)

        # 步骤6:保存 token
        with open(token_file, 'w') as token:
            token.write(creds.to_json())

    # 构建 Gmail API 服务对象
    service = build('gmail', 'v1', credentials=creds)
    return service


# ============ Gmail API 读取邮件 ============

def gmail_list_messages(
    service: object,
    query: str = '',
    max_results: int = 20,
    label_ids: List[str] = None
) -> List[Dict]:
    """
    列出 Gmail 邮件

    常用查询语法(Gmail 搜索语法):
    - is:unread           未读邮件
    - from:user@email.com 来自某人的邮件
    - to:user@email.com   发给某人的邮件
    - subject:hello       主题包含 hello
    - has:attachment      有附件的邮件
    - label:inbox         收件箱中的邮件
    - newer_than:1d       一天内的邮件
    - older_than:7d       七天前的邮件
    - is:starred          星标邮件
    - category:primary    主要邮件
    - category:promotions 推广邮件
    - category:updates    更新邮件
    """
    try:
        results = service.users().messages().list(
            userId='me',
            q=query,
            maxResults=max_results,
            labelIds=label_ids
        ).execute()

        messages = results.get('messages', [])
        return messages

    except HttpError as error:
        print(f"Gmail API 错误: {error}")
        return []


def gmail_get_message(service: object, msg_id: str) -> Dict:
    """
    获取单封 Gmail 邮件的完整内容

    Gmail API 返回的邮件结构:
    - payload.headers: 邮件头(From, To, Subject 等)
    - payload.parts: 邮件正文和附件(多部分邮件)
    - payload.body: 邮件正文(单部分邮件)
    - sizeEstimate: 邮件大小估算
    - labelIds: 邮件标签
    """
    try:
        msg = service.users().messages().get(
            userId='me',
            id=msg_id,
            format='full'  # full: 完整内容 / minimal: 仅ID和标签 / raw: 原始RFC822
        ).execute()

        # 解析邮件头
        headers = msg['payload'].get('headers', [])
        header_dict = {}
        for h in headers:
            header_dict[h['name'].lower()] = h['value']

        # 解析邮件正文
        body = gmail_extract_body(msg['payload'])

        # 解析附件信息
        attachments = gmail_extract_attachments(msg['payload'])

        return {
            "id": msg['id'],
            "thread_id": msg['threadId'],
            "from": header_dict.get('from', ''),
            "to": header_dict.get('to', ''),
            "subject": header_dict.get('subject', ''),
            "date": header_dict.get('date', ''),
            "body": body,
            "attachments": attachments,
            "labels": msg.get('labelIds', []),
            "snippet": msg.get('snippet', ''),  # 邮件摘要(自动生成)
            "size_estimate": msg.get('sizeEstimate', 0)
        }

    except HttpError as error:
        print(f"获取邮件失败: {error}")
        return {}


def gmail_extract_body(payload: Dict) -> str:
    """递归提取邮件正文(支持嵌套的多部分邮件)"""
    body = ""

    if payload.get('body', {}).get('data'):
        # 单部分邮件,直接解码
        body = urlsafe_b64decode(
            payload['body']['data']
        ).decode('utf-8', errors='replace')

    elif payload.get('parts'):
        # 多部分邮件,递归查找文本内容
        for part in payload['parts']:
            content_type = part.get('mimeType', '')

            if content_type == 'text/plain':
                # 纯文本正文
                if part.get('body', {}).get('data'):
                    body = urlsafe_b64decode(
                        part['body']['data']
                    ).decode('utf-8', errors='replace')

            elif content_type == 'text/html':
                # HTML 正文(优先使用)
                if part.get('body', {}).get('data'):
                    body = urlsafe_b64decode(
                        part['body']['data']
                    ).decode('utf-8', errors='replace')

            elif content_type.startswith('multipart/'):
                # 嵌套的多部分,递归处理
                body = gmail_extract_body(part)

    return body


def gmail_extract_attachments(payload: Dict) -> List[Dict]:
    """提取邮件附件信息"""
    attachments = []

    if payload.get('parts'):
        for part in payload['parts']:
            if part.get('filename'):
                # 有文件名的部分是附件
                attachments.append({
                    "filename": part['filename'],
                    "attachment_id": part['body'].get('attachmentId', ''),
                    "size": part['body'].get('size', 0),
                    "mime_type": part.get('mimeType', '')
                })

            # 递归查找嵌套部分的附件
            if part.get('parts'):
                attachments.extend(
                    gmail_extract_attachments(part)
                )

    return attachments


# ============ Gmail API 发送邮件 ============

def gmail_send_message(
    service: object,
    to: str,
    subject: str,
    body: str,
    cc: str = None,
    bcc: str = None,
    reply_to: str = None,
    thread_id: str = None,
    references: str = None
) -> Optional[str]:
    """
    通过 Gmail API 发送邮件

    支持的功能:
    - 发送新邮件
    - 回复邮件(通过 threadId 关联到同一会话)
    - 抄送和密送
    - HTML 格式正文
    """
    try:
        # 构建邮件消息
        message = MIMEMultipart()
        message['to'] = to
        message['subject'] = subject

        if cc:
            message['cc'] = cc
        if bcc:
            message['bcc'] = bcc
        if reply_to:
            message['Reply-To'] = reply_to

        # 回复邮件时关联到原始会话
        if thread_id and references:
            message['In-Reply-To'] = references
            message['References'] = references

        # 添加 HTML 正文
        message.attach(MIMEText(body, 'html', 'utf-8'))

        # 编码为 base64url 格式(Gmail API 要求)
        raw_message = urlsafe_b64encode(
            message.as_bytes()
        ).decode('utf-8')

        # 构建请求体
        send_body = {'raw': raw_message}
        if thread_id:
            send_body['threadId'] = thread_id

        # 发送邮件
        result = service.users().messages().send(
            userId='me',
            body=send_body
        ).execute()

        return result['id']

    except HttpError as error:
        print(f"发送邮件失败: {error}")
        return None


# ============ Gmail API 标签和分类操作 ============

def gmail_manage_labels(
    service: object,
    msg_id: str,
    add_labels: List[str] = None,
    remove_labels: List[str] = None
) -> bool:
    """
    管理邮件标签(用于分类和状态管理)

    常用系统标签 ID:
    - INBOX       收件箱
    - SENT        已发送
    - DRAFT       草稿
    - TRASH       回收站
    - SPAM        垃圾邮件
    - UNREAD      未读
    - STARRED     星标
    - IMPORTANT   重要

    自定义标签可以通过 list() 方法获取
    """
    try:
        body = {}
        if add_labels:
            body['addLabelIds'] = add_labels
        if remove_labels:
            body['removeLabelIds'] = remove_labels

        service.users().messages().modify(
            userId='me',
            id=msg_id,
            body=body
        ).execute()

        return True

    except HttpError as error:
        print(f"标签操作失败: {error}")
        return False


def gmail_list_custom_labels(service: object) -> List[Dict]:
    """获取所有自定义标签"""
    try:
        results = service.users().labels().list(
            userId='me'
        ).execute()

        labels = results.get('labels', [])
        return [
            {
                "id": label['id'],
                "name": label['name'],
                "type": label['type'],  # system 或 user
                "color": label.get('color', {})
            }
            for label in labels
        ]

    except HttpError as error:
        print(f"获取标签失败: {error}")
        return []

3. 邮件智能分类原理

邮件分类是 email-management 的核心能力之一。它不依赖简单的关键词匹配,而是利用 LLM 的语义理解能力,结合邮件的多维度特征进行智能分类。

"""
邮件智能分类引擎
基于 LLM 语义理解 + 规则辅助的混合分类方案
"""

from openai import OpenAI
from typing import List, Dict, Optional
from dataclasses import dataclass
from enum import Enum
import json
import re


# ============ 分类体系定义 ============

class EmailCategory(Enum):
    """邮件分类枚举"""
    URGENT = "紧急"           # 需要立即处理
    IMPORTANT = "重要"        # 需要关注和处理
    NORMAL = "普通"           # 常规邮件
    FYI = "通知"              # 仅供参考,无需回复
    SOCIAL = "社交"           # 社交网络通知
    PROMOTION = "推广"        # 营销推广邮件
    FINANCE = "财务"          # 发票、账单等
    HR = "人事"               # HR 相关通知
    IT = "技术"               # IT 系统通知
    MEETING = "会议"          # 会议邀请和更新
    NEWSLETTER = "订阅"       # 邮件订阅/Newsletter
    SPAM = "垃圾"             # 垃圾邮件
    OTHER = "其他"            # 未分类


@dataclass
class ClassificationResult:
    """分类结果"""
    category: EmailCategory     # 主分类
    confidence: float           # 置信度 (0-1)
    priority: int               # 优先级 (1-5, 1最高)
    needs_reply: bool           # 是否需要回复
    summary: str                # 邮件摘要
    action_items: List[str]     # 需要执行的操作
    sub_labels: List[str]       # 子标签


class EmailClassifier:
    """
    邮件智能分类器

    分类策略:LLM 语义分类 + 规则辅助
    1. 先用快速规则过滤明显的类别(推广、社交、系统通知)
    2. 对不确定的邮件使用 LLM 进行语义分类
    3. 结合发件人历史行为和用户偏好调整分类

    这种混合策略既保证了速度,又保证了准确性
    """

    def __init__(
        self,
        api_key: str,
        model: str = "gpt-4o-mini",
        custom_categories: List[str] = None,
        user_preferences: Dict = None
    ):
        self.client = OpenAI(api_key=api_key)
        self.model = model
        self.custom_categories = custom_categories or []
        self.user_preferences = user_preferences or {}

        # 规则引擎:快速过滤明显类别
        self.rule_patterns = {
            EmailCategory.PROMOTION: [
                r'(?:退订|unsubscribe|取消订阅)',
                r'(?:优惠|折扣|discount|sale|促销)',
                r'(?:限时|limited.time|flash.sale)',
                r'(?:会员|VIP|exclusive)',
            ],
            EmailCategory.SOCIAL: [
                r'(?:关注了你|followed you)',
                r'(?:点赞了|liked your)',
                r'(?:评论了|commented on)',
                r'(?:LinkedIn|Twitter|Facebook|Instagram)',
            ],
            EmailCategory.FINANCE: [
                r'(?:发票|invoice|收据|receipt)',
                r'(?:账单|bill|payment|付款)',
                r'(?:报销|reimbursement)',
                r'(?:工资|salary|payroll)',
            ],
            EmailCategory.HR: [
                r'(?:入职|onboarding)',
                r'(?:考勤|attendance)',
                r'(?:请假|leave|vacation)',
                r'(?:培训|training)',
            ],
            EmailCategory.IT: [
                r'(?:监控告警|alert|monitoring)',
                r'(?:系统通知|system notification)',
                r'(?:安全提醒|security alert)',
                r'(?:CI/CD|pipeline|deploy)',
            ],
            EmailCategory.MEETING: [
                r'(?:会议邀请|meeting invitation)',
                r'(?:日程更新|calendar update)',
                r'(?:Zoom|Teams|腾讯会议)',
                r'(?:已接受|accepted|已拒绝|declined)',
            ],
        }

        # 重要发件人列表(从用户偏好中加载)
        self.important_senders = set(
            self.user_preferences.get('important_senders', [])
        )

        # 紧急关键词
        self.urgent_keywords = [
            '紧急', 'urgent', 'ASAP', '立即', 'immediately',
            '截止', 'deadline', '最后期限', 'critical',
            '宕机', 'down', '故障', 'outage'
        ]

    def classify(self, email_data: Dict) -> ClassificationResult:
        """
        对邮件进行分类

        分类流程:
        1. 规则快速过滤
        2. 发件人优先级判断
        3. LLM 语义分类(对不确定的邮件)
        4. 综合判断,输出最终分类
        """
        # 步骤1:规则快速过滤
        rule_result = self._rule_based_classify(email_data)
        if rule_result and rule_result.confidence > 0.85:
            # 规则匹配置信度高,直接返回
            return rule_result

        # 步骤2:发件人优先级判断
        sender = email_data.get('from', '')
        if sender in self.important_senders:
            priority_boost = 2  # 重要发件人优先级提升
        else:
            priority_boost = 0

        # 步骤3:LLM 语义分类
        llm_result = self._llm_classify(email_data)

        # 步骤4:综合判断
        if rule_result and llm_result:
            # 规则和LLM都有结果,取置信度更高的
            if rule_result.confidence > llm_result.confidence:
                final_result = rule_result
            else:
                final_result = llm_result
        elif llm_result:
            final_result = llm_result
        else:
            final_result = ClassificationResult(
                category=EmailCategory.OTHER,
                confidence=0.3,
                priority=3,
                needs_reply=False,
                summary="",
                action_items=[],
                sub_labels=[]
            )

        # 调整优先级
        final_result.priority = max(1, final_result.priority - priority_boost)

        return final_result

    def _rule_based_classify(self, email_data: Dict) -> Optional[ClassificationResult]:
        """基于规则的快速分类"""
        subject = email_data.get('subject', '')
        body = email_data.get('body', '')
        from_addr = email_data.get('from', '')
        combined_text = f"{subject} {body} {from_addr}"

        # 检查紧急程度
        is_urgent = any(
            kw in combined_text.lower()
            for kw in self.urgent_keywords
        )

        # 匹配规则模式
        best_match = None
        best_confidence = 0

        for category, patterns in self.rule_patterns.items():
            for pattern in patterns:
                if re.search(pattern, combined_text, re.IGNORECASE):
                    confidence = 0.8  # 规则匹配置信度
                    if confidence > best_confidence:
                        best_confidence = confidence
                        best_match = category

        if best_match:
            return ClassificationResult(
                category=best_match,
                confidence=best_confidence,
                priority=1 if is_urgent else 3,
                needs_reply=is_urgent or best_match in [
                    EmailCategory.URGENT,
                    EmailCategory.IMPORTANT,
                    EmailCategory.FINANCE
                ],
                summary=subject[:100],
                action_items=["需要处理"] if is_urgent else [],
                sub_labels=[]
            )

        # 紧急但无类别匹配
        if is_urgent:
            return ClassificationResult(
                category=EmailCategory.URGENT,
                confidence=0.7,
                priority=1,
                needs_reply=True,
                summary=subject[:100],
                action_items=["紧急处理"],
                sub_labels=[]
            )

        return None

    def _llm_classify(self, email_data: Dict) -> Optional[ClassificationResult]:
        """基于 LLM 的语义分类"""
        categories_str = ", ".join(
            [c.value for c in EmailCategory] + self.custom_categories
        )

        prompt = f"""你是一个专业的邮件分类助手。请对以下邮件进行分类。

可用的分类类别:{categories_str}

请分析邮件内容,返回以下信息:
1. category: 最合适的分类类别
2. confidence: 分类置信度 (0-1)
3. priority: 优先级 (1-5, 1最高)
4. needs_reply: 是否需要回复 (true/false)
5. summary: 邮件内容摘要(50字以内)
6. action_items: 需要执行的操作列表

邮件信息:
- 发件人: {email_data.get('from', '')}
- 收件人: {email_data.get('to', '')}
- 主题: {email_data.get('subject', '')}
- 日期: {email_data.get('date', '')}
- 正文: {email_data.get('body', '')[:2000]}

请以 JSON 格式返回结果。"""

        try:
            response = self.client.chat.completions.create(
                model=self.model,
                messages=[
                    {
                        "role": "system",
                        "content": "你是一个邮件分类助手,只返回JSON格式的分类结果。"
                    },
                    {"role": "user", "content": prompt}
                ],
                response_format={"type": "json_object"},
                temperature=0.1  # 低温度,保证分类稳定性
            )

            result = json.loads(response.choices[0].message.content)

            # 映射分类名称到枚举
            category_str = result.get('category', '其他')
            category = EmailCategory.OTHER
            for cat in EmailCategory:
                if cat.value == category_str:
                    category = cat
                    break

            return ClassificationResult(
                category=category,
                confidence=min(1.0, max(0.0, result.get('confidence', 0.5))),
                priority=min(5, max(1, result.get('priority', 3))),
                needs_reply=result.get('needs_reply', False),
                summary=result.get('summary', ''),
                action_items=result.get('action_items', []),
                sub_labels=result.get('sub_labels', [])
            )

        except Exception as e:
            print(f"LLM 分类失败: {e}")
            return None

    def batch_classify(
        self,
        emails: List[Dict],
        batch_size: int = 10
    ) -> List[ClassificationResult]:
        """批量分类邮件(提高效率)"""
        results = []

        # 先用规则快速过滤
        rule_classified = []
        llm_needed = []

        for email_data in emails:
            rule_result = self._rule_based_classify(email_data)
            if rule_result and rule_result.confidence > 0.85:
                rule_classified.append((email_data, rule_result))
            else:
                llm_needed.append(email_data)

        # 对需要 LLM 分类的邮件进行批量处理
        # 将多封邮件合并到一个 prompt 中,减少 API 调用次数
        for i in range(0, len(llm_needed), batch_size):
            batch = llm_needed[i:i + batch_size]
            batch_results = self._batch_llm_classify(batch)

            for j, email_data in enumerate(batch):
                if j < len(batch_results):
                    results.append(batch_results[j])
                else:
                    # LLM 分类失败,使用默认分类
                    results.append(ClassificationResult(
                        category=EmailCategory.OTHER,
                        confidence=0.3,
                        priority=3,
                        needs_reply=False,
                        summary="",
                        action_items=[],
                        sub_labels=[]
                    ))

        # 合并结果(保持原始顺序)
        all_results = {}
        for email_data, result in rule_classified:
            idx = emails.index(email_data)
            all_results[idx] = result

        for i, email_data in enumerate(llm_needed):
            idx = emails.index(email_data)
            if i < len(results):
                all_results[idx] = results[i]

        return [all_results[i] for i in range(len(emails))]

    def _batch_llm_classify(
        self,
        emails: List[Dict]
    ) -> List[ClassificationResult]:
        """批量 LLM 分类(将多封邮件合并到一个请求中)"""
        categories_str = ", ".join(
            [c.value for c in EmailCategory] + self.custom_categories
        )

        # 构建批量分类 prompt
        email_descriptions = []
        for i, email_data in enumerate(emails):
            email_descriptions.append(
                f"邮件{i+1}:\n"
                f"- 发件人: {email_data.get('from', '')}\n"
                f"- 主题: {email_data.get('subject', '')}\n"
                f"- 正文: {email_data.get('body', '')[:500]}\n"
            )

        prompt = f"""请对以下{len(emails)}封邮件进行分类。

可用分类:{categories_str}

{''.join(email_descriptions)}

请以 JSON 格式返回结果,格式为:
{{
  "results": [
    {{
      "category": "分类名",
      "confidence": 0.8,
      "priority": 3,
      "needs_reply": true,
      "summary": "摘要",
      "action_items": ["操作1"]
    }}
  ]
}}"""

        try:
            response = self.client.chat.completions.create(
                model=self.model,
                messages=[
                    {
                        "role": "system",
                        "content": "你是邮件分类助手,只返回JSON格式结果。"
                    },
                    {"role": "user", "content": prompt}
                ],
                response_format={"type": "json_object"},
                temperature=0.1
            )

            result = json.loads(response.choices[0].message.content)
            batch_results = []

            for item in result.get('results', []):
                category_str = item.get('category', '其他')
                category = EmailCategory.OTHER
                for cat in EmailCategory:
                    if cat.value == category_str:
                        category = cat
                        break

                batch_results.append(ClassificationResult(
                    category=category,
                    confidence=min(1.0, max(0.0, item.get('confidence', 0.5))),
                    priority=min(5, max(1, item.get('priority', 3))),
                    needs_reply=item.get('needs_reply', False),
                    summary=item.get('summary', ''),
                    action_items=item.get('action_items', []),
                    sub_labels=item.get('sub_labels', [])
                ))

            return batch_results

        except Exception as e:
            print(f"批量 LLM 分类失败: {e}")
            return []

4. 智能回复生成原理

智能回复是 email-management 最实用的功能之一。它不是简单的模板填充,而是基于邮件上下文、对话历史和用户风格生成的个性化回复。

"""
智能回复生成引擎
基于 LLM 的上下文感知回复生成
"""

from openai import OpenAI
from typing import List, Dict, Optional
from dataclasses import dataclass
import json


@dataclass
class ReplyDraft:
    """回复草稿"""
    subject: str                # 回复主题
    body: str                   # 回复正文
    tone: str                   # 语气风格
    confidence: float           # 生成置信度
    alternatives: List[str]     # 备选回复
    suggested_attachments: List[str]  # 建议添加的附件


class SmartReplyEngine:
    """
    智能回复引擎

    回复生成策略:
    1. 分析原始邮件的意图和情感
    2. 检索相关上下文(对话历史、相关文档)
    3. 根据用户风格偏好生成回复
    4. 提供多个备选方案供用户选择
    5. 自动检查回复的完整性和适当性
    """

    def __init__(
        self,
        api_key: str,
        model: str = "gpt-4o",
        user_profile: Dict = None,
        style_examples: List[str] = None
    ):
        self.client = OpenAI(api_key=api_key)
        self.model = model
        self.user_profile = user_profile or {}
        self.style_examples = style_examples or []

    def generate_reply(
        self,
        email_data: Dict,
        thread_history: List[Dict] = None,
        context_documents: List[str] = None,
        tone: str = "professional",
        language: str = "zh"
    ) -> ReplyDraft:
        """
        生成智能回复

        参数说明:
        - email_data: 原始邮件数据
        - thread_history: 同一会话的历史邮件
        - context_documents: 相关上下文文档(如产品文档、FAQ等)
        - tone: 语气风格 (professional/casual/friendly/formal)
        - language: 回复语言 (zh/en)
        """
        # 步骤1:构建回复 prompt
        system_prompt = self._build_system_prompt(tone, language)
        user_prompt = self._build_user_prompt(
            email_data, thread_history, context_documents
        )

        # 步骤2:调用 LLM 生成回复
        response = self.client.chat.completions.create(
            model=self.model,
            messages=[
                {"role": "system", "content": system_prompt},
                {"role": "user", "content": user_prompt}
            ],
            temperature=0.7,  # 适中的创造性
            max_tokens=1500
        )

        # 步骤3:解析回复
        reply_content = response.choices[0].message.content

        # 步骤4:生成备选方案
        alternatives = self._generate_alternatives(
            email_data, tone, language, count=2
        )

        # 步骤5:构建回复草稿
        subject = f"Re: {email_data.get('subject', '')}"
        if subject.startswith("Re: Re:"):
            subject = subject.replace("Re: Re:", "Re:", 1)

        return ReplyDraft(
            subject=subject,
            body=reply_content,
            tone=tone,
            confidence=0.85,
            alternatives=alternatives,
            suggested_attachments=self._suggest_attachments(email_data)
        )

    def _build_system_prompt(self, tone: str, language: str) -> str:
        """构建系统 prompt"""
        tone_instructions = {
            "professional": "专业、简洁、有条理,使用正式的商务用语",
            "casual": "轻松、自然、友好,像同事间的日常沟通",
            "friendly": "热情、亲切、有温度,让收件人感到被重视",
            "formal": "正式、严谨、规范,适用于对外商务沟通",
        }

        tone_desc = tone_instructions.get(tone, tone_instructions["professional"])

        # 用户画像信息
        user_name = self.user_profile.get('name', '')
        user_title = self.user_profile.get('title', '')
        user_company = self.user_profile.get('company', '')

        system_prompt = f"""你是一个专业的邮件回复助手。请根据以下要求生成邮件回复:

语气风格:{tone_desc}
回复语言:{"中文" if language == "zh" else "English"}

回复要求:
1. 直接回复核心问题,不要废话
2. 如果原始邮件有多个问题,逐一回复
3. 语气要与原始邮件的正式程度匹配
4. 如果不确定某些信息,明确指出并建议确认
5. 回复要有明确的行动项或下一步计划
6. 不要使用过于模板化的语言,要自然流畅"""

        if user_name:
            system_prompt += f"\n\n发件人信息:{user_name}"
        if user_title:
            system_prompt += f",{user_title}"
        if user_company:
            system_prompt += f",{user_company}"

        # 添加用户风格示例(few-shot learning)
        if self.style_examples:
            system_prompt += "\n\n参考该用户的写作风格:\n"
            for example in self.style_examples[:3]:
                system_prompt += f"---\n{example}\n---\n"

        return system_prompt

    def _build_user_prompt(
        self,
        email_data: Dict,
        thread_history: List[Dict] = None,
        context_documents: List[str] = None
    ) -> str:
        """构建用户 prompt"""
        prompt_parts = []

        # 原始邮件信息
        prompt_parts.append(f"=== 需要回复的邮件 ===")
        prompt_parts.append(f"发件人: {email_data.get('from', '')}")
        prompt_parts.append(f"主题: {email_data.get('subject', '')}")
        prompt_parts.append(f"日期: {email_data.get('date', '')}")
        prompt_parts.append(f"正文:\n{email_data.get('body', '')}")

        # 对话历史
        if thread_history:
            prompt_parts.append(f"\n=== 对话历史 ===")
            for hist_email in thread_history[-5:]:  # 最近5封
                prompt_parts.append(
                    f"[{hist_email.get('date', '')}] "
                    f"{hist_email.get('from', '')}: "
                    f"{hist_email.get('body', '')[:300]}"
                )

        # 上下文文档
        if context_documents:
            prompt_parts.append(f"\n=== 相关参考资料 ===")
            for doc in context_documents[:3]:
                prompt_parts.append(doc[:500])

        prompt_parts.append("\n请生成回复。")

        return "\n".join(prompt_parts)

    def _generate_alternatives(
        self,
        email_data: Dict,
        tone: str,
        language: str,
        count: int = 2
    ) -> List[str]:
        """生成备选回复方案"""
        alternatives = []

        tones = ["professional", "casual", "friendly", "formal"]
        # 选择与主回复不同的语气
        alt_tones = [t for t in tones if t != tone][:count]

        for alt_tone in alt_tones:
            system_prompt = self._build_system_prompt(alt_tone, language)
            user_prompt = (
                f"请用更{alt_tone}的语气回复以下邮件:\n"
                f"发件人: {email_data.get('from', '')}\n"
                f"主题: {email_data.get('subject', '')}\n"
                f"正文: {email_data.get('body', '')[:1000]}\n"
                f"请直接给出回复内容,不要解释。"
            )

            try:
                response = self.client.chat.completions.create(
                    model=self.model,
                    messages=[
                        {"role": "system", "content": system_prompt},
                        {"role": "user", "content": user_prompt}
                    ],
                    temperature=0.8,
                    max_tokens=800
                )
                alternatives.append(response.choices[0].message.content)
            except Exception as e:
                print(f"生成备选回复失败: {e}")

        return alternatives

    def _suggest_attachments(self, email_data: Dict) -> List[str]:
        """根据邮件内容建议可能需要的附件"""
        suggestions = []
        body = email_data.get('body', '').lower()
        subject = email_data.get('subject', '').lower()
        combined = f"{subject} {body}"

        # 基于关键词建议附件
        attachment_rules = {
            '报价': ['报价单', '价格表'],
            '合同': ['合同模板', 'NDA'],
            '简历': ['个人简历', '作品集'],
            '报告': ['周报模板', '月报模板'],
            '方案': ['方案文档', '技术规格书'],
            'invoice': ['Invoice Template', 'Payment Details'],
            'proposal': ['Proposal Template', 'Case Studies'],
            'meeting': ['会议议程', '会议纪要模板'],
        }

        for keyword, attachments in attachment_rules.items():
            if keyword in combined:
                suggestions.extend(attachments)

        return list(set(suggestions))  # 去重

    def generate_bulk_replies(
        self,
        emails: List[Dict],
        tone: str = "professional",
        language: str = "zh"
    ) -> List[ReplyDraft]:
        """批量生成回复(用于相似邮件的批量处理)"""
        drafts = []

        # 先对邮件进行聚类,找出相似的邮件
        clusters = self._cluster_similar_emails(emails)

        for cluster in clusters:
            if len(cluster) == 1:
                # 单独邮件,单独生成回复
                draft = self.generate_reply(
                    cluster[0], tone=tone, language=language
                )
                drafts.append(draft)
            else:
                # 相似邮件,生成一个模板回复,然后个性化调整
                template_draft = self.generate_reply(
                    cluster[0], tone=tone, language=language
                )
                for email_data in cluster:
                    # 基于模板微调
                    personalized = self._personalize_reply(
                        template_draft, email_data
                    )
                    drafts.append(personalized)

        return drafts

    def _cluster_similar_emails(
        self,
        emails: List[Dict],
        similarity_threshold: float = 0.8
    ) -> List[List[Dict]]:
        """将相似邮件聚类(用于批量回复)"""
        # 简单实现:基于主题相似度聚类
        clusters = []
        used = set()

        for i, email_a in enumerate(emails):
            if i in used:
                continue

            cluster = [email_a]
            used.add(i)

            for j, email_b in enumerate(emails):
                if j in used or j == i:
                    continue

                # 简单的主题相似度判断
                subject_a = email_a.get('subject', '').lower()
                subject_b = email_b.get('subject', '').lower()

                # 计算词重叠率
                words_a = set(subject_a.split())
                words_b = set(subject_b.split())
                if words_a and words_b:
                    overlap = len(words_a & words_b) / len(words_a | words_b)
                    if overlap >= similarity_threshold:
                        cluster.append(email_b)
                        used.add(j)

            clusters.append(cluster)

        return clusters

    def _personalize_reply(
        self,
        template: ReplyDraft,
        email_data: Dict
    ) -> ReplyDraft:
        """基于模板个性化回复"""
        # 替换模板中的占位符
        body = template.body
        body = body.replace("{sender_name}", email_data.get('from', '').split('<')[0].strip())
        body = body.replace("{subject}", email_data.get('subject', ''))

        return ReplyDraft(
            subject=f"Re: {email_data.get('subject', '')}",
            body=body,
            tone=template.tone,
            confidence=template.confidence * 0.9,  # 模板微调置信度略低
            alternatives=template.alternatives,
            suggested_attachments=template.suggested_attachments
        )

5. 定时发送与调度引擎

"""
邮件调度引擎
支持定时发送、周期发送、条件触发发送
"""

import schedule
import time
import threading
from datetime import datetime, timedelta
from typing import Callable, List, Dict, Optional
from dataclasses import dataclass
from enum import Enum
import json
import os


class ScheduleType(Enum):
    """调度类型"""
    ONCE = "once"           # 一次性的定时发送
    RECURRING = "recurring"  # 周期性发送
    CONDITIONAL = "conditional"  # 条件触发发送


@dataclass
class ScheduledEmail:
    """定时邮件"""
    id: str
    schedule_type: ScheduleType
    to: str
    subject: str
    body: str
    send_at: datetime           # 发送时间
    recurrence: Optional[str]   # 周期规则(如 "daily", "weekly")
    condition: Optional[str]    # 触发条件
    status: str = "pending"     # pending / sent / failed / cancelled
    created_at: datetime = None
    sent_at: datetime = None
    error: str = None


class EmailScheduler:
    """
    邮件调度引擎

    支持的调度类型:
    1. 定时发送:在指定时间发送邮件
    2. 周期发送:按固定周期发送邮件(如每周一早上9点)
    3. 条件触发:满足条件时发送邮件(如收到某类邮件时自动回复)

    调度引擎使用后台线程运行,不阻塞主程序
    """

    def __init__(self, send_func: Callable, storage_path: str = "./scheduled_emails.json"):
        self.send_func = send_func  # 实际发送邮件的函数
        self.storage_path = storage_path
        self.scheduled_emails: Dict[str, ScheduledEmail] = {}
        self._running = False
        self._thread = None

        # 加载已保存的定时邮件
        self._load_scheduled_emails()

    def schedule_email(
        self,
        to: str,
        subject: str,
        body: str,
        send_at: datetime = None,
        delay_minutes: int = None,
        recurrence: str = None,
        condition: str = None
    ) -> str:
        """
        创建定时邮件

        使用示例:
        # 1小时后发送
        scheduler.schedule_email(
            to="client@example.com",
            subject="项目进度更新",
            body="...",
            delay_minutes=60
        )

        # 明天早上9点发送
        scheduler.schedule_email(
            to="client@example.com",
            subject="会议纪要",
            body="...",
            send_at=datetime(2025, 5, 16, 9, 0)
        )

        # 每周一早上9点发送周报
        scheduler.schedule_email(
            to="team@company.com",
            subject="周报",
            body="...",
            send_at=datetime(2025, 5, 19, 9, 0),
            recurrence="weekly"
        )
        """
        # 计算发送时间
        if send_at is None and delay_minutes is not None:
            send_at = datetime.now() + timedelta(minutes=delay_minutes)
        elif send_at is None:
            send_at = datetime.now()

        # 确定调度类型
        if condition:
            schedule_type = ScheduleType.CONDITIONAL
        elif recurrence:
            schedule_type = ScheduleType.RECURRING
        else:
            schedule_type = ScheduleType.ONCE

        # 生成唯一 ID
        email_id = f"sched_{int(time.time() * 1000)}"

        scheduled = ScheduledEmail(
            id=email_id,
            schedule_type=schedule_type,
            to=to,
            subject=subject,
            body=body,
            send_at=send_at,
            recurrence=recurrence,
            condition=condition,
            status="pending",
            created_at=datetime.now()
        )

        self.scheduled_emails[email_id] = scheduled
        self._save_scheduled_emails()

        return email_id

    def cancel_scheduled_email(self, email_id: str) -> bool:
        """取消定时邮件"""
        if email_id in self.scheduled_emails:
            self.scheduled_emails[email_id].status = "cancelled"
            self._save_scheduled_emails()
            return True
        return False

    def start(self):
        """启动调度引擎(后台线程)"""
        if self._running:
            return

        self._running = True
        self._thread = threading.Thread(target=self._run_loop, daemon=True)
        self._thread.start()

    def stop(self):
        """停止调度引擎"""
        self._running = False
        if self._thread:
            self._thread.join(timeout=5)

    def _run_loop(self):
        """调度主循环"""
        while self._running:
            now = datetime.now()

            for email_id, scheduled in list(self.scheduled_emails.items()):
                if scheduled.status != "pending":
                    continue

                # 检查是否到达发送时间
                if scheduled.send_at <= now:
                    try:
                        # 执行发送
                        self.send_func(
                            to=scheduled.to,
                            subject=scheduled.subject,
                            body=scheduled.body
                        )
                        scheduled.status = "sent"
                        scheduled.sent_at = now

                        # 如果是周期性邮件,安排下一次发送
                        if scheduled.schedule_type == ScheduleType.RECURRING:
                            next_send = self._calculate_next_occurrence(
                                scheduled.send_at, scheduled.recurrence
                            )
                            if next_send:
                                # 创建下一次的定时邮件
                                self.schedule_email(
                                    to=scheduled.to,
                                    subject=scheduled.subject,
                                    body=scheduled.body,
                                    send_at=next_send,
                                    recurrence=scheduled.recurrence
                                )

                    except Exception as e:
                        scheduled.status = "failed"
                        scheduled.error = str(e)

                    self._save_scheduled_emails()

            # 每30秒检查一次
            time.sleep(30)

    def _calculate_next_occurrence(
        self,
        current: datetime,
        recurrence: str
    ) -> Optional[datetime]:
        """计算下一次发送时间"""
        recurrence_map = {
            "daily": timedelta(days=1),
            "weekly": timedelta(weeks=1),
            "biweekly": timedelta(weeks=2),
            "monthly": timedelta(days=30),  # 近似
            "quarterly": timedelta(days=90),  # 近似
        }

        delta = recurrence_map.get(recurrence)
        if delta:
            return current + delta
        return None

    def _save_scheduled_emails(self):
        """保存定时邮件到文件"""
        data = {}
        for email_id, scheduled in self.scheduled_emails.items():
            data[email_id] = {
                "id": scheduled.id,
                "schedule_type": scheduled.schedule_type.value,
                "to": scheduled.to,
                "subject": scheduled.subject,
                "body": scheduled.body,
                "send_at": scheduled.send_at.isoformat(),
                "recurrence": scheduled.recurrence,
                "condition": scheduled.condition,
                "status": scheduled.status,
                "created_at": scheduled.created_at.isoformat() if scheduled.created_at else None,
                "sent_at": scheduled.sent_at.isoformat() if scheduled.sent_at else None,
                "error": scheduled.error,
            }

        with open(self.storage_path, 'w', encoding='utf-8') as f:
            json.dump(data, f, ensure_ascii=False, indent=2)

    def _load_scheduled_emails(self):
        """从文件加载定时邮件"""
        if not os.path.exists(self.storage_path):
            return

        try:
            with open(self.storage_path, 'r', encoding='utf-8') as f:
                data = json.load(f)

            for email_id, item in data.items():
                self.scheduled_emails[email_id] = ScheduledEmail(
                    id=item['id'],
                    schedule_type=ScheduleType(item['schedule_type']),
                    to=item['to'],
                    subject=item['subject'],
                    body=item['body'],
                    send_at=datetime.fromisoformat(item['send_at']),
                    recurrence=item.get('recurrence'),
                    condition=item.get('condition'),
                    status=item['status'],
                    created_at=datetime.fromisoformat(item['created_at']) if item.get('created_at') else None,
                    sent_at=datetime.fromisoformat(item['sent_at']) if item.get('sent_at') else None,
                    error=item.get('error'),
                )
        except Exception as e:
            print(f"加载定时邮件失败: {e}")

📥 安装与使用 | Installation & Usage

安装方式

方式一:NPM 安装(Node.js)
# 安装 email-management skill
npm install @ai-skills/email-management

# 安装 Google API 依赖
npm install googleapis

# 安装 IMAP/SMTP 依赖
npm install imapflow nodemailer
方式二:PyPI 安装(Python)
# 安装 email-management skill
pip install ai-email-management

# 安装 Google API 依赖
pip install google-auth-oauthlib google-api-python-client

# 安装 IMAP/SMTP 依赖
pip install imapclient beautifulsoup4
方式三:从源码安装
# 克隆仓库
git clone https://github.com/ai-agent-skills/email-management.git
cd email-management

# 安装依赖
pip install -e .

# 或者使用 npm
npm install
npm run build
npm link

Gmail OAuth2.0 配置

Gmail API 需要配置 OAuth2.0 认证,以下是完整的配置步骤:

步骤1:创建 Google Cloud 项目
├── 访问 https://console.cloud.google.com/
├── 点击 "创建项目"
├── 输入项目名称(如 "email-management-agent")
└── 点击 "创建"

步骤2:启用 Gmail API
├── 在项目中,进入 "API 和服务" > "库"
├── 搜索 "Gmail API"
├── 点击进入,点击 "启用"
└── 等待 API 启用完成

步骤3:创建 OAuth2.0 凭证
├── 进入 "API 和服务" > "凭证"
├── 点击 "创建凭证" > "OAuth 客户端 ID"
├── 应用类型选择 "桌面应用"
├── 输入名称(如 "email-management-client")
├── 点击 "创建"
└── 下载 credentials.json 文件

步骤4:配置 OAuth 同意屏幕
├── 进入 "API 和服务" > "OAuth 同意屏幕"
├── 选择 "外部"(如果是个人账号)
├── 填写应用信息
├── 添加范围:
│   ├── .../auth/gmail.readonly
│   ├── .../auth/gmail.send
│   ├── .../auth/gmail.compose
│   ├── .../auth/gmail.modify
│   └── .../auth/gmail.labels
├── 添加测试用户(你的 Gmail 地址)
└── 发布应用(或保持测试模式)

步骤5:首次运行认证
├── 将 credentials.json 放到项目根目录
├── 运行程序,会自动打开浏览器
├── 登录 Google 账号并授权
├── 授权完成后 token.json 会自动保存
└── 后续运行无需再次授权

使用示例

示例1:读取未读邮件并分类
# 场景:每天早上自动读取未读邮件并分类

from email_management import EmailManager, EmailClassifier

# 初始化邮件管理器(Gmail)
manager = EmailManager(
    provider="gmail",
    credentials_file="credentials.json"
)

# 初始化分类器
classifier = EmailClassifier(
    api_key="sk-your-openai-api-key",
    model="gpt-4o-mini"
)

# 读取未读邮件
unread_emails = manager.get_unread_emails(limit=20)

print(f"📬 共有 {len(unread_emails)} 封未读邮件\n")

# 逐封分类
for email_data in unread_emails:
    result = classifier.classify(email_data)

    print(f"📧 主题: {email_data['subject']}")
    print(f"   发件人: {email_data['from']}")
    print(f"   分类: {result.category.value} (置信度: {result.confidence:.0%})")
    print(f"   优先级: {'⭐' * result.priority}")
    print(f"   需要回复: {'是' if result.needs_reply else '否'}")
    print(f"   摘要: {result.summary}")
    if result.action_items:
        print(f"   待办: {', '.join(result.action_items)}")
    print()

    # 自动应用 Gmail 标签
    label_map = {
        "紧急": "URGENT",
        "重要": "IMPORTANT",
        "财务": "Finance",
        "会议": "Meetings",
    }
    label = label_map.get(result.category.value)
    if label:
        manager.add_label(email_data['id'], label)
示例2:智能回复客户邮件
# 场景:自动生成客户咨询的回复草稿

from email_management import EmailManager, SmartReplyEngine

# 初始化
manager = EmailManager(provider="gmail", credentials_file="credentials.json")

reply_engine = SmartReplyEngine(
    api_key="sk-your-openai-api-key",
    model="gpt-4o",
    user_profile={
        "name": "张三",
        "title": "客户经理",
        "company": "ABC科技有限公司"
    }
)

# 获取需要回复的客户邮件
customer_emails = manager.search_emails(
    query="from:customer@example.com is:unread"
)

for email_data in customer_emails:
    # 获取对话历史
    thread = manager.get_thread(email_data['thread_id'])

    # 生成回复草稿
    draft = reply_engine.generate_reply(
        email_data=email_data,
        thread_history=thread,
        tone="professional",
        language="zh"
    )

    print(f"📧 回复: {email_data['subject']}")
    print(f"📝 草稿:\n{draft.body}\n")
    print(f"📎 建议附件: {', '.join(draft.suggested_attachments)}")
    print(f"🔄 备选方案:")
    for i, alt in enumerate(draft.alternatives, 1):
        print(f"   方案{i}: {alt[:100]}...")

    # 保存为草稿(不直接发送,需要人工确认)
    manager.save_draft(
        to=email_data['from'],
        subject=draft.subject,
        body=draft.body,
        thread_id=email_data['thread_id']
    )
    print("✅ 已保存为草稿\n")
示例3:批量处理邮件
# 场景:批量归档通知邮件、删除垃圾邮件

from email_management import EmailManager, EmailClassifier

manager = EmailManager(provider="gmail", credentials_file="credentials.json")
classifier = EmailClassifier(api_key="sk-your-openai-api-key")

# 获取最近7天的邮件
recent_emails = manager.get_emails_since(days=7)

# 批量分类
results = classifier.batch_classify(recent_emails)

# 统计分类结果
stats = {}
for email_data, result in zip(recent_emails, results):
    cat = result.category.value
    stats[cat] = stats.get(cat, 0) + 1

print("📊 邮件分类统计:")
for cat, count in sorted(stats.items(), key=lambda x: -x[1]):
    print(f"  {cat}: {count} 封")

# 批量处理
archived_count = 0
deleted_count = 0

for email_data, result in zip(recent_emails, results):
    # 归档通知和推广邮件
    if result.category.value in ["通知", "推广", "订阅"]:
        manager.archive_email(email_data['id'])
        archived_count += 1

    # 删除垃圾邮件
    elif result.category.value == "垃圾":
        manager.delete_email(email_data['id'])
        deleted_count += 1

    # 标记重要邮件
    elif result.priority <= 2:
        manager.mark_important(email_data['id'])
        manager.add_star(email_data['id'])

print(f"\n✅ 处理完成:")
print(f"  归档: {archived_count} 封")
print(f"  删除: {deleted_count} 封")
print(f"  标记重要: {sum(1 for r in results if r.priority <= 2)} 封")
示例4:定时发送邮件
# 场景:跨时区定时发送邮件

from email_management import EmailManager, EmailScheduler
from datetime import datetime, timedelta

manager = EmailManager(provider="gmail", credentials_file="credentials.json")

# 创建调度器
scheduler = EmailScheduler(
    send_func=manager.send_email,
    storage_path="./my_scheduled_emails.json"
)

# 启动调度引擎
scheduler.start()

# 示例1:1小时后发送邮件
email_id_1 = scheduler.schedule_email(
    to="client@example.com",
    subject="项目进度更新",
    body="""
    <h2>项目进度更新</h2>
    <p>Hi 客户,</p>
    <p>以下是本周的项目进度:</p>
    <ul>
        <li>前端开发完成 80%</li>
        <li>后端 API 开发完成 90%</li>
        <li>测试用例编写完成 60%</li>
    </ul>
    <p>预计下周可以进入集成测试阶段。</p>
    <p>Best regards,<br>张三</p>
    """,
    delay_minutes=60
)
print(f"✅ 已安排1小时后发送,ID: {email_id_1}")

# 示例2:明天早上9点(美国东部时间)发送
# 计算对应的中国时间
us_morning = datetime(2025, 5, 19, 9, 0)  # 美东时间
cn_time = us_morning + timedelta(hours=12)  # 大约对应中国时间

email_id_2 = scheduler.schedule_email(
    to="us-client@company.com",
    subject="Follow-up on our meeting",
    body="""
    <p>Hi Team,</p>
    <p>Following up on our discussion yesterday...</p>
    <p>Best regards</p>
    """,
    send_at=cn_time
)
print(f"✅ 已安排定时发送,ID: {email_id_2}")

# 示例3:每周一早上9点发送周报
email_id_3 = scheduler.schedule_email(
    to="team@company.com",
    subject="本周周报",
    body="""
    <h2>周报模板</h2>
    <p>各位好,</p>
    <p>以下是本周的工作总结:</p>
    <h3>本周完成</h3>
    <ul><li>...</li></ul>
    <h3>下周计划</h3>
    <ul><li>...</li></ul>
    """,
    send_at=datetime(2025, 5, 19, 9, 0),
    recurrence="weekly"
)
print(f"✅ 已安排每周发送,ID: {email_id_3}")

# 查看所有定时邮件
print("\n📋 当前定时邮件:")
for eid, scheduled in scheduler.scheduled_emails.items():
    print(f"  {eid}: {scheduled.subject} -> {scheduled.to} @ {scheduled.send_at} [{scheduled.status}]")
示例5:Outlook 邮箱集成
# 场景:使用 Microsoft Graph API 操作 Outlook 邮箱

from email_management import EmailManager

# Outlook 配置
manager = EmailManager(
    provider="outlook",
    client_id="your-azure-app-client-id",
    client_secret="your-azure-app-client-secret",
    tenant_id="your-tenant-id",
    redirect_uri="http://localhost:8000/callback"
)

# 读取收件箱
emails = manager.get_emails(folder="inbox", limit=10)

for email_data in emails:
    print(f"📧 {email_data['subject']}")
    print(f"   From: {email_data['from']}")
    print(f"   Date: {email_data['date']}")

# 发送邮件
manager.send_email(
    to="colleague@company.com",
    subject="会议确认",
    body="""
    <p>Hi,</p>
    <p>确认明天下午2点的会议安排。</p>
    <p>会议室:3F-A01</p>
    <p>议题:Q3项目规划</p>
    <p>谢谢!</p>
    """,
    cc="manager@company.com"
)

# 创建日历事件(Outlook 特有功能)
manager.create_calendar_event(
    subject="Q3项目规划会议",
    start_time="2025-05-20T14:00:00",
    end_time="2025-05-20T15:00:00",
    attendees=["colleague@company.com"],
    location="3F-A01"
)
示例6:与 LangChain Agent 集成
# 场景:将 email-management 集成到 LangChain Agent 中

from langchain.agents import AgentExecutor, create_openai_tools_agent
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from email_management import EmailManager, EmailClassifier, SmartReplyEngine

# 初始化邮件管理组件
manager = EmailManager(provider="gmail", credentials_file="credentials.json")
classifier = EmailClassifier(api_key="sk-your-key")
reply_engine = SmartReplyEngine(api_key="sk-your-key")

# 定义 LangChain 工具
from langchain_core.tools import tool

@tool
def read_unread_emails(limit: int = 10) -> str:
    """读取未读邮件。参数 limit 为读取数量,默认10。"""
    emails = manager.get_unread_emails(limit=limit)
    result = []
    for e in emails:
        result.append(
            f"主题: {e['subject']}\n"
            f"发件人: {e['from']}\n"
            f"摘要: {e.get('snippet', '')[:100]}\n"
            f"ID: {e['id']}"
        )
    return "\n---\n".join(result) if result else "没有未读邮件"

@tool
def classify_email(email_id: str) -> str:
    """对指定邮件进行智能分类。参数 email_id 为邮件ID。"""
    email_data = manager.get_email(email_id)
    result = classifier.classify(email_data)
    return (
        f"分类: {result.category.value}\n"
        f"优先级: {result.priority}\n"
        f"需要回复: {'是' if result.needs_reply else '否'}\n"
        f"摘要: {result.summary}"
    )

@tool
def generate_reply(email_id: str, tone: str = "professional") -> str:
    """为指定邮件生成智能回复草稿。参数 email_id 为邮件ID,tone 为语气风格。"""
    email_data = manager.get_email(email_id)
    draft = reply_engine.generate_reply(email_data, tone=tone)
    return (
        f"回复主题: {draft.subject}\n"
        f"回复内容:\n{draft.body}\n"
        f"建议附件: {', '.join(draft.suggested_attachments) or '无'}"
    )

@tool
def send_email(to: str, subject: str, body: str) -> str:
    """发送邮件。参数 to 为收件人,subject 为主题,body 为正文。"""
    result = manager.send_email(to=to, subject=subject, body=body)
    return f"邮件已发送,ID: {result}"

@tool
def search_emails(query: str, limit: int = 5) -> str:
    """搜索邮件。参数 query 为搜索条件,limit 为返回数量。"""
    emails = manager.search_emails(query=query, limit=limit)
    result = []
    for e in emails:
        result.append(f"主题: {e['subject']}\n发件人: {e['from']}\nID: {e['id']}")
    return "\n---\n".join(result) if result else "未找到匹配的邮件"

# 创建 Agent
tools = [read_unread_emails, classify_email, generate_reply, send_email, search_emails]

llm = ChatOpenAI(model="gpt-4o", temperature=0)

prompt = ChatPromptTemplate.from_messages([
    ("system", """你是一个邮件管理助手。你可以帮助用户:
1. 读取和搜索邮件
2. 智能分类邮件
3. 生成回复草稿
4. 发送邮件

请根据用户的需求使用合适的工具。"""),
    MessagesPlaceholder("chat_history", optional=True),
    ("human", "{input}"),
    MessagesPlaceholder("agent_scratchpad"),
])

agent = create_openai_tools_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

# 使用 Agent
result = agent_executor.invoke({
    "input": "帮我看看今天的未读邮件,哪些需要紧急处理?"
})
print(result["output"])

result = agent_executor.invoke({
    "input": "帮我回复客户关于产品价格的邮件,语气要专业"
})
print(result["output"])

⚙️ 高级配置 | Advanced Configuration

完整配置文件

# email-management 配置文件
# 文件路径: ~/.email-management/config.yaml

# ============ 邮箱连接配置 ============
email:
  # 默认邮箱提供商
  provider: gmail  # gmail / outlook / smtp

  # Gmail 配置
  gmail:
    credentials_file: ~/.email-management/credentials.json
    token_file: ~/.email-management/token.json
    # API 调用频率限制(避免触发 Google 限额)
    rate_limit:
      requests_per_second: 5
      requests_per_day: 1000000

  # Outlook 配置
  outlook:
    client_id: your-azure-app-client-id
    client_secret: your-azure-app-client-secret
    tenant_id: your-tenant-id
    redirect_uri: http://localhost:8000/callback

  # 通用 SMTP/IMAP 配置
  smtp:
    host: smtp.gmail.com
    port: 465
    use_ssl: true
    username: your-email@gmail.com
    password: your-app-password  # 建议使用环境变量

  imap:
    host: imap.gmail.com
    port: 993
    use_ssl: true
    username: your-email@gmail.com
    password: your-app-password

# ============ LLM 配置 ============
llm:
  # 分类模型(使用便宜快速的模型)
  classification:
    provider: openai
    model: gpt-4o-mini
    temperature: 0.1
    max_tokens: 500

  # 回复生成模型(使用更强大的模型)
  reply_generation:
    provider: openai
    model: gpt-4o
    temperature: 0.7
    max_tokens: 1500

  # 本地模型(隐私敏感场景)
  local:
    provider: ollama
    model: llama3
    base_url: http://localhost:11434

# ============ 分类配置 ============
classification:
  # 启用的分类类别
  categories:
    - 紧急
    - 重要
    - 普通
    - 通知
    - 财务
    - 会议
    - 推广
    - 垃圾

  # 自定义分类规则
  custom_rules:
    - name: "客户邮件"
      pattern: "from:*.client.com"
      category: "重要"
      priority: 2

    - name: "系统告警"
      pattern: "subject:*[ALERT]*"
      category: "紧急"
      priority: 1

  # 分类策略
  strategy: hybrid  # rule_first / llm_only / hybrid
  # rule_first: 先用规则,规则不确定再用LLM
  # llm_only: 完全依赖LLM
  # hybrid: 规则+LLM并行,取置信度高的

  # 置信度阈值
  confidence_threshold: 0.7

# ============ 回复配置 ============
reply:
  # 默认语气
  default_tone: professional

  # 是否自动发送(false=保存草稿,true=直接发送)
  auto_send: false

  # 回复前是否需要人工确认
  require_confirmation: true

  # 用户风格学习
  style_learning:
    enabled: true
    # 从已发送邮件中学习风格
    learn_from_sent: true
    # 学习的邮件数量
    sample_size: 50

  # 回复模板
  templates:
    - name: "收到确认"
      trigger: "邮件只需要确认收到"
      template: |
        Hi {sender_name},

        收到,谢谢!

        {signature}

    - name: "需要更多信息"
      trigger: "邮件信息不完整,需要补充"
      template: |
        Hi {sender_name},

        感谢你的邮件。关于{subject},我需要以下补充信息:
        - {missing_info_1}
        - {missing_info_2}

        请提供后我会尽快处理。

        {signature}

# ============ 调度配置 ============
scheduler:
  # 是否启用调度引擎
  enabled: true

  # 存储路径
  storage_path: ~/.email-management/scheduled_emails.json

  # 检查间隔(秒)
  check_interval: 30

  # 最大重试次数
  max_retries: 3

  # 重试间隔(秒)
  retry_interval: 300

# ============ 安全配置 ============
security:
  # 凭证加密
  encrypt_credentials: true
  encryption_key_env: EMAIL_MANAGEMENT_ENCRYPTION_KEY

  # 敏感操作确认
  confirm_before_delete: true
  confirm_before_send: true

  # 日志级别
  log_level: INFO  # DEBUG / INFO / WARNING / ERROR

  # 审计日志
  audit_log:
    enabled: true
    path: ~/.email-management/audit.log

# ============ 性能配置 ============
performance:
  # 批量处理大小
  batch_size: 20

  # 并发请求数
  max_concurrent: 5

  # 请求超时(秒)
  request_timeout: 30

  # 缓存配置
  cache:
    enabled: true
    ttl: 300  # 缓存有效期(秒)
    max_size: 1000

环境变量配置

# ============ 必需的环境变量 ============

# OpenAI API Key
export OPENAI_API_KEY="sk-your-openai-api-key"

# Gmail OAuth 凭证文件路径
export GMAIL_CREDENTIALS_FILE="/path/to/credentials.json"

# ============ 可选的环境变量 ============

# 加密密钥(用于凭证加密存储)
export EMAIL_MANAGEMENT_ENCRYPTION_KEY="your-encryption-key"

# SMTP 密码(如果使用 SMTP 方式)
export SMTP_PASSWORD="your-app-password"

# Outlook 客户端密钥
export AZURE_CLIENT_SECRET="your-client-secret"

# 日志级别
export EMAIL_MANAGEMENT_LOG_LEVEL="INFO"

# 代理设置(如果需要)
export HTTP_PROXY="http://proxy:8080"
export HTTPS_PROXY="http://proxy:8080"

📊 效果对比 | Performance Comparison

邮件处理效率对比

指标手动处理规则过滤器email-management
日均处理时间2-3小时1-1.5小时15-30分钟
分类准确率85% (人为错误)60% (关键词局限)92% (语义理解)
回复质量因人而异模板化个性化+专业
漏处理率5-10%15-20%2-3%
重复操作时间45分钟/天20分钟/天5分钟/天
跨时区处理无法自动无法自动自动定时发送

分类准确率对比

邮件类型关键词规则朴素贝叶斯LLM 语义分类email-management (混合)
紧急邮件45%62%88%93%
财务邮件78%82%90%95%
会议邀请72%75%91%94%
推广邮件85%88%93%96%
系统通知90%85%89%94%
社交通知82%80%92%95%
普通邮件40%55%80%85%
平均70%75%89%93%

回复生成质量对比

维度模板回复简单生成email-management
上下文理解部分完整 ✔️
语气匹配固定一般精准 ✔️
个性化程度高 ✔️
信息完整性依赖模板不稳定稳定 ✔️
多语言支持需要多模板支持支持 ✔️
行动项明确性不稳定稳定 ✔️

成本对比

方案初始搭建月度维护API 调用成本/月总计(首月)
专职助理处理$0$2000+$0$2000+
邮件客户端规则$0$50+$0$50+
SaaS 邮件工具$0$30-100$0$30-100
email-management$0$0$5-20$5-20

注:email-management 的主要成本是 LLM API 调用费用。使用 gpt-4o-mini 分类每封邮件约 0.0003,使用gpt4o生成回复约0.0003,使用 gpt-4o 生成回复约 0.01-0.03。每天处理 50 封邮件,月度成本约 $5-20。

🎨 定制项 | Customization Options

可定制项一览

定制项支持程度说明
分类类别完全支持可自定义任意分类体系
分类规则完全支持正则表达式 + 语义规则
回复语气完全支持professional/casual/friendly/formal
回复模板完全支持支持变量替换的模板系统
用户风格学习支持从已发送邮件学习写作风格
定时规则完全支持一次性/周期性/条件触发
邮箱提供商部分支持Gmail/Outlook 完整,其他基本
LLM 模型完全支持OpenAI/Anthropic/Ollama/任意兼容
安全策略完全支持加密、审计、确认机制
批量处理完全支持可配置批量大小和并发数
通知方式支持邮件/Slack/Webhook 通知
多账号管理支持同时管理多个邮箱账号

自定义分类示例

# 自定义分类体系

from email_management import EmailClassifier, EmailCategory

# 方式1:扩展默认分类
custom_categories = [
    "VIP客户",      # VIP 客户邮件
    "合作伙伴",     # 合作伙伴邮件
    "内部沟通",     # 公司内部邮件
    "法务合规",     # 法务和合规相关
]

classifier = EmailClassifier(
    api_key="sk-your-key",
    custom_categories=custom_categories
)

# 方式2:完全自定义分类
class MyCategory(Enum):
    CRITICAL = "critical"       # 紧急
    CLIENT = "client"           # 客户
    INTERNAL = "internal"       # 内部
    VENDOR = "vendor"           # 供应商
    AUTO_NOTIFY = "auto_notify" # 自动通知
    JUNK = "junk"               # 垃圾

# 方式3:自定义规则
custom_rules = [
    {
        "name": "CEO邮件",
        "pattern": r"from:ceo@company\.com",
        "category": "紧急",
        "priority": 1,
        "needs_reply": True
    },
    {
        "name": "Jenkins构建通知",
        "pattern": r"from:jenkins@.*\.com subject:*Build*",
        "category": "通知",
        "priority": 4,
        "needs_reply": False
    },
    {
        "name": "发票邮件",
        "pattern": r"(发票|invoice|收据|receipt)",
        "category": "财务",
        "priority": 2,
        "needs_reply": True,
        "auto_action": "forward:finance@company.com"
    }
]

自定义回复风格学习

# 从已发送邮件中学习用户的写作风格

from email_management import StyleLearner

learner = StyleLearner(
    api_key="sk-your-key",
    model="gpt-4o"
)

# 从 Gmail 已发送邮件中学习
style_profile = learner.learn_from_sent_emails(
    manager=manager,
    sample_size=50  # 学习最近50封已发送邮件
)

# 查看学到的风格特征
print("📊 你的写作风格特征:")
print(f"  平均邮件长度: {style_profile.avg_length} 字")
print(f"  常用问候语: {style_profile.common_greetings}")
print(f"  常用结束语: {style_profile.common_closings}")
print(f"  正式程度: {style_profile.formality_score}/10")
print(f"  常用短语: {style_profile.common_phrases[:5]}")

# 将风格特征应用到回复引擎
reply_engine = SmartReplyEngine(
    api_key="sk-your-key",
    user_profile=style_profile.to_dict(),
    style_examples=style_profile.example_emails
)

🏗️ 架构对比 | Architecture Comparison

email-management vs 传统邮件客户端 vs SaaS 邮件工具

┌──────────────────────────────────────────────────────────────────┐
│                    传统邮件客户端架构                               │
│                                                                  │
│  ┌─────┐   ┌─────┐   ┌─────┐   ┌─────┐                        │
│  │IMAP │──>│本地  │──>│规则  │──>│UI   │                        │
│  │SMTP │   │存储  │   │引擎  │   │展示  │                        │
│  └─────┘   └─────┘   └─────┘   └─────┘                        │
│     ↑          ↑          ↑          ↑                           │
│  手动配置   本地存储   关键词规则  手动操作                        │
│  协议连接   占用空间   不够智能  效率低下                          │
│                                                                  │
│  特点:功能有限,规则死板,无AI能力                                  │
└──────────────────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────────┐
│                    SaaS 邮件工具架构                                │
│                                                                  │
│  ┌─────┐   ┌─────┐   ┌─────┐   ┌─────┐   ┌─────┐             │
│  │API  │──>│云端  │──>│ML   │──>│模板  │──>│Web  │             │
│  │集成  │   │处理  │   │模型  │   │系统  │   │界面  │             │
│  └─────┘   └─────┘   └─────┘   └─────┘   └─────┘             │
│     ↑          ↑          ↑          ↑          ↑               │
│  需要授权   数据在云端  黑盒模型  模板有限  订阅付费               │
│  隐私风险   不可控    不可定制  不够灵活  持续成本                 │
│                                                                  │
│  特点:有一定AI能力,但不可定制,数据隐私风险                        │
└──────────────────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────────┐
│                  email-management 架构                             │
│                                                                  │
│  ┌──────────────────────────────────────────────────────────┐    │
│  │                   Agent 适配层                             │    │
│  │  OpenAI Agents | LangChain | CrewAI | AutoGen            │    │
│  └──────────────────────────┬───────────────────────────────┘    │
│                             │                                    │
│  ┌──────────────────────────┴───────────────────────────────┐    │
│  │                email-management 核心                       │    │
│  │                                                          │    │
│  │  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐   │    │
│  │  │智能分类  │ │智能回复  │ │调度引擎  │ │安全引擎  │   │    │
│  │  │引擎     │ │引擎     │ │         │ │         │   │    │
│  │  └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘   │    │
│  │       │            │            │            │          │    │
│  │  ┌────┴────────────┴────────────┴────────────┴─────┐   │    │
│  │  │              LLM 编排层                           │   │    │
│  │  │  OpenAI | Anthropic | Ollama | 自定义模型         │   │    │
│  │  └────────────────────┬────────────────────────────┘   │    │
│  │                       │                                │    │
│  │  ┌────────────────────┴────────────────────────────┐   │    │
│  │  │              邮箱协议层                           │   │    │
│  │  │  Gmail API | Graph API | IMAP | SMTP            │   │    │
│  │  └─────────────────────────────────────────────────┘   │    │
│  └──────────────────────────────────────────────────────────┘    │
│                                                                  │
│  特点:AI原生、可定制、框架无关、数据可控                           │
└──────────────────────────────────────────────────────────────────┘

详细对比表

维度传统邮件客户端SaaS 邮件工具email-management
AI 能力有限完整 ✔️
分类准确率60%75%93% ✔️
回复生成模板化智能生成 ✔️
定制程度规则有限功能固定完全可定制 ✔️
数据隐私本地云端风险可控 ✔️
框架集成多框架 ✔️
成本模型免费/买断订阅制API 按量 ✔️
多邮箱支持支持部分支持支持 ✔️
定时发送部分支持支持完整支持 ✔️
批量处理手动有限智能批量 ✔️
学习曲线
离线能力支持不支持不支持

什么时候该用 email-management?

适合用 email-management 的场景:

  • 每天处理大量邮件(50+封)的职场人士
  • 需要跨时区发送邮件的国际业务人员
  • 重复性邮件处理工作占比高的岗位
  • 已在使用 AI Agent 框架,需要扩展邮件能力
  • 对数据隐私有要求,不想把邮件数据交给第三方SaaS
  • 需要深度定制邮件处理流程

应该用传统邮件客户端的场景:

  • 邮件量很少(每天<10封)
  • 只需要基本的收发邮件功能
  • 不需要AI辅助
  • 需要离线访问邮件

应该用 SaaS 邮件工具的场景:

  • 团队协作需求(共享收件箱)
  • 不想自己部署和维护
  • 需要开箱即用的邮件追踪功能
  • 预算充足,偏好订阅制

🔥 实战案例 | Real-world Case Study

案例:电商客服邮件自动化

"""
实战案例:电商客服邮件自动化系统

场景:
- 某电商公司每天收到 200+ 客户邮件
- 邮件类型:订单查询、退换货、投诉、产品咨询、合作洽谈
- 客服团队5人,每天花3小时处理邮件
- 目标:将邮件处理时间减少70%

方案:
- 使用 email-management 自动分类和初步回复
- 人工审核 AI 生成的回复后发送
- 紧急邮件实时通知客服主管
"""

from email_management import (
    EmailManager, EmailClassifier, SmartReplyEngine, EmailScheduler
)
from openai import OpenAI
import json
from datetime import datetime


# ============ 步骤1:初始化系统 ============

# 邮件管理器
manager = EmailManager(
    provider="gmail",
    credentials_file="credentials.json"
)

# 自定义电商分类体系
class EcommerceCategory(Enum):
    ORDER_QUERY = "订单查询"       # 订单状态、物流查询
    RETURN_REFUND = "退换货"       # 退货、换货、退款
    COMPLAINT = "投诉"             # 客户投诉、差评反馈
    PRODUCT_INQUIRY = "产品咨询"   # 产品信息、库存查询
    PARTNERSHIP = "合作洽谈"       # 商务合作、供应商
    PAYMENT_ISSUE = "支付问题"     # 支付失败、发票
    PROMOTION = "营销推广"         # 营销邮件
    OTHER = "其他"

# 分类器(使用电商专用分类)
classifier = EmailClassifier(
    api_key="sk-your-key",
    model="gpt-4o-mini",
    custom_categories=[c.value for c in EcommerceCategory]
)

# 回复引擎(加载产品知识库)
reply_engine = SmartReplyEngine(
    api_key="sk-your-key",
    model="gpt-4o",
    user_profile={
        "name": "ABC商城客服团队",
        "company": "ABC商城",
    }
)

# 产品知识库(简化版,实际应从数据库加载)
product_knowledge = {
    "退货政策": "7天无理由退货,15天质量问题换货,30天保修",
    "物流时效": "标准配送3-5天,加急配送1-2天,同城当日达",
    "支付方式": "支持支付宝、微信支付、银行卡、花呗分期",
    "发票说明": "电子发票下单后自动发送至邮箱,纸质发票需额外申请",
}


# ============ 步骤2:邮件分类处理 ============

def process_incoming_emails():
    """处理收件箱中的新邮件"""
    # 获取未读邮件
    unread = manager.get_unread_emails(limit=50)
    print(f"📬 收到 {len(unread)} 封新邮件\n")

    for email_data in unread:
        # 智能分类
        result = classifier.classify(email_data)

        print(f"📧 [{result.category.value}] {email_data['subject']}")
        print(f"   优先级: {'⭐' * result.priority} | 需回复: {'是' if result.needs_reply else '否'}")

        # 根据分类执行不同操作
        if result.category.value == "投诉":
            # 投诉邮件:立即通知主管
            handle_complaint(email_data, result)
        elif result.category.value == "退换货":
            # 退换货:自动生成退货指引
            handle_return_refund(email_data, result)
        elif result.category.value == "订单查询":
            # 订单查询:自动回复订单状态
            handle_order_query(email_data, result)
        elif result.category.value == "产品咨询":
            # 产品咨询:基于知识库回复
            handle_product_inquiry(email_data, result)
        elif result.category.value == "营销推广":
            # 营销邮件:自动归档
            manager.archive_email(email_data['id'])
            print("   -> 已自动归档")
        else:
            print("   -> 等待人工处理")

        print()


def handle_complaint(email_data, result):
    """处理投诉邮件 - 最高优先级"""
    # 1. 标记为紧急
    manager.add_label(email_data['id'], 'URGENT')
    manager.add_star(email_data['id'])

    # 2. 生成回复草稿
    draft = reply_engine.generate_reply(
        email_data=email_data,
        tone="friendly",  # 投诉邮件用友好的语气
        context_documents=[
            "投诉处理流程:1.致歉 2.了解详情 3.提供解决方案 4.跟进反馈"
        ]
    )

    # 3. 保存草稿
    manager.save_draft(
        to=email_data['from'],
        subject=draft.subject,
        body=draft.body,
        thread_id=email_data['thread_id']
    )

    # 4. 通知主管(通过 Slack 或邮件)
    notify_manager(email_data, result)

    print("   -> 已标记紧急 + 生成回复草稿 + 通知主管")


def handle_return_refund(email_data, result):
    """处理退换货邮件"""
    # 生成退货指引回复
    draft = reply_engine.generate_reply(
        email_data=email_data,
        tone="professional",
        context_documents=[
            product_knowledge["退货政策"],
            "退换货流程:1.提交申请 2.审核通过 3.寄回商品 4.退款/换货"
        ]
    )

    manager.save_draft(
        to=email_data['from'],
        subject=draft.subject,
        body=draft.body,
        thread_id=email_data['thread_id']
    )

    # 添加财务标签
    manager.add_label(email_data['id'], 'Finance')

    print("   -> 已生成退货指引草稿")


def handle_order_query(email_data, result):
    """处理订单查询邮件"""
    # 尝试从邮件中提取订单号
    import re
    order_pattern = r'(?:订单号|order\s*#?|ord\s*#?)\s*[::]?\s*(\w{10,20})'
    match = re.search(order_pattern, email_data['body'], re.IGNORECASE)

    if match:
        order_id = match.group(1)
        # 查询订单状态(实际应调用订单系统API)
        order_status = query_order_status(order_id)

        # 生成包含订单状态的回复
        draft = reply_engine.generate_reply(
            email_data=email_data,
            tone="professional",
            context_documents=[
                f"订单号: {order_id}",
                f"当前状态: {order_status['status']}",
                f"物流公司: {order_status['carrier']}",
                f"物流单号: {order_status['tracking_number']}",
                product_knowledge["物流时效"]
            ]
        )
    else:
        # 没有找到订单号,请求提供
        draft = reply_engine.generate_reply(
            email_data=email_data,
            tone="professional",
            context_documents=[
                "请客户提供订单号以便查询订单状态"
            ]
        )

    manager.save_draft(
        to=email_data['from'],
        subject=draft.subject,
        body=draft.body,
        thread_id=email_data['thread_id']
    )

    print("   -> 已生成订单查询回复草稿")


def handle_product_inquiry(email_data, result):
    """处理产品咨询邮件"""
    # 基于产品知识库生成回复
    relevant_docs = []
    for topic, content in product_knowledge.items():
        relevant_docs.append(f"{topic}: {content}")

    draft = reply_engine.generate_reply(
        email_data=email_data,
        tone="friendly",
        context_documents=relevant_docs
    )

    manager.save_draft(
        to=email_data['from'],
        subject=draft.subject,
        body=draft.body,
        thread_id=email_data['thread_id']
    )

    print("   -> 已生成产品咨询回复草稿")


def query_order_status(order_id: str) -> dict:
    """查询订单状态(模拟)"""
    return {
        "order_id": order_id,
        "status": "运输中",
        "carrier": "顺丰速运",
        "tracking_number": "SF1234567890",
        "estimated_delivery": "2025-05-20"
    }


def notify_manager(email_data, result):
    """通知客服主管"""
    # 实际实现可以发送 Slack 消息、钉钉通知等
    print(f"   📱 已通知主管: 投诉邮件 - {email_data['subject']}")


# ============ 步骤3:运行系统 ============

if __name__ == "__main__":
    print("=" * 60)
    print("🏪 ABC商城 - 邮件自动化处理系统")
    print("=" * 60)
    print()

    process_incoming_emails()

    print("\n" + "=" * 60)
    print("✅ 处理完成!请登录邮箱审核回复草稿。")
    print("=" * 60)

运行效果示例:

============================================================
🏪 ABC商城 - 邮件自动化处理系统
============================================================

📬 收到 23 封新邮件

📧 [投诉] 我的订单3天了还没发货!!
   优先级: ⭐ | 需回复: 是
   -> 已标记紧急 + 生成回复草稿 + 通知主管

📧 [退换货] 申请退货 - 商品与描述不符
   优先级: ⭐⭐ | 需回复: 是
   -> 已生成退货指引草稿

📧 [订单查询] 订单号 ABC123456789 什么时候到?
   优先级: ⭐⭐⭐ | 需回复: 是
   -> 已生成订单查询回复草稿

📧 [产品咨询] 你们这款手机支持5G吗?
   优先级: ⭐⭐⭐ | 需回复: 是
   -> 已生成产品咨询回复草稿

📧 [营销推广] 限时优惠!全场5折起
   优先级: ⭐⭐⭐⭐ | 需回复: 否
   -> 已自动归档

...

============================================================
✅ 处理完成!请登录邮箱审核回复草稿。
============================================================

效果数据:

指标使用前使用后改善
日均处理时间3小时45分钟-75%
回复时效2-4小时15-30分钟-87%
投诉响应时间4-8小时5分钟(通知)-98%
重复操作时间1.5小时10分钟-89%
客户满意度72%89%+24%

❓ 常见问题 | FAQ

1. Gmail 提示"不够安全的应用"怎么办?

# Gmail 从2022年9月起不再支持"不太安全的应用"密码
# 解决方案:使用应用专用密码

# 步骤1:开启两步验证
# 访问 https://myaccount.google.com/security
# 开启"两步验证"

# 步骤2:生成应用专用密码
# 访问 https://myaccount.google.com/apppasswords
# 选择"邮件"和设备,生成16位密码

# 步骤3:使用应用专用密码替代普通密码
manager = EmailManager(
    provider="smtp",
    smtp_host="smtp.gmail.com",
    smtp_port=465,
    username="your-email@gmail.com",
    password="xxxx xxxx xxxx xxxx"  # 16位应用专用密码
)

# 推荐方案:使用 Gmail API + OAuth2.0(更安全)
manager = EmailManager(
    provider="gmail",
    credentials_file="credentials.json"
)

2. 如何处理大量邮件时的 API 速率限制?

# Google API 速率限制:
# - Gmail API: 每秒5次请求,每天10亿次
# - 超出限制会返回 429 Too Many Requests

# 解决方案1:添加请求间隔
import time

def rate_limited_get_emails(manager, total=100, batch_size=20):
    """带速率限制的批量获取邮件"""
    all_emails = []

    for offset in range(0, total, batch_size):
        emails = manager.get_emails(limit=batch_size, offset=offset)
        all_emails.extend(emails)

        # 每批之间等待,避免触发速率限制
        time.sleep(1)  # 等待1秒

        print(f"已获取 {len(all_emails)}/{total} 封邮件")

    return all_emails

# 解决方案2:使用批量 API
# Gmail API 支持批量请求,可以在一个 HTTP 请求中执行多个操作

# 解决方案3:使用指数退避重试
from tenacity import retry, stop_after_attempt, wait_exponential

@retry(
    stop=stop_after_attempt(5),
    wait=wait_exponential(multiplier=1, min=4, max=60)
)
def get_email_with_retry(manager, email_id):
    """带重试的邮件获取"""
    return manager.get_email(email_id)

3. 如何保证邮件数据安全?

# 安全最佳实践

# 1. 凭证加密存储
from cryptography.fernet import Fernet

class SecureCredentialStore:
    """安全的凭证存储"""

    def __init__(self, key: str):
        self.cipher = Fernet(key.encode())

    def save(self, key: str, value: str):
        """加密保存凭证"""
        encrypted = self.cipher.encrypt(value.encode())
        # 保存到安全的位置(如系统密钥链)

    def load(self, key: str) -> str:
        """解密加载凭证"""
        encrypted = self._load_from_storage(key)
        return self.cipher.decrypt(encrypted).decode()

# 2. 使用环境变量,不要硬编码密码
import os
password = os.environ.get('SMTP_PASSWORD')  # 从环境变量读取

# 3. 审计日志
# 记录所有邮件操作,包括读取、发送、删除
audit_log = {
    "timestamp": datetime.now().isoformat(),
    "action": "send_email",
    "user": "agent@example.com",
    "to": "client@example.com",
    "subject": "项目更新",
    "result": "success"
}

# 4. 敏感操作确认
# 发送邮件前需要人工确认
reply_engine = SmartReplyEngine(
    api_key="sk-your-key",
    auto_send=False,           # 不自动发送
    require_confirmation=True   # 需要确认
)

# 5. 使用 OAuth2.0 而非密码
# OAuth2.0 的 token 可以随时撤销,比密码更安全

4. 如何处理中文邮件的编码问题?

# 中文邮件编码问题常见于:
# 1. 邮件头(Subject, From)的编码
# 2. 邮件正文的编码
# 3. 附件文件名的编码

# 解决方案:统一使用 UTF-8 解码

from email.header import decode_header
from email import message_from_bytes

def safe_decode_header(header_value: str) -> str:
    """安全解码邮件头,处理各种编码"""
    if not header_value:
        return ""

    parts = decode_header(header_value)
    decoded_parts = []

    for content, charset in parts:
        if isinstance(content, bytes):
            try:
                # 优先使用检测到的编码
                decoded_parts.append(
                    content.decode(charset or 'utf-8', errors='replace')
                )
            except (LookupError, UnicodeDecodeError):
                # 编码名无效或解码失败,尝试常见中文编码
                for encoding in ['utf-8', 'gbk', 'gb2312', 'big5']:
                    try:
                        decoded_parts.append(content.decode(encoding))
                        break
                    except UnicodeDecodeError:
                        continue
                else:
                    decoded_parts.append(content.decode('utf-8', errors='replace'))
        else:
            decoded_parts.append(content)

    return ''.join(decoded_parts)


def safe_decode_body(payload: bytes, charset: str = None) -> str:
    """安全解码邮件正文"""
    if charset:
        try:
            return payload.decode(charset, errors='replace')
        except LookupError:
            pass

    # 尝试常见中文编码
    for encoding in ['utf-8', 'gbk', 'gb2312', 'big5', 'iso-8859-1']:
        try:
            return payload.decode(encoding)
        except UnicodeDecodeError:
            continue

    return payload.decode('utf-8', errors='replace')

5. 如何实现多邮箱统一管理?

# 同时管理多个邮箱账号

from email_management import EmailManager, MultiAccountManager

# 创建多账号管理器
multi_manager = MultiAccountManager()

# 添加 Gmail 工作邮箱
multi_manager.add_account(
    name="work_gmail",
    provider="gmail",
    credentials_file="work_credentials.json"
)

# 添加 Outlook 公司邮箱
multi_manager.add_account(
    name="company_outlook",
    provider="outlook",
    client_id="azure-client-id",
    client_secret="azure-client-secret",
    tenant_id="tenant-id"
)

# 添加个人 SMTP 邮箱
multi_manager.add_account(
    name="personal",
    provider="smtp",
    smtp_host="smtp.163.com",
    smtp_port=465,
    username="personal@163.com",
    password=os.environ.get('PERSONAL_EMAIL_PASSWORD')
)

# 统一获取所有邮箱的未读邮件
all_unread = multi_manager.get_all_unread()

for account_name, emails in all_unread.items():
    print(f"\n📬 {account_name}: {len(emails)} 封未读")
    for email_data in emails:
        print(f"  - [{email_data['from']}] {email_data['subject']}")

# 从指定账号发送邮件
multi_manager.send_email(
    account_name="work_gmail",
    to="client@example.com",
    subject="项目更新",
    body="..."
)

6. 如何与现有 Agent 框架集成?

# 与 CrewAI 集成示例

from crewai import Agent, Task, Crew
from email_management import EmailManager, EmailClassifier, SmartReplyEngine

# 创建邮件管理工具
manager = EmailManager(provider="gmail", credentials_file="credentials.json")
classifier = EmailClassifier(api_key="sk-your-key")
reply_engine = SmartReplyEngine(api_key="sk-your-key")

# 创建邮件分类 Agent
email_sorter = Agent(
    role="邮件分类专家",
    goal="准确分类所有未读邮件,识别紧急和重要邮件",
    backstory="你是一个经验丰富的邮件管理助手,擅长快速识别邮件的优先级和类别。",
    tools=[read_unread_emails, classify_email]
)

# 创建邮件回复 Agent
email_responder = Agent(
    role="邮件回复专家",
    goal="为需要回复的邮件生成专业、得体的回复草稿",
    backstory="你是一个专业的商务沟通专家,擅长撰写各种风格的邮件回复。",
    tools=[generate_reply, search_emails]
)

# 创建任务
sort_task = Task(
    description="读取今天的未读邮件并进行分类,标记紧急和重要邮件",
    agent=email_sorter,
    expected_output="分类结果列表,包含每封邮件的类别和优先级"
)

reply_task = Task(
    description="为所有需要回复的邮件生成回复草稿",
    agent=email_responder,
    expected_output="回复草稿列表"
)

# 创建 Crew
email_crew = Crew(
    agents=[email_sorter, email_responder],
    tasks=[sort_task, reply_task],
    verbose=True
)

# 运行
result = email_crew.kickoff()
print(result)

📚 扩展学习资源 | Extended Resources

官方资源

邮件协议学习

AI Agent 框架

社区资源

Conclusion | 结语

  • That's all for today~ - | 今天就写到这里啦~

  • Guys, ( ̄ω ̄( ̄ω ̄〃 ( ̄ω ̄〃)ゝ See you tomorrow~~ | 小伙伴们,( ̄ω ̄( ̄ω ̄〃 ( ̄ω ̄〃)ゝ我们明天再见啦~~

  • Everyone, be happy every day! 大家要天天开心哦

  • Welcome everyone to point out any mistakes in the article~ | 欢迎大家指出文章需要改正之处~

  • Learning has no end; win-win cooperation | 学无止境,合作共赢

  • Welcome all the passers-by, boys and girls, to offer better suggestions! ~~~ | 欢迎路过的小哥哥小姐姐们提出更好的意见哇~~

image