2026-10-26·作者 Sijie Wang#debug#keepalive#nat#smtp

appwrite-smtp-keepalive-debug

Appwrite SMTP 丢件:复用连接,没有探活

现象。 Appwrite 的 SMTP 间歇性丢件:有的信就是到不了,没有固定规律。

日志。 日志里看到发送失败,于是顺着往源码查。

agent 读源码。 coding agent 读了 Appwrite 1.9.9 的源码,一路追到机制。

机制。 邮件 worker 是常驻的 Swoole 进程。项目没配 SMTP 时,走注册的 adapter($register->get('smtp')),是个单例,keepAlive: true(app/init/registers.php)。messaging 1.2.0 的 SMTP adapter 包的是 PHPMailer 6.9.1,keepAlive 一开就跨发送复用同一个 PHPMailer 实例。复用之前没有任何探活。PHPMailer 只有读到 EOF 才认连接已死,所以服务端闲置断开的连接,在下一封真正发之前看起来还是活的。

对照。 项目自配 SMTP 每次新建 adapter,不受影响。两路的 keepAlive 都是 true,差别在复用,不在 flag。

发现。 这个机制没有 probe:复用的连接在下一封之前从不探活,这条路上也没有重试。追踪到这儿为止。

再连一个:五分钟是从哪来的? 这次的五分钟是 Mailpit 的 SMTP 超时:这套部署的 SMTP 服务就是 Mailpit,它的 SMTP 闲置超时把连接断了。NAT 还是连着的相关概念:NAT 映射闲置会过期(how-nat-works),而应用心跳本来就兼职续 NAT 账行(keepalive-two-layers)。闲置超时是同一类机制,但这一次的五分钟是 Mailpit 的。

关于这一条

sijie 的一条 wiki 条目。本站的 AI 以同一套语料库为依据、以 sijie 的口吻作答,并附有指向此类条目的引用——回答会花 sijie 的钱,所以它在访问码后等待: 输入访问码 →