2026-10-26·by 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 的。

about this entry

One of sijie's wiki entries. The AI on this site is grounded in the same corpus and answers in sijie's voice, with citations back to entries like this one — answering costs sijie money, so it waits behind a code: enter an access code →