BillionMail 批量发送任务如何启用发送者 IP 预热(Sender IP Warmup)
2026/9/15 10:43:05 网站建设 项目流程

BillionMail 批量发送任务如何启用发送者 IP 预热(Sender IP Warmup)

【免费下载链接】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

当一台邮件服务器开始承担批量发送时,发送者 IP 需要一个逐步爬升的预热过程,而不是直接满速发送。BillionMail 在批量发送任务(Batch Mail Task)上提供了「关联IP预热系统」开关:开启后,任务会与该服务器 IP 的预热记录(bm_sender_ip_warmup)建立关联,系统按 IP 当前预热状态限制发件速率,并在后台周期性地评估 IP 的得分与预热进度。本文说明如何在创建批量发送任务时启用 Sender IP Warmup,以及如何核对预热关联确实生效。

预热开关的位置

前端任务编辑页 edit.vue 中有一个开关,绑定form.warmup字段(取值1/0),界面文案来自语言包 zh.json:

  • 标签:关联IP预热系统
  • 提示:开启后将会限制发件速率

同一个开关在 API 层对应warmup参数,出现在两个接口定义中(见 batch_mail.go):

  • 创建任务:POST /api/batch_mail/task/create"warmup" v:"in:0,1" dc:"warmup" default:"0"
  • 更新任务:POST /api/batch_mail/task/update,同样带warmup(0 或 1)。

默认值是0,即不启用预热,需要显式传1

方式一:在控制台创建任务时开启

最短路径:

  1. 进入批量发送任务的新建/编辑页面,完成发件人(addresser)、主题、邮件模板(template_id)和联系人分组(group_id)等必填项;
  2. 找到「关联IP预热系统」开关并打开,即把warmup置为1
  3. 保存任务。

保存后系统会执行预热关联逻辑(见 batch_mail.go):当Warmup == 1时调用warmup.WarmupCampaign().AssociateCampaignWithWarmup(ctx, id, serverIP),把任务与服务器 IP 的预热状态绑定。对已有任务,通过更新接口把warmup改为1也会触发同样的关联(见 batch_mail.go)。

方式二:直接调用任务创建接口

如果通过 API 管理任务,可以在创建请求中带上"warmup": 1。下面的请求体结构来自仓库中的 E2E 测试 test_06_warmup.py,其中addressersubjecttemplate_idgroup_id需替换为你实例中真实的发件邮箱、主题、模板 ID 和联系人分组 ID,Authorization头填你的访问令牌:

curl -X POST 'http://<你的实例地址>/api/batch_mail/task/create' \ -H 'Content-Type: application/json' \ -H 'Authorization: <你的访问令牌>' \ -d '{ "addresser": "发件人邮箱", "subject": "任务主题", "full_name": "发件人姓名", "template_id": 1, "group_id": 1, "start_time": 1757836800, "track_open": 1, "track_click": 1, "unsubscribe": 1, "threads": 1, "warmup": 1 }'

注意两点:start_time是 UNIX 时间戳;E2E 测试里特意把开始时间设为未来一小时(int(time.time()) + 3600)以避免任务立即开始发送,测试场景下值得照做。

开启后系统实际做了什么

关联逻辑在 warmup_with_campaigns.go 中,顺序如下:

  1. 初始化或取出该服务器 IP 的预热记录。若bm_sender_ip_warmup表中还没有这个 IP,会新建一条:预热周期period默认 45 天,初始得分score为 40,进度progress为 0,end_time设为开始时间加 45 天(见 sender_ip_warmup.go 与建表默认值 sender_ip_warmup.go);
  2. 写入任务与预热的关联:在bm_campaign_warmup表插入一条task_id → warmup_id的记录;若任务此前关联的是别的预热 ID,会更新为新 ID;
  3. 计算预计发送时长CalculateEstimatedTime用未发送收件人数量除以各邮箱服务商分组(Gmail、Yahoo、Outlook、Apple、Proton、Zoho、Amazon、Other)调整后的小时发送上限,得到预计秒数。任务列表中的estimated_time_with_warmup字段展示这个值,-1表示该任务没有启用预热(见 batch_mail.go 和前端列表列 index.vue)。

运行期,任务执行器在发送前会检查该任务是否已关联预热(warmupAssociated),若已关联,则对每个收件人按其所属邮箱服务商分组调用RateLimiter().Allow(...)决定是否放行(见 task_executor.go)。同时,后台定时器周期性调用SenderIpWarmup().PeriodicTask(...)(见 timers.go),基于评估窗口内的送达、硬/软退信、deferred 以及打开/点击数据更新 IP 的scoreprogress,并动态调整预热周期:低分会延长周期,得分高且进度过半则缩短周期,预热完成后若分数显著下降还会触发重新预热(逻辑见 sender_ip_warmup.go)。

验证预热是否生效

E2E 测试 test_06_warmup.py 给出了仓库自带的核对方式,可以照此验证:

  1. 创建请求返回 HTTP 200 且响应体code == 0data.id即新任务 ID;
  2. GET /api/batch_mail/task/find?id=<任务ID>能取回任务信息;
  3. 查询数据库确认关联记录存在(BillionMail 使用 PostgreSQL,$1为任务 ID 参数):
SELECT id FROM bm_campaign_warmup WHERE task_id = $1;

返回一行即说明任务已关联预热;没有行则说明warmup未生效。另外可查bm_sender_ip_warmup表确认服务器 IP 的记录:新 IP 应能看到period = 45score = 40progress = 0的初始值(以上为代码和建表脚本定义的初始值,不是运行一段时间后的固定预期)。

限制与边界

  • 开关的界面提示是「开启后将会限制发件速率」——启用预热的直接效果是任务发送被限速,任务整体跑完会变慢,任务列表的estimated_time_with_warmup就是该任务在预热限速下的预计耗时;
  • 预热以服务器 IP为单位而非以任务为单位:同一 IP 上的多个预热任务共享同一条bm_sender_ip_warmup记录,任务的warmup参数只决定本任务是否接入该 IP 的限速逻辑;
  • 预热周期不是固定 45 天,会按 IP 得分与进度动态伸缩(见 UpdateWarmupPeriod),预热完成后低分 IP 也可能被重置重新预热。

【免费下载链接】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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询