Files
mailgo/docs/architecture.md
2026-06-01 18:59:55 +08:00

26 KiB
Raw Permalink Blame History

MailGo 系统设计文档

项目mail_go —— 自托管 Go 邮件系统
架构师:高见远
版本v1.0
日期2025-07


1. 实现方案分析

1.1 核心技术挑战

挑战 说明 应对策略
SMTP/IMAP/POP3 三协议并行 三个邮件协议服务需同时运行、共享同一套用户与邮件数据 统一 Backend 接口层,三个协议服务均委托给同一 MailStore + UserStore
邮件解析与持久化 go-message 解析 MIME 后需拆分为元数据 + 正文 + 附件 统一 MessageParser 服务,解析后原子写入 DB + 文件系统
IMAP 文件夹/标记/搜索 go-imap/v2 需实现完整的 Backend / User / Mailbox / Message 接口 采用"数据库为单一真相源"架构,IMAP 操作全部映射到 GORM 查询
跨平台路径 Linux/Windows 配置与数据路径不同 config 层根据 runtime.GOOS 自动映射路径前缀
附件存储一致性 附件写入文件系统后需与 DB 记录对齐 事务内写 DB + 事后写文件,失败时异步清理孤儿文件
Web 认证与权限 普通用户 vs 管理员,Session 管理 Gin 中间件:AuthMiddleware(登录检查)+ AdminMiddleware(管理员检查)

1.2 框架与库选型

组件 选型 理由
SMTP 服务端 github.com/emersion/go-smtp PRD 指定,成熟稳定
IMAP 服务端 github.com/emersion/go-imap/v2 PRD 指定,v2 API 更现代
POP3 服务端 手工实现(TCP 监听 + 文本协议) emersion 系列无官方 go-pop3POP3 协议简单,自实现可控
邮件解析 github.com/emersion/go-message 与 go-smtp/go-imap 生态一致
Web 框架 gin-gonic/gin PRD 指定,高性能
模板引擎 html/template Go 标准库,自动转义防 XSS
ORM gorm.io/gorm + gorm.io/driver/sqlite + gorm.io/driver/mysql PRD 指定,双数据库支持
配置解析 github.com/BurntSushi/toml TOML 格式标准库
密码哈希 golang.org/x/crypto/bcrypt PRD 指定
UUID github.com/google/uuid PRD 指定,用于附件文件名等
Session github.com/gin-contrib/sessions + cookie store 轻量,无需 Redis

1.3 架构模式

采用 分层架构 + 共享 Store 层

┌──────────────────────────────────────────────┐
│              main.go (启动入口)                │
├──────────┬──────────┬──────────┬───────────────┤
│ SMTP     │ IMAP     │ POP3     │  Web (Gin)   │
│ Server   │ Server   │ Server   │  Router      │
├──────────┴──────────┴──────────┴───────────────┤
│              Store Layer (共享)                 │
│  UserStore │ MailStore │ DomainStore │ AttachmentStore │
├────────────────────────────────────────────────┤
│              GORM (SQLite / MySQL)             │
└────────────────────────────────────────────────┘
  • 协议层SMTP/IMAP/POP3)仅负责协议握手,业务逻辑委托 Store 层
  • Web 层Gin + html/template)负责 UI 渲染和 HTTP API
  • Store 层封装所有数据库操作,是唯一的数据访问入口
  • Config 在启动时加载为全局单例,通过依赖注入传递给各 Server

2. 项目文件列表

mail_go/
├── main.go                           # 程序入口:配置加载 → DB 初始化 → 各服务启动
├── go.mod                            # Go 模块定义
├── go.sum                            # 依赖校验
├── config/
│   ├── config.go                     # 配置结构体 + 加载 + 自动补全逻辑
│   └── defaults.go                  # 默认值常量(端口、路径等)
├── internal/
│   ├── db/
│   │   ├── db.go                     # GORM 初始化 + AutoMigrate
│   │   └── models.go                 # User / Domain / Message / Attachment 模型
│   ├── store/
│   │   ├── user_store.go             # 用户 CRUD + 认证
│   │   ├── mail_store.go             # 邮件 CRUD + 文件夹查询
│   │   ├── domain_store.go           # 域名 CRUD
│   │   └── attachment_store.go       # 附件元数据 CRUD
│   ├── smtp_server/
│   │   └── server.go                 # SMTP 服务端(go-smtp Backend 实现)
│   ├── imap_server/
│   │   ├── server.go                 # IMAP 服务端启动
│   │   └── backend.go               # go-imap Backend/User/Mailbox/Message 实现
│   ├── pop3_server/
│   │   └── server.go                 # POP3 服务端(TCP 监听 + 文本协议)
│   ├── web/
│   │   ├── server.go                 # Gin 引擎初始化 + 路由注册
│   │   ├── middleware/
│   │   │   ├── auth.go               # 登录认证中间件
│   │   │   └── admin.go              # 管理员鉴权中间件
│   │   ├── handlers/
│   │   │   ├── auth.go               # 登录/登出处理
│   │   │   ├── mail.go               # 收件箱/发件箱/撰写/查看
│   │   │   └── admin.go              # 管理后台处理
│   │   └── templates/
│   │       ├── base.html             # 基础布局模板
│   │       ├── login.html            # 登录页
│   │       ├── inbox.html            # 收件箱
│   │       ├── compose.html          # 撰写邮件
│   │       ├── sent.html             # 发件箱
│   │       ├── view.html             # 邮件阅读
│   │       └── admin/
│   │           ├── dashboard.html    # 管理首页
│   │           ├── domains.html      # 域名管理
│   │           └── users.html        # 用户管理
│   └── storage/
│       └── attachment.go             # 附件文件读写(磁盘操作)
├── scripts/
│   └── install.sh                    # Linux 安装脚本(创建目录、设置权限)
└── docs/
    ├── prd.md
    └── architecture.md              # 本文档

3. 数据结构与接口

3.1 数据库模型(GORM

classDiagram
    class User {
        +uint ID
        +string Username
        +string PasswordHash
        +uint DomainID
        +Domain Domain
        +int64 QuotaBytes
        +int64 UsedBytes
        +bool IsActive
        +bool IsAdmin
        +time CreatedAt
        +time UpdatedAt
    }

    class Domain {
        +uint ID
        +string Name
        +int SmtpPort
        +int ImapPort
        +int Pop3Port
        +string TlsCertPath
        +string TlsKeyPath
        +bool TlsEnabled
        +time CreatedAt
        +time UpdatedAt
    }

    class Message {
        +uint ID
        +uint UserID
        +User User
        +string MessageID
        +string Folder
        +string FromAddr
        +string ToAddr
        +string CcAddr
        +string Subject
        +string TextBody
        +string HtmlBody
        +bool IsRead
        +bool IsFlagged
        +time Date
        +time CreatedAt
    }

    class Attachment {
        +uint ID
        +uint MessageID
        +Message Message
        +string FileName
        +string FilePath
        +string ContentType
        +int64 FileSize
        +time CreatedAt
    }

    Domain "1" --> "*" User : has
    User "1" --> "*" Message : owns
    Message "1" --> "*" Attachment : has

详细字段说明

User

字段 类型 说明
ID uint 主键
Username string 用户名(@ 前部分)
PasswordHash string bcrypt 哈希
DomainID uint 所属域名外键
Domain Domain 所属域名
QuotaBytes int64 附件配额(字节),默认 5GB
UsedBytes int64 已用空间(字节)
IsActive bool 是否启用
IsAdmin bool 是否管理员
CreatedAt time.Time 创建时间
UpdatedAt time.Time 更新时间

Domain

字段 类型 说明
ID uint 主键
Name string 域名(如 example.com
SmtpPort int SMTP 端口
ImapPort int IMAP 端口
Pop3Port int POP3 端口
TlsCertPath string TLS 证书路径
TlsKeyPath string TLS 私钥路径
TlsEnabled bool 是否启用 TLS
CreatedAt time.Time 创建时间
UpdatedAt time.Time 更新时间

Message

字段 类型 说明
ID uint 主键
UserID uint 所属用户外键
User User 所属用户
MessageID string RFC 2822 Message-ID
Folder string 文件夹:INBOX / Sent / Drafts / Trash
FromAddr string 发件人地址
ToAddr string 收件人地址(逗号分隔)
CcAddr string 抄送地址(逗号分隔)
Subject string 主题
TextBody string 纯文本正文
HtmlBody string HTML 正文
IsRead bool 是否已读
IsFlagged bool 是否标记
Date time.Time 邮件日期
CreatedAt time.Time 入库时间

Attachment

字段 类型 说明
ID uint 主键
MessageID uint 所属邮件外键
Message Message 所属邮件
FileName string 原始文件名
FilePath string 磁盘相对路径
ContentType string MIME 类型
FileSize int64 文件大小(字节)
CreatedAt time.Time 创建时间

3.2 核心接口设计

Config 结构体

// config/config.go

type Config struct {
    Database DatabaseConfig
    Storage  StorageConfig
    Web      WebConfig
    SMTP     SMTPConfig
    IMAP     IMAPConfig
    POP3     POP3Config
}

type DatabaseConfig struct {
    Driver string // "sqlite" | "mysql"
    DSN    string
}

type StorageConfig struct {
    BaseDir    string
    AttachDir  string
}

type WebConfig struct {
    Listen string // ":8080" 或 Unix socket 路径
}

type SMTPConfig struct {
    Port    int
    TLSPort int
    Cert    string
    Key     string
}

type IMAPConfig struct {
    Port    int
    TLSPort int
    Cert    string
    Key     string
}

type POP3Config struct {
    Port    int
    TLSPort int
    Cert    string
    Key     string
}

Store 接口

// internal/store/

type UserStore interface {
    Create(user *models.User) error
    GetByID(id uint) (*models.User, error)
    GetByUsername(username string, domainID uint) (*models.User, error)
    GetByEmail(email string) (*models.User, error)
    Authenticate(email, password string) (*models.User, error)
    Update(user *models.User) error
    Delete(id uint) error
    List(domainID uint, page, size int) ([]models.User, int64, error)
    UpdateUsedBytes(id uint, delta int64) error
}

type MailStore interface {
    Create(msg *models.Message) error
    GetByID(id uint) (*models.Message, error)
    ListByUserAndFolder(userID uint, folder string, page, size int) ([]models.Message, int64, error)
    MarkRead(id uint) error
    MarkFlagged(id uint, flagged bool) error
    MoveToFolder(id uint, folder string) error
    Delete(id uint) error
    CountUnread(userID uint, folder string) (int64, error)
}

type DomainStore interface {
    Create(domain *models.Domain) error
    GetByID(id uint) (*models.Domain, error)
    GetByName(name string) (*models.Domain, error)
    Update(domain *models.Domain) error
    Delete(id uint) error
    List(page, size int) ([]models.Domain, int64, error)
}

type AttachmentStore interface {
    Create(att *models.Attachment) error
    ListByMessage(messageID uint) ([]models.Attachment, error)
    Delete(id uint) error
    DeleteByMessage(messageID uint) error
}

SMTP Backend 接口(go-smtp 要求)

// internal/smtp_server/server.go

// 实现 go-smtp 的 Backend 接口
type smtpBackend struct {
    userStore  store.UserStore
    mailStore  store.MailStore
    domainStore store.DomainStore
    attStore   store.AttachmentStore
    storage    *storage.AttachmentStorage
}

func (b *smtpBackend) NewSession(c *smtp.Conn) (smtp.Session, error)
func (s *smtpSession) AuthPlain(username, password string) error
func (s *smtpSession) Mail(from string, opts *smtp.MailOptions) error
func (s *smtpSession) Rcpt(to string, opts *smtp.RcptOptions) error
func (s *smtpSession) Data(r io.Reader) error
func (s *smtpSession) Logout() error

IMAP Backend 接口(go-imap/v2 要求)

// internal/imap_server/backend.go

// 实现 go-imap/v2 的 backend.Backend 接口
type imapBackend struct {
    userStore  store.UserStore
    mailStore  store.MailStore
    domainStore store.DomainStore
    attStore   store.AttachmentStore
}

func (b *imapBackend) Login(username, password string) (backend.User, error)

// imapUser 实现 backend.User
type imapUser struct {
    user  *models.User
    store *mailStoreGorm
}

func (u *imapUser) ListMailboxes(subscribed bool) ([]imap.Mailbox, error)
func (u *imapUser) GetMailbox(name string) (backend.Mailbox, error)

// imapMailbox 实现 backend.Mailbox
type imapMailbox struct {
    user   *models.User
    folder string
    store  *mailStoreGorm
}

// imapMessage 实现 backend.Message

4. Web 路由表

Method Path Handler 中间件 说明
GET /login auth.ShowLogin 登录页
POST /login auth.DoLogin 登录提交
POST /logout auth.DoLogout Auth 登出
GET / mail.Inbox Auth 收件箱(重定向到 /inbox
GET /inbox mail.Inbox Auth 收件箱列表
GET /inbox/:id mail.View Auth 查看邮件
GET /compose mail.Compose Auth 撰写页面
POST /compose mail.DoSend Auth 发送邮件
GET /sent mail.Sent Auth 发件箱
GET /sent/:id mail.View Auth 查看已发送邮件
POST /mail/delete/:id mail.Delete Auth 删除邮件
POST /mail/read/:id mail.MarkRead Auth 标记已读
GET /attachment/:id mail.DownloadAttachment Auth 下载附件
GET /admin admin.Dashboard Auth + Admin 管理后台首页
GET /admin/domains admin.ListDomains Auth + Admin 域名列表
GET /admin/domains/new admin.NewDomain Auth + Admin 新增域名页
POST /admin/domains admin.CreateDomain Auth + Admin 创建域名
POST /admin/domains/:id/delete admin.DeleteDomain Auth + Admin 删除域名
GET /admin/domains/:id/dns admin.DNSHint Auth + Admin DNS 配置提示
GET /admin/users admin.ListUsers Auth + Admin 用户列表
GET /admin/users/new admin.NewUser Auth + Admin 新增用户页
POST /admin/users admin.CreateUser Auth + Admin 创建用户
POST /admin/users/:id/delete admin.DeleteUser Auth + Admin 删除用户
GET /admin/users/:id/edit admin.EditUser Auth + Admin 编辑用户页
POST /admin/users/:id admin.UpdateUser Auth + Admin 更新用户

5. 程序调用流程

5.1 启动流程

sequenceDiagram
    participant Main as main.go
    participant Cfg as config
    participant DB as db
    participant Store as Store Layer
    participant SMTP as SMTP Server
    participant IMAP as IMAP Server
    participant POP3 as POP3 Server
    participant Web as Web Server (Gin)

    Main->>Cfg: LoadConfig("config.toml")
    Cfg->>Cfg: 检测文件是否存在
    alt 配置文件不存在
        Cfg->>Cfg: 生成默认配置并写入文件
    else 配置文件存在但字段缺失
        Cfg->>Cfg: 补全缺失字段为默认值
    end
    Cfg-->>Main: 返回 *Config

    Main->>DB: InitDB(cfg.Database)
    DB->>DB: 根据 Driver 选择 SQLite/MySQL
    DB->>DB: gorm.Open(...)
    DB->>DB: db.AutoMigrate(User, Domain, Message, Attachment)
    DB-->>Main: 返回 *gorm.DB

    Main->>Store: NewStoreLayer(db, cfg.Storage)
    Store-->>Main: 返回 Store 实例集合

    Main->>Store: 检查是否存在 admin 用户
    alt 无 admin 用户
        Main->>Store: 创建默认 admin 账户
    end

    par 并行启动服务
        Main->>SMTP: NewSMTPServer(cfg.SMTP, stores)
        SMTP->>SMTP: smtp.NewServer(backend)
        SMTP->>SMTP: 监听 Port + TLSPort
    and
        Main->>IMAP: NewIMAPServer(cfg.IMAP, stores)
        IMAP->>IMAP: imapserver.New(backend)
        IMAP->>IMAP: 监听 Port + TLSPort
    and
        Main->>POP3: NewPOP3Server(cfg.POP3, stores)
        POP3->>POP3: net.Listen + 协议循环
        POP3->>POP3: 监听 Port + TLSPort
    and
        Main->>Web: NewWebServer(cfg.Web, stores)
        Web->>Web: 注册路由 + 中间件
        Web->>Web: gin.Run(cfg.Web.Listen)
    end

5.2 用户收信流程(SMTP 入站 → Web 展示)

sequenceDiagram
    participant Remote as 远程 MTA
    participant SMTP as SMTP Server
    participant Parser as MessageParser
    participant MS as MailStore
    participant AS as AttachmentStore
    participant FS as FileSystem
    participant User as 浏览器用户
    participant Web as Web Server (Gin)

    Remote->>SMTP: TCP 连接 + EHLO/MAIL FROM/RCPT TO
    SMTP->>SMTP: 验证收件人域名是否在本系统
    SMTP->>SMTP: 查找对应用户
    Remote->>SMTP: DATA (邮件内容)
    SMTP->>Parser: ParseMIME(r io.Reader)
    Parser->>Parser: go-message 解析 MIME
    Parser-->>SMTP: 返回 ParsedMessage{From, To, Subject, TextBody, HtmlBody, Attachments}

    SMTP->>MS: Create(Message{Folder:"INBOX", ...})
    MS->>MS: GORM INSERT messages

    loop 每个附件
        SMTP->>AS: Create(Attachment{FileName, ContentType, Size})
        AS->>AS: GORM INSERT attachments
        SMTP->>FS: WriteFile(attachmentsDir/uuid.ext, data)
    end

    SMTP-->>Remote: 250 OK

    Note over User,Web: 用户稍后登录 Web 查看邮件

    User->>Web: GET /inbox
    Web->>Web: AuthMiddleware 检查 Session
    Web->>MS: ListByUserAndFolder(userID, "INBOX", page, size)
    MS-->>Web: []Message + total
    Web->>Web: 渲染 inbox.html
    Web-->>User: 收件箱页面

    User->>Web: GET /inbox/42
    Web->>MS: GetByID(42)
    MS-->>Web: Message 详情
    Web->>AS: ListByMessage(42)
    AS-->>Web: []Attachment
    Web->>Web: 渲染 view.html
    Web-->>User: 邮件阅读页

    User->>Web: GET /attachment/7
    Web->>AS: GetByID(7) → FilePath
    Web->>FS: OpenFile(attachmentsDir/filepath)
    Web-->>User: 文件下载流

6. 有序任务列表

Task ID 任务名称 依赖 涉及文件 优先级
T01 项目基础设施:go.mod + 入口 + 配置系统 + 数据库层 go.mod, main.go, config/config.go, config/defaults.go, internal/db/db.go, internal/db/models.go, internal/store/*.go P0
T02 邮件协议服务端(SMTP + IMAP + POP3 T01 internal/smtp_server/server.go, internal/imap_server/server.go, internal/imap_server/backend.go, internal/pop3_server/server.go P0
T03 Web 服务核心:路由 + 中间件 + 认证 + 邮件页面 T01 internal/web/server.go, internal/web/middleware/auth.go, internal/web/middleware/admin.go, internal/web/handlers/auth.go, internal/web/handlers/mail.go P0
T04 管理后台 + 附件存储 + 模板 T01, T03 internal/web/handlers/admin.go, internal/storage/attachment.go, internal/web/templates/*.html P0
T05 集成调试 + 安装脚本 T02, T03, T04 main.go(更新), scripts/install.sh P1

任务详细说明

T01: 项目基础设施

  • 初始化 go.mod,声明所有依赖
  • 实现 config.LoadConfig():读取 TOML → 缺失字段补全默认值 → 写回文件
  • 实现 config 中的路径映射:Linux 用 /etc/mail_go/ + /srv/mail_go/Windows 用 ./win/etc/mail_go/ + ./win/srv/mail_go/
  • 实现 db.InitDB():根据 driver 选择 SQLite/MySQL,执行 AutoMigrate
  • 定义所有 GORM 模型:User, Domain, Message, Attachment
  • 实现 Store 层所有接口的 GORM 实现
  • main.go 骨架:加载配置 → 初始化 DB → 创建 Store → 首次启动生成 admin

T02: 邮件协议服务端

  • SMTP:实现 go-smtp 的 Backend/Session 接口,收信后调用 MailStore 写入
  • IMAP:实现 go-imap/v2 的 Backend/User/Mailbox 接口,查询 MailStore
  • POP3TCP 监听 + 文本协议实现(USER/PASS/STAT/LIST/RETR/DELE/QUIT),查询 MailStore
  • 三个服务均接受 Store 实例作为构造参数

T03: Web 服务核心

  • Gin 引擎初始化 + Session 中间件配置
  • AuthMiddleware:检查 Session 中的 userID,未登录重定向 /login
  • AdminMiddleware:检查用户 IsAdmin 字段
  • 登录/登出 handlerbcrypt 校验 + Session 写入
  • 收件箱/发件箱/撰写 handler:渲染模板 + Store 调用
  • 发送邮件 handler:构造 MIME 消息,通过本地 SMTP 发送

T04: 管理后台 + 附件存储 + 模板

  • 管理后台 handler:域名 CRUD、用户 CRUD、DNS 提示
  • AttachmentStorage:附件文件写入/读取/删除磁盘操作
  • 所有 HTML 模板:base 布局 + login/inbox/compose/sent/view/admin 系列页面
  • 附件上传(compose 页面多文件上传)+ 下载 handler

T05: 集成调试 + 安装脚本

  • main.go 更新:并行启动 SMTP/IMAP/POP3/Web 四个服务,graceful shutdown
  • 端汇总测试:SMTP → Store → Web 展示 全链路
  • install.shLinux 下创建 /etc/mail_go/ /srv/mail_go/ 目录、设置权限

7. 依赖包列表(go.mod 草稿)

module mail_go

go 1.22

require (
    github.com/emersion/go-smtp v0.21.0
    github.com/emersion/go-imap/v2 v2.0.0-beta.5
    github.com/emersion/go-message v0.18.0
    github.com/gin-gonic/gin v1.10.0
    github.com/gin-contrib/sessions v0.0.5
    github.com/BurntSushi/toml v1.3.2
    gorm.io/gorm v1.25.12
    gorm.io/driver/sqlite v1.5.6
    gorm.io/driver/mysql v1.5.7
    github.com/google/uuid v1.6.0
    golang.org/x/crypto v0.25.0
)

版本号为撰写时最新稳定版参考,实际以 go get 拉取为准。


8. 跨文件共享约定(Shared Knowledge

8.1 配置传递

  • main.go 加载 Config 单例,通过构造函数注入到各 Server
  • 所有 Server 签名统一为 NewXxxServer(cfg XxxConfig, stores *Stores, ...) *XxxServer
  • 禁止在 Store/Handler 层直接读取配置文件,一律通过参数传递

8.2 Session 约定

  • Session 名称:mail_go_session
  • 登录后写入 Session 的 key
    • userID → uint
    • userEmail → string(完整邮箱地址,如 admin@example.com
    • isAdmin → bool
  • Session 使用 Cookie 存储,MaxAge = 8640024 小时)
  • Cookie HttpOnly = true, SameSite = Lax

8.3 错误处理

  • Store 层错误统一返回 Go error,不做日志输出
  • Web Handler 层捕获 Store 错误后:
    • 5xx → 渲染 base.html 中的错误提示区
    • 4xx → 重定向或渲染对应页面并显示错误消息
  • SMTP/IMAP/POP3 协议层错误直接返回协议规定的错误码

8.4 邮件地址规范

  • 系统内部统一使用完整邮箱地址(user@domain.com)标识用户
  • User.Username 仅存储 @ 前部分
  • 查找用户时通过 User.Username + Domain.Name 组合查询
  • Message.FromAddr / ToAddr / CcAddr 均为完整邮箱地址

8.5 文件夹命名

内部名称 IMAP 映射 说明
INBOX INBOX 收件箱
Sent Sent Messages 发件箱
Drafts Drafts 草稿箱
Trash Trash 废纸篓

8.6 附件存储路径

  • 附件存储根目录:cfg.Storage.AttachDir
  • 单个附件路径:{AttachDir}/{uuid}{ext},其中 uuid 由 google/uuid 生成,ext 保留原始扩展名
  • Attachment.FilePath 存储相对路径(不含 AttachDir 前缀)

8.7 数据库约定

  • 所有表名使用蛇形复数:users, domains, messages, attachments
  • 时间字段统一使用 time.TimeUTC),GORM 自动管理 created_at / updated_at
  • 软删除暂不实现,删除操作为硬删除
  • 分页统一参数:page(从 1 开始)、size(默认 20

9. 任务依赖图

graph LR
    T01[T01: 项目基础设施] --> T02[T02: 邮件协议服务端]
    T01 --> T03[T03: Web 服务核心]
    T01 --> T04[T04: 管理后台+附件+模板]
    T03 --> T04
    T02 --> T05[T05: 集成调试+安装脚本]
    T03 --> T05
    T04 --> T05

T02 与 T03 可并行开发(仅依赖 T01),T04 依赖 T03(管理后台 handler 需要 Web 框架),T05 为最终集成。


10. 待明确事项

# 问题 假设 影响范围
1 DKIM 私钥由系统自动生成还是管理员手动导入?(PRD OQ-1) 第一期仅管理员手动导入,/admin 域名配置页提供私钥文件路径输入框 admin handler, Domain 模型
2 是否支持邮件转发规则?(PRD OQ-2) 第一期不支持,SMTP 收信仅投递到本地用户 smtp_server
3 附件大小上限由全局配置还是按用户配额?(PRD OQ-3) 第一期采用全局配置 + 用户配额双重限制:单文件上限 25MB(硬编码),总空间不超过用户 QuotaBytes compose handler, AttachmentStorage
4 Web 撰写是否支持富文本?(PRD OQ-4) 第一期仅支持纯文本(textarea),后续可引入 Markdown 或 TinyMCE compose.html, mail handler
5 多域名是否纳入第一期?(PRD OQ-5) 第一期支持多域名(Domain 表设计已包含),但 DNS 提示仅展示通用模板 admin handler, DNS 提示
6 是否支持 OAuth2/LDAP 认证?(PRD OQ-6 第一期仅本地账户认证,bcrypt 密码校验 auth handler
7 go-imap/v2 仍为 beta 版本,API 可能变更 锁定特定 commit hash,在 go.mod 中 replace 指向稳定版本 go.mod, imap_server
8 POP3 协议实现范围 实现 USER/PASS/STAT/LIST/RETR/DELE/NOOP/RSET/QUIT 基本命令,不支持 APOP/UIDL pop3_server
9 首次启动 admin 账户的默认密码 admin(首次登录后强制修改,或 /admin 页面提示修改) main.go
10 Windows 上是否支持 Unix Socket 不支持,Windows 下 web.listen 仅支持 TCP 端口格式 :8080 config, web server