博客更新以后,读者未必会回来。把新文章推送到邮箱,听起来只差一个订阅框,实际还要处理确认订阅、退订、邮件被拒收和地址失效。周刊持续发送以后,这些小事会比第一封邮件的排版更影响维护成本。
listmonk 适合把订阅者、邮件列表和发送活动放在自己的服务器上管理。它需要 PostgreSQL,通过 SMTP 等发送渠道交付邮件。可以在 GitHub 找到项目代码,也可以直接使用容器。这里围绕一份每周发送一次的技术周刊,安排从部署到日常维护的完整流程。
发刊之前,先确定哪部分由谁负责
一份周刊至少涉及网站、名单管理和邮件发送三个部分。博客提供文章和订阅表单,listmonk 保存订阅状态并组织发送,SMTP 服务负责把邮件交给收件方服务器。把 listmonk 放到 VPS 上,并不意味着这台 VPS 还必须自己运行一套公网邮件服务器。
刚开始可以接入已经提供 SMTP 凭据的邮件服务,先把发件域名、发送额度和退信接收路径配置清楚。自建邮件服务器要另外承担 IP 信誉、队列和收件策略等工作。如果目标只是发一份周刊,没有必要在第一天就把这些工作一起接过来。
读者的名单也要有明确边界。订阅技术周刊和注册网站账号是两件不同的事。不要把后台所有邮箱导出之后直接导入发送列表。保留“何时、通过什么入口订阅”的记录,以后排查重复邮件和退订争议时有用。
先在私人入口完成安装
准备一台能运行 Docker Compose 的 Linux 服务器,并留出 PostgreSQL 数据、上传图片和备份的空间。如果需要新实例,可以从雨云查看云服务器配置,注册时填写优惠码 KuZhuJi。邮件是否能够送达,主要还要看发送渠道和域名配置,不应拿 VPS 带宽代替邮件发送能力。
官方安装指南提供了 Compose 文件。下载后先阅读再启动,尤其检查镜像、端口、默认密码和数据卷:
mkdir -p ~/listmonk
cd ~/listmonk
curl -fL https://raw.githubusercontent.com/knadh/listmonk/master/docker-compose.yml \
-o compose.yaml
chmod 600 compose.yaml
官方示例里的数据库密码是演示值,必须替换;应用与 PostgreSQL 使用同一份数据库凭据。把应用端口改为只监听本机:
ports:
- "127.0.0.1:9000:9000"
数据库不需要接受公网连接,可以删除数据库服务的 ports 映射。应用仍通过 Compose 网络中的 db:5432 连接数据库。应用读取的是容器内地址,不能改成宿主机的 127.0.0.1。
当前官方 Compose 文件会在启动应用之前执行安装和升级步骤。先在空数据库上试用,验证配置后记录使用的镜像标签或摘要。正式发送环境不要依赖一个会不断变化的镜像标签:下一次拉取可能同时带来数据库迁移,影响的范围远大于更换一个网页界面。
docker compose config --quiet
docker compose up -d
docker compose ps
docker compose logs --tail=100 app
从本机通过 SSH 隧道进入初始化页面:
ssh -N -L 19000:127.0.0.1:9000 user@server.example.com
浏览器访问 http://127.0.0.1:19000,完成管理员创建。这一步应在向公众提供订阅入口之前完成。管理账号与日常发刊账号分别保存,避免在多人协作时共用最高权限的密码。
HTTPS 接入要照顾订阅和退订页面
公开域名可以使用 newsletter.example.com,由现有 Caddy 或 Nginx 反向代理到本机9000端口。Caddy 的基础站点配置如下,前提是 DNS 已经指向服务器,服务器80、443端口可用:
newsletter.example.com {
reverse_proxy 127.0.0.1:9000
}
不要为了只让自己访问后台,在反向代理上给整个域名加一道只有站长知道的密码。读者需要访问订阅确认、退订和其他公开页面。如果要额外限制后台,应依据HTTP 路由说明区分管理入口和公开入口,并分别测试。简单部署可以先保留应用的后台认证,之后再加针对管理路径的限制。
设置里的公开根地址应当与读者实际访问的 HTTPS 地址一致。确认邮件和退订链接都用这个地址检查,不能只看后台能够登录。反向代理成功返回首页,不代表邮件里的链接已经正确。
把双重确认完整走一遍
listmonk 用列表组织订阅者,一次发送活动可以面向一个或多个列表。订阅者加入列表后的状态还会区分未确认、已确认和已退订,具体语义见订阅概念。
为公开周刊创建一个需要双重确认的列表。读者提交邮箱以后,先收到确认邮件;点击确认链接,才成为该列表的已确认订阅者。试用时准备两个自己控制的测试邮箱,一个完成确认,另一个保持未确认,然后向这个列表发送测试活动,核对实际收件情况。
导入名单时不要一律勾选“已确认”。从旧系统迁来的地址,要有原系统的订阅状态;普通通讯录中的地址不应凭空变成周刊订阅者。如果旧系统只导出了邮箱,没有退订状态和来源信息,应先补齐记录,再决定迁移哪些人。
列表数量少一点通常更容易维护。起步时一个正式周刊列表和一个内部测试列表就够了。不要因为后台支持很多标签和属性,就立刻给每个人加一套复杂画像。能帮助决定发送范围的属性才有保留价值。
第一封邮件,先用手机读完
邮件模板先保持简单:标题、几段正文、文章链接、退订入口。长段落、复杂表格和太多图片,在不同邮箱客户端里容易出现差异。技术周刊可以把详细代码留在网站,邮件解释这周值得读什么,避免把整篇终端教程塞进收件箱。
模板文档列出了邮件模板变量与内置函数。退订链接应使用系统提供的机制,不要自行拼接一个看起来相似的 URL。换模板之后,再发送一封测试邮件,确认每个变量都已经替换,没有把模板表达式直接发给读者。
至少检查桌面邮箱和手机邮箱两种环境。看标题是否被截断,正文是否能直接读,图片不可用时是否还能理解内容,退订按钮是否找得到。第一封正式邮件也不应夹带“测试一下能不能收到”的内容;内部测试列表正是为这种工作准备的。
打开率可以辅助观察,但不能直接解释为读者认真读完的比例。邮箱客户端可能阻止图片加载,也可能提前获取图片。与其围绕一个看似精确的百分比做判断,不如同时看读者回复、退订变化和文章实际反馈。
SMTP 接受邮件之后,还会发生什么
应用显示发送完成,通常只说明这一批发送操作已经完成。对方邮箱可能后来拒收,也可能把邮件放进垃圾箱。排查时把活动日志、SMTP 返回结果、退信和收件箱观察放在一起,不要只盯着“已发送”计数。
listmonk 的退信处理支持 POP3 邮箱扫描和多种服务的 Webhook。采用哪种方式取决于你的发送渠道。SMTP 服务如果会自动改写 Return-Path,不能只在应用里填一个邮箱就假定退信一定到那里;先用测试收件地址确认实际回传路径。
退信策略从保守设置开始。偶发的邮箱满额与地址永久不存在,需要不同的后续处理。启用自动屏蔽或删除之前,先看几条事件是否与真实邮件一致。通知入口的凭据也要限制权限,不能把它当作不重要的公开接口。
每期发送之前扫一眼上一期的异常,比隔半年整理一次名单更省事。发现持续失败的地址,就按既定策略停止发送;读者已经退订,下一次导入也不能把状态覆盖成正常订阅。
从第一百个订阅者开始,保留一份简短发刊记录
每期记录发送时间、目标列表、主题、异常情况和处理结果就够了。目的是下一次遇到问题时能比较:这次是否换了模板,是否扩大了名单,是否更换 SMTP,是否同一邮箱域名集中退信。不要只保存“成功发送多少封”一个数字。
名单分组也应围绕真实用途。例如正式周刊和产品更新是两种订阅意图,不能因为同一个人订阅了周刊,就默认他也接受另一类消息。一次活动选择多个列表之前,检查是否存在交叉订阅与相应发送逻辑,避免重复或意外扩大范围。
如果准备从旧工具迁移,先导入少量自己控制的地址,覆盖已确认、未确认和已退订三种状态,再核对映射。历史退订状态丢失后,下一期可能重新向拒绝接收的人发信。源系统的记录应保留到迁移核对完成,不能看到 CSV 导入成功就立即删除。
停刊一段时间后恢复发送,也值得重新检查名单和内容说明。告诉读者这封邮件的用途,保持原有订阅主题,退订入口继续可用。长期没有互动的地址可能已经失效,发送规模逐步恢复时观察退信与投诉信息,比一次性向全部旧地址发送更容易定位问题。
备份必须包含图片和配置
数据库里有名单、列表、活动和状态,上传目录里还可能有邮件使用的图片。只备份数据库,恢复后历史邮件的图片地址可能失效;只保存 CSV 名单,又丢掉了退订状态和发送记录。
单机小规模部署可以在停止应用写入期间做一份逻辑备份:
cd ~/listmonk
umask 077
mkdir -p backups
docker compose stop app
docker compose exec -T db pg_dump -U listmonk -Fc listmonk \
> backups/listmonk.dump
tar -czf backups/uploads.tar.gz uploads
docker compose start app
命令中的数据库用户和库名按自己的配置修改。执行后检查两个命令的退出状态和备份文件,再把备份复制到独立存储,另行保存 Compose、SMTP 设置及恢复需要的凭据。失败时不要删除刚得到的文件,应确认哪个步骤没完成。
恢复演练用单独的数据库和测试域名。先禁用真实发送渠道,防止恢复后误把旧活动重新发出去;再检查订阅状态、退订页面、模板图片和后台权限。能够打开恢复出来的后台,只完成了其中一项。
更新之前阅读升级说明,保存应用版本和数据库备份。若迁移已经执行,出问题后简单换回旧镜像未必足够。周刊正常运转以后,最值得固定下来的习惯是每次发刊前内部试读、发刊后看退信、升级前做可恢复的备份。这样一份邮件列表才不会随着订阅人数增加,出现问题却缺少可追溯的记录。











