运维手册

通过 IMAP 接收邮件:将邮箱用作应用输入接口

作者:Alexey Bulygin
邮件从投递口直接进入一台小型处理设备

电子邮件是每个组织都已经具备的集成渠道。供应商用它发送发票,表单用它提交数据,机器用它发出告警。邮件接入把这些邮件视为接口,而不是日常负担。脚本连接邮箱,读取新到邮件,再根据内容执行相应操作。

这是一种历史悠久但常被低估的模式,因为另一种选择通常并不存在。你很难要求每个合作方都接入自己的 API。本文将介绍它适合哪些任务,如何构建才不容易失效,以及哪些情况下 Webhook 确实是更好的选择。

通过 IMAP 接收邮件适合哪些任务

只要发件方不愿或无法与你的系统直接集成,邮件接入就有实际价值。

合作方发送的文件。发票、采购订单、送货单和对账单以附件形式到达,而发送这些文件的组织永远不会专门对接你的系统。脚本按发件方和业务编号归档文件,往往就是所需的全部集成。

设备告警。很多硬件只能发送电子邮件,例如备份设备、监控系统和老旧工业设备。通过 IMAP 接收邮件,可以为这些设备提供统一的采集入口。

表单提交和回复。任何通过邮件发送结构化内容的系统都适用,包括需要自动处理的退信通知和外出自动回复。

通过回复完成审批。用户回复一封邮件并写下“同意”,就可以构成工作流中的一个步骤。用程序读取这封回复,通常比开发一个没人愿意登录的界面更简单。

如何设置才能长期可靠运行

接收邮件的技术本身并不复杂,能否持久可靠取决于几项设计决策。

使用专用邮箱。不要使用某个人邮箱中的文件夹,也不要与人工阅读相同邮件的用户共用邮箱。独立地址可以防止有人整理邮件时破坏脚本所依赖的状态。在 TrekMail,这不会增加成本,因为邮箱不按用户收费。

使用仅限当前任务的凭据。不要使用员工个人的登录信息。如果脚本凭据泄露或需要轮换,影响范围应仅限这个脚本。

移动已处理邮件,不要删除。建立“已处理”文件夹,既能保留审计记录,也能在修复缺陷后重新处理。删除会让每一次错误都无法挽回,而错误一定会发生。

正确处理重复到达的同一封邮件。重试、重新连接和重新处理都会出现。以 Message-ID 作为唯一键,跳过已经见过的邮件,就能让重复输入不执行任何操作,而不是造成数据问题。

让故障明确发出告警。脚本停止读取邮箱后,通常要等到有人追问发票去了哪里才会被发现。系统不仅应在报错时通知,还应在脚本长时间未运行时主动告警。

为什么 IMAP 适合这项工作

邮件接入采用 IMAP,因为 IMAP 相当于邮件的远程文件系统,而不仅仅是下载协议。

脚本可以在服务器端搜索,先读取邮件标头,再决定是否下载正文,还能在文件夹之间移动邮件并设置标记。整个过程无需下载完整邮箱。这样既能选择性处理,也能降低资源消耗,对于保留了多年历史邮件的邮箱尤其重要。

真正关键的优势是 IMAP 几乎无处不在。每种编程语言都有相应库,协议不会以破坏兼容性的方式频繁变化,今天编写的脚本十年后仍可继续运行。大多数厂商 API 都无法提供同等保障。

还应知道,免费套餐包含 IMAP,因此只用于接收数据的邮箱完全免费。但免费套餐不能发信,如果程序需要自动回复,就必须使用付费套餐或单独的 SMTP 配置

运行成本

成本往往令人意外,因为它比大多数人的预期低得多。

用于接收数据的邮箱就是普通邮箱,而邮箱数量由套餐等级限制,不会逐个收费。因此,增加第十二个接入地址的边际成本为零。正因如此,为每个来源设置独立邮箱才是实用方案,而不是浪费。真正消耗的是共享存储空间,以及发生故障时所需的维护精力。

与按用户收费的平台相比,这会改变架构上的取舍。在那些平台中,每个新邮箱都会增加费用,所以不同邮件流经常被塞进同一个超负荷地址,脚本还要从中拆分多个互不相关的来源。在这里,成本最低的方案恰好也是最清晰的方案。

何时应使用 Webhook

明确两者的适用边界,可以避免搭建错误的系统。

如果合作方提供 Webhook,就应该使用。主动推送在延迟、可靠性和清晰度方面都优于轮询。事件发生时便会收到结构化数据,无需等到下一次轮询才发现,也不用解析自然语言。只有在不存在这种选项时,才应将邮件接入作为替代方案。

轮询频率也有下限。每分钟检查一次没有问题,每秒检查一次则属于滥用,很快会受到频率限制。如果确实要求实时响应,无论采用何种读取方式,电子邮件都不是合适的传输渠道。

解析人工撰写的邮件同样不可靠。从机器生成的消息中提取采购订单号可以稳定实现,从用户输入的一段文字中判断真实意图却做不到。让工作流依赖这种判断,会持续产生少量但无法彻底消除的失败。

从一个邮箱扩展到多个邮箱

邮件接入很容易扩展,具体架构取决于需要处理多少条邮件流。

来源不多时,每个来源使用一个邮箱最清楚。每个脚本只读取自己的地址,一个来源的改动不会影响其他来源。由于邮箱按套餐限制数量,而不是逐个收费,二十个接入地址与一个地址的价格相同。

如果同类来源很多,最好在单个邮箱前设置 catch-all 地址。invoice-acme@invoice-globex@ 等地址都把邮件送到同一个邮箱,地址本身则携带脚本所需的路由信息。这与每次注册使用一个别名采用相同技巧,只是将它用于机器而不是供应商。

如果邮件量确实很大,请记住存储空间由所有邮箱共享。接入邮箱不断累积附件,会持续消耗共享容量。因此,应在设计中预先加入配额和保留策略,而不是日后才发现问题。具体设置见邮箱存储配额

分享这篇文章

我们使用运行和保护 TrekMail 所必需的技术。确认后还会允许《Cookie 政策》中所述的有限分析和广告衡量。

登录 TrekMail

访问您的控制面板、邮箱和 DNS。

12 个字符 两次密码一致

重置邮件已发送

如果该邮箱对应已有账户,我们已发送密码重置说明。

继续即表示您同意 TrekMail 的 服务条款隐私政策.