BillionMail 仓库开发实战指南CLAUDE.md 工程规范、测试命令与两大关键约束的源码级解读【免费下载链接】BillionMailBillionMail gives you open-source MailServer, NewsLetter, Email Marketing — fully self-hosted, dev-friendly, and free from monthly fees. Join the discord: https://discord.gg/asfXzBUhZr项目地址: https://gitcode.com/GitHub_Trending/bi/BillionMail导读本文以仓库根目录的 CLAUDE.md 为骨架系统讲解 BillionMail 开源邮件营销平台自建 MailServer、Newsletter 与 Email Marketing的工程组织方式目录分层、技术栈、编码规范、质量检查与测试命令并重点剖析两条Bug 记忆规则——public.FormatMX邮件主机名规范与 RBACmodules注册机制——结合 Go 源码 与 RBAC 中间件 给出调用链证据。读完本文你将能在该仓库中快速定位代码、按规范提交改动、跑通质量与测试流水线并理解哪些坑是维护者明文禁止的。一、BillionMail 是什么BillionMail 是一个开源的邮件服务器与邮件营销一体化平台覆盖批量发送bulk sending、营销活动campaigns、联系人管理contact management、IP 预热warmup与数据分析analytics等完整链路见 README.md。与纯 SaaS 邮件营销服务不同它强调完全自托管self-hosted邮件基础设施Postfix、Dovecot、Rspamd与业务控制面Go 后端 Vue 前端全部随仓库交付可通过 docker-compose.yml 一键拉起。CLAUDE.md 的核心价值在于它既是给 AI Agent 的协作协议项目根目录的 CLAUDE.md 通常会被 Claude Code / Cursor 等工具自动加载也是给人类开发者的工程手册——约 90 行内容浓缩了目录约定、质量红线、测试入口与历史踩坑记录是进入本仓库的第一份必读文档。二、技术栈全览文档声明 vs. 仓库实际CLAUDE.md 的 Stack 一节给出了高层技术栈结合 core/go.mod 与前端目录可精确到版本层次技术仓库证据后端语言Go当前 go.mod 声明go 1.24.0module billionmail-core后端框架GoFrame v2github.com/gogf/gf/v2 v2.10.0go.mod数据库PostgreSQLgogf/contrib/drivers/pgsql/v2、Redisgogf/contrib/nosql/redis/v2go.mod、init.sql前端Vue 3 TypeScript Pinia Naive UI Vitest pnpmcore/frontend/src、core/frontend/package.json、core/frontend/vitest.config.ts邮件栈Postfix / Dovecot / Rspamdconf/postfix、conf/dovecot、conf/rspamd、Dockerfiles部署Docker Composedocker-compose.yml、env_init值得注意的两点补充版本以 go.mod 为准CLAUDE.md 标注 Go 1.22但仓库当前 go.mod 实际声明go 1.24.0。这类文档滞后于代码的情况在开源仓库很常见动手前应以源码为准。依赖蕴含业务能力github.com/sashabaranov/go-openaiAI 撰写邮件、github.com/xuri/excelize/v2联系人导入导出、github.com/golang-jwt/jwt/v5API Token 鉴权、github.com/miekg/dnsDNS 记录校验、github.com/go-acme/lego/v4免费 SSL 申请等依赖分别对应 AskAI、联系人管理、API 邮件、域名 SSL 等模块与core/internal/service/下的业务域一一对应。三、目录结构与分层约定核心骨架CLAUDE.md 用一棵目录树勾勒出全仓布局这是理解仓库的地图。原样继承并补充源码级说明core/ ├── internal/ │ ├── cmd/ # CLI 入口含 ACME 证书续期子命令 │ ├── controller/ # HTTP 处理器16 业务域 │ ├── service/ # 业务逻辑batch_mail、domains、rbac、maillog_stat、warmup、contact 等 │ ├── dao/ # 数据访问层 │ ├── model/entity/ # ORM 实体 │ └── consts/ # 常量日志类型、邮件服务商等 ├── api/ # API 路由定义 ├── frontend/src/ │ ├── views/ # 页面组件domain、contacts、mailbox、settings 等 │ ├── components/ # 可复用 UI 组件 │ ├── store/ # Pinia 状态模块 │ ├── api/modules/ # API 客户端模块 │ ├── router/ # Vue Router 模块路由 │ ├── hooks/ # Composables │ ├── utils/ # 工具base、data、time、storage │ ├── features/ # 功能组件EmailEditor 邮件编辑器 │ └── i18n/ # 国际化en、zh、ja 等 ├── template/ # 邮件模板确认信、退订信、欢迎信 └── manifest/ # 配置/部署 conf/ # 邮件服务配置postfix、dovecot、rspamd、redis Dockerfiles/ # 容器定义core、postfix、dovecot、rspamd从源码看controller 域数量确为 16 个以上abnormal_recipient、askai、batch_mail、campaign、contact、dockerapi、domains、email_template、files、languages、mail_boxes、mail_services、operation_log、overview、rbac、relay、settings、subscribe_list、tags、video_outreach分别位于 core/internal/controller 与 core/api 下。前后端映射关系同样清晰前端 core/frontend/src/views 下的domain/、contacts/、mailbox/、smtp/、template/、overview/、settings/等目录与后端 controller 域基本一一对应API 调用则集中在 core/frontend/src/api/modules。CLAUDE.md 还给出了明确的组织规则Organization Rules这是所有贡献者必须遵守的放置约定Controllers →core/internal/controller/一个业务域一个目录Services →core/internal/service/一个业务域一个目录API 路由 →core/api/一个业务域一个目录前端页面 →core/frontend/src/views/一个功能一个目录测试 → 与被测源码放在一起*_test.go、*.test.ts每个文件单一职责、命名具有描述性。以domains域为例三条规则同时落地路由定义在 core/api/domains/v1HTTP 处理器在 core/internal/controller/domains每个接口一个文件如domains_v1_add_domain.go业务逻辑在 core/internal/service/domainsdomains.go、dns.go、ssl.go、blacklist.go、baseurl.go。而测试就近存放例如 core/internal/service/domains/dns_test.go、core/internal/service/maillog_stat/tracker_test.go。四、代码质量红线改完必跑的检查CLAUDE.md 规定编辑任何文件后必须执行质量检查且修完所有报错才能继续。这是仓库的硬性 gate# Go 侧 cd core go vet ./... gofmt -l . # 前端侧 cd core/frontend pnpm run lint拆解两条 Go 命令的意义go vet ./...静态分析捕捉不可达代码、错误的 Printf 格式串、锁拷贝等常见缺陷gofmt -l .列出未按标准格式化的文件-l只输出文件名列表不实际改写用于 CI 中快速定位格式违规pnpm run lint前端 ESLint 检查前端工程配置见 core/frontend/eslint.config.mjs。这一规范与仓库中测试文件的高密度分布相互印证——例如 core/internal/service/batch_mail 下同时存在spintax_test.go、template_render_test.go、simple_rate_controller_test.go、jwt_test.go等说明该域对正确性要求极高任何改动都应有对应的质量反馈闭环。五、测试规范三条命令覆盖 Go 与前端CLAUDE.md 给出三档测试入口核心是short 模式——-short标志跳过需要数据库等外部依赖的用例让开发者在无 DB 环境下也能快速回归# Goshort 模式无需数据库 cd core go test -count1 -short ./internal/service/... # 前端 cd core/frontend pnpm test # 两者一起 cd core go test -count1 -short ./internal/service/... cd frontend pnpm test参数细节-count1禁用 Go 测试缓存确保每次都是真实执行避免 CI 里吃到过期缓存./internal/service/...覆盖全部业务逻辑包。前端侧Vitest 配置位于 core/frontend/vitest.config.ts测试入口与全局 setup 见 core/frontend/src/test-setup.ts同时存在 core/frontend/src/utils 下成对的*.test.ts如base.test.ts、data.test.ts、storage.test.ts以及 hooks 测试useCopy.test.ts、useDataTable.test.ts。仓库中的集成测试也验证了short 模式的必要性例如 core/internal/service/batch_mail/task_executor_integration_test.go、core/internal/service/maillog_stat/tracker_integration_test.go 这类以_integration_test.go命名的文件需要真实环境正常开发回归应优先跑 short 用例。六、两大Bug 记忆规则必须刻进脑子的红线CLAUDE.md 的Bug Memory Rules是整个文档中信息密度最高的部分它记录的是历史上真实踩过的坑面向所有后来者尤其是 AI Agent6.1 永远不要用裸域名做邮件基础设施NEVER use bare domain for mail infrastructure (DNS, certs, DKIM, dedicated IPs). Always usepublic.FormatMX(domain)to get the mail hostname (e.g.,mail.example.com).这条规则的底层实现位于 core/internal/service/public/common.go#L2673-L2681// FormatMX format the email domain func FormatMX(domain string) string { val, err : g.DB().Model(domain).Where(domain, domain).WhereOr(a_record, domain).Value(a_record) if err nil !val.IsEmpty() { return val.String() } return mail. strings.TrimPrefix(domain, mail.) }其行为分两层优先查库若domain表中有该域或其 A 记录值的自定义a_record多 IP 发信场景下每个域可配置独立主机名则返回该自定义值兜底拼接否则返回mail. 域名对已是mail.开头的域名做幂等去重即默认mail.example.com。调用链证据——FormatMX几乎贯穿域名从接入到发信的每一个环节添加域名入库前强制规范化主机名见 core/internal/controller/domains/domains_v1_add_domain.go#L22 的req.Hostname public.FormatMX(req.Domain)DNS 记录生成与校验MX 记录值与校验均基于FormatMX结果见 core/internal/service/domains/domains.go#L750-L805SSL 证书签发与查询证书的 SNI/域名列表全部使用格式化后的主机名见 core/internal/service/domains/ssl.go#L28-L81Postfix 环境注入把主机名写入 Postfix 容器的/postfix.sh环境变量BILLIONMAIL_HOSTNAME见 core/internal/service/domains/domains.go#L116-L123证书续期 CLI检查证书存在性与续期路径同样基于FormatMX见 core/internal/cmd/cmd.go#L473-L487。为什么不能裸用域名邮件基础设施MX 记录、TLS 证书、DKIM 签名、专用 IP必须绑定在mail.example.com这样的专用主机名上而非裸域example.com——裸域往往被用作网站解析与邮件解析混用会导致 DNS 记录冲突、SPF/DKIM 校验失败、证书 SAN 不匹配等问题。这是贡献者最容易犯、也最致命的一类错误。6.2 新增 controller 必须登记到 RBAC modules 列表When adding new controllers, add the module name to the RBACmoduleslist incore/internal/service/middlewares/rbac.go.这条规则的落地位置在 core/internal/service/middlewares/rbac.go#L18-L59PathToRouteInfo函数内置了一个白名单式模块列表modules : []string{ account, role, permission, domains, mail_boxes, overview, dockerapi, contact, email_template, batch_mail, files, abnormal_recipient, languages, mail_services, relay, settings, subscribe_list, operation_log, askai, tags, video_outreach, }该函数从请求路径中提取module/action/resource三元组先扫描 modules 列表确定模块再用正则/api/(\w)/(\w)(?:/.*)?解析资源与动作并把list/detail → read、create/update/delete映射为标准 CRUD 语义。随后RBACMiddleware.PermissionCheck同文件 core/internal/service/middlewares/rbac.go#L74-L162执行默认拒绝策略/api/login、/api/refresh-token、/api/unsubscribe、/api/batch_mail/api/send等公开/API 邮件端点走旁路白名单不校验权限管理员角色admin直接放行其余请求若module/action/resource任一为空即模块未登记默认拒绝并返回 403。因此如果新增 controller 却没有把模块名加入列表该模块的所有接口都会因无法解析出 module 而被默认拒绝——这就是新增模块必须登记这条规则的直接后果。做功能扩展时modules数组core/internal/service/middlewares/rbac.go#L21-L28与 JWT 旁路清单同文件 L76-L87注释明确要求must match jwt.go bypass list需要同步维护相关鉴权逻辑还可对照 core/internal/service/batch_mail/jwt.go 查看 API 邮件的独立 Token 机制。七、面向 Agent 的协作命令CLAUDE.md 末尾定义了一组斜杠命令用于和 AI 编码工具如 Claude Code 的自定义 slash commands协作命令作用/test运行完整测试套件即第五节的三条命令/fixLint 类型检查 并行 Agent 自动修复/commit质量检查 AI 生成提交信息 push/update-app升级依赖并修复弃用项这组命令把质量门禁从文档规范变成了可执行的动作/commit会先跑完第四、五节的所有检查再提交/fix则利用并行 Agent 分批处理 lint 与类型错误。对于希望给仓库贡献代码的开发者理解这组命令背后对应的检查项go vet/gofmt/pnpm lint/go test -short比记忆命令本身更重要。八、从规范到贡献一份可执行的行动清单综合全文向本仓库提交代码的推荐流程是定位按域domain查找——后端看 core/internal/controller 与 core/internal/service 同名目录前端看 core/frontend/src/views 对应目录路由定义在 core/api改动遵循单一职责controller 每个接口一个文件service 承载业务逻辑若新增业务域先在 core/internal/service/middlewares/rbac.go#L21-L28 的modules列表登记模块名否则会被默认拒绝涉及邮件基础设施DNS/证书/DKIM/IP一律经public.FormatMX格式化主机名禁止裸域质量门禁go vet ./... gofmt -l .Go、pnpm run lint前端全部清零回归测试go test -count1 -short ./internal/service/...与pnpm test测试文件就近放在被测源码旁。结语CLAUDE.md 虽然只有约 90 行却是 BillionMail 仓库最浓缩的开发宪法目录树告诉你代码在哪组织规则告诉你代码该放哪质量与测试命令告诉你如何自证正确而两条 Bug 记忆规则则用源码级的实现common.go 的 FormatMX 与 rbac.go 的 modules 白名单划出了两个最容易踩坑的雷区。对任何想要参与这个开源邮件营销平台、或是在自建邮件基础设施项目中借鉴工程实践的开发者来说遵守这套规范就是避免 80% 返工的开始。【免费下载链接】BillionMailBillionMail gives you open-source MailServer, NewsLetter, Email Marketing — fully self-hosted, dev-friendly, and free from monthly fees. Join the discord: https://discord.gg/asfXzBUhZr项目地址: https://gitcode.com/GitHub_Trending/bi/BillionMail创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考