Skip to content

AIAPI-LD/EMailService

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 

Repository files navigation

mail_core

mail_core 是一个“Provider 可插拔 + 统一 API + 本地状态持久化”的邮箱服务模块。 它解决的问题是:上层业务只写一套调用代码,就可以在不同临时邮箱后端之间切换,并且自动处理邮箱过期、轮换和本地记录维护。

1. 设计目标

  • 统一调用入口:调用方只依赖 MailService
  • 运行时多态:通过 JSON 配置切换 provider,不改业务代码。
  • 明确状态管理:邮箱 jwt/address/创建时间/过期时间 统一落盘。
  • 强制规则:每次拉邮件前先做过期检查,必要时自动重建邮箱。
  • 可扩展:新增 Provider 只需实现抽象接口并注册工厂。

2. 当前能力总览

  • 已内置 Provider:
    • cloudflare_worker
    • duckmail
    • gpt_mail
    • mock
  • 本地存储:JSON 文件(默认 ./data/mailboxes.json
  • 统一验证码提取:支持从邮件原文中提取 6 位验证码
  • 自动轮换策略:
    • TTL 过期轮换
    • 鉴权失败(401/403)触发一次重建重试

3. 目录结构

mail_core/
  __init__.py
  api.py                    # 统一门面 MailService
  config.py                 # JSON 配置加载与环境变量注入
  errors.py                 # 统一异常
  models.py                 # 数据模型
  provider_base.py          # Provider 抽象接口
  provider_registry.py      # Provider 注册工厂
  store.py                  # 本地 JSON 存储
  code_parser.py            # 验证码提取器
  providers/
    cloudflare_worker.py
    duckmail_provider.py
    gptmail_provider.py
    mock_provider.py

4. 依赖与环境

最低依赖(按当前代码):

  • Python 3.10+
  • requests

可选依赖:

  • 若你需要继续使用旧脚本场景中的 dotenv,可自行安装 python-dotenvmail_core 本身不强依赖。

5. 快速开始

5.1 准备配置

  1. 复制 mail_config.example.jsonmail_config.json
  2. 根据你使用的 Provider 填入参数
  3. 如需密钥,设置环境变量

5.2 最小调用示例

from mail_core import MailService

svc = MailService.from_config("mail_config.json")

# 获取一个业务键对应的邮箱记录(不存在则创建)
record = svc.acquire_mailbox("gemini_signup")
print(record.address, record.expires_at)

# 拉取邮件(内部会先检查是否过期)
record, messages = svc.get_messages("gemini_signup", limit=20)
print(record.address, len(messages))

# 轮询验证码
record, code = svc.get_verification_code(
    "gemini_signup",
    timeout_sec=180,
    poll_interval_sec=5,
)
print("code =", code)

6. 配置说明

6.1 配置骨架

{
  "default_provider_id": "cf_main",
  "store": {
    "path": "./data/mailboxes.json"
  },
  "providers": {
    "cf_main": {
      "type": "cloudflare_worker"
    }
  }
}

字段说明:

  • default_provider_id:默认 provider 实例 ID,可省略;省略时使用 providers 第一个条目。
  • store.path:本地 JSON 存储路径。相对路径按配置文件所在目录解析。
  • providers:provider 实例集合,键是实例 ID,值是 provider 参数对象。
  • providers.<id>.type:provider 类型,必须已在注册表中注册。

6.2 环境变量注入规则

mail_core 支持两种方式:

  1. ${ENV_NAME} 内联替换
    示例:"api_key": "${DUCKMAIL_API_KEY}"

  2. *_env 映射注入
    示例:"admin_password_env": "ADMIN_PASSWORD"
    加载时自动读取环境变量并映射为 admin_password

7. Provider 详解

7.1 cloudflare_worker

常用参数:

  • worker_domain
  • email_domain
  • admin_passwordadmin_password_env
  • token_ttl_seconds
  • request_timeout_sec
  • enable_prefix

特点:

  • 标准的“创建邮箱 + JWT 拉信”模型
  • 支持 TTL 过期轮换

7.2 duckmail

常用参数:

  • api_base(默认 https://api.duckmail.sbs
  • api_key(可选)
  • default_domain(可空,空则自动拉取可用域名)
  • token_ttl_seconds
  • request_timeout_sec
  • create_max_retries
  • password_length

特点:

  • 内部自动执行“建账号 + 换 token”
  • 读取邮件时优先取源内容,失败回退详情内容
  • 支持 TTL 过期轮换

7.3 gpt_mail

常用参数:

  • base_url(默认 https://mail.chatgpt.org.uk
  • request_timeout_sec
  • extra_headers

关键设计(当前版本为强约束):

  • type 仅支持 gpt_mail
  • 邮箱记录严格视为永不过期
  • expires_at 固定写入 null
  • 不提供 token_ttl_seconds 配置入口。
  • jwt 语义为邮箱地址本身(因为 GPTMail 接口不返回独立 token)。

示例:

{
  "providers": {
    "gpt_main": {
      "type": "gpt_mail",
      "base_url": "https://mail.chatgpt.org.uk",
      "request_timeout_sec": 10,
      "extra_headers": {}
    }
  }
}

7.4 mock

本地测试用 Provider,不依赖真实网络服务。适合单元测试和开发联调。

8. 统一 API(调用契约)

MailService 核心接口:

  • from_config(config_path)
  • acquire_mailbox(key, provider_id=None, name_hint=None, force_recreate=False)
  • refresh_if_expired(key, provider_id=None, name_hint=None, create_if_missing=True)
  • get_messages(key, limit=20, offset=0, provider_id=None, name_hint=None, create_if_missing=True)
  • get_latest_raw(key, provider_id=None, name_hint=None, create_if_missing=True)
  • get_verification_code(key, timeout_sec=180, poll_interval_sec=5, provider_id=None, name_hint=None, create_if_missing=True, limit=20)
  • list_mailboxes()
  • close()

key 说明:

  • key 是业务侧稳定标识,不是邮箱地址。
  • 同一个 key 在轮换后仍可继续使用,调用方不需要关心地址变化。

9. 过期与轮换策略

统一策略在 MailService 执行:

  1. 每次 get_messages/get_latest_raw/get_verification_code 前先调用 refresh_if_expired
  2. 若记录过期则自动重建邮箱并更新本地 JSON。
  3. 若拉信遇到 ProviderAuthError,会触发一次“重建 + 重试”。

Provider 级差异:

  • cloudflare_worker / duckmail:默认按 TTL 轮换(来自配置或 provider 默认)。
  • gpt_mail:永不过期,不参与 TTL 轮换。

10. 本地存储格式

默认文件:data/mailboxes.json

{
  "version": 1,
  "mailboxes": {
    "gemini_signup": {
      "key": "gemini_signup",
      "provider_id": "cf_main",
      "address": "abc123@example.com",
      "jwt": "xxxxx",
      "created_at": "2026-03-01T10:00:00.000Z",
      "expires_at": "2026-03-08T10:00:00.000Z",
      "updated_at": "2026-03-01T10:00:00.000Z",
      "rotation_count": 0,
      "last_fetch_at": null,
      "last_error": null,
      "meta": {}
    }
  }
}

写入特性:

  • 进程内线程锁保护
  • 临时文件 + os.replace 原子落盘

11. 新增 Provider 指南

实现步骤:

  1. mail_core/providers/ 新建 provider 文件并继承 MailProvider
  2. 实现以下方法:
    • provider_name
    • create_mailbox
    • fetch_messages
  3. 如需特殊过期语义:
    • 覆写 default_ttl_seconds()is_non_expiring()
  4. mail_core/provider_registry.py 注册 type -> factory
  5. 更新 mail_config.example.json 和本 README

12. 异常模型

核心异常类型:

  • ConfigError:配置错误
  • ProviderNotFoundError:provider 类型未注册
  • ProviderRequestError:网络/响应错误
  • ProviderAuthError:鉴权错误(会触发轮换重试)
  • StoreError:本地存储读写失败
  • MailboxNotFoundError:找不到业务键对应记录

13. 安全建议

  • 不要把密钥明文提交到仓库,优先用环境变量注入。
  • 日志中不要直接打印完整 jwt
  • 对生产环境建议限制 mailboxes.json 文件权限。

14. 常见问题

Q: 为什么我没有传 provider_id 也能创建邮箱?
A: 会自动使用 default_provider_id

Q: 为什么同一个 key 下邮箱地址变了?
A: 发生了过期轮换或鉴权失败重建。

Q: gpt_mail 为什么不轮换?
A: 这是当前版本的强设计:gpt_mail 定义为永不过期 provider。

15. 当前版本约束(重要)

  • 已明确取消向后兼容设计。
  • gpt_mail 仅接受 type: "gpt_mail"
  • 不保证旧配置中的历史字段可无改动沿用。

About

支持GPT Mail, DuckMail以及域名邮箱。通过统一的创建/拉取邮箱接口使用。一次编写,多后端通用。

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages