发票逾期催收邮件模板与Python自动化发送实战指南
做 B2B 业务或者维护企业内部财务系统的开发者,大概率会遇到一个躲不掉的需求:客户的发票逾期未付,财务同事需要催款,然后找到你,问能不能“写个邮件模板自动发一下”。
这个需求听起来很简单。很多人第一反应是去搜索引擎找几封英文的 invoice reminder email template,复制粘贴,替换掉客户名、金额、日期,然后手动发给客户。但这样做的结果往往很现实:客户根本不理,邮件进了垃圾箱,甚至因为措辞不当把客户关系弄僵。问题不是邮件模板本身,而是模板背后的逻辑太粗糙。
我在这篇文章里想给出的判断是:逾期发票催收邮件不是“复制粘贴”这么简单,真正能提升回款率的模板,至少要满足三件事——分级策略、字段变量化、自动化触达。只抄几封模板解决不了问题,但如果你能把模板从静态文本改造成可以渲染、可以批量发送、可以记录日志的最小工程,效果会完全不一样。
文章会提供可直接复制使用的中文催收邮件模板,然后带你用 Python 标准库把模板改造成一个小型自动化发送脚本。整个过程不需要复杂框架,也不强行引入重量级中间件,适合普通后端开发快速落地。
1. 为什么“复制粘贴”式催收邮件容易失效
先看一个常见的催收场景。某企业有 200 个客户,其中 20 个应收账款逾期超过 30 天。财务希望技术侧开发一个催收功能,但需求并不清晰,只是说“你帮我发封邮件提醒一下”。
大多数人会怎么做?把 Excel 导出来,手写邮件正文,然后一封一封发。这里面有几个很实际的问题:
第一,没有分级。所有客户收到的都是同一封邮件,不管是刚逾期 3 天还是逾期 90 天。客户团队的负责人扫一眼就知道这是“群发模板”,回复率和付款意愿自然不高。
第二,字段写死。邮件正文里写“您好,您有一笔 5000 元发票逾期未付”,可下一张发票变成 6800 元时,你又要重新改文案。一旦客户数量多、发票数量多,这种维护方式很快失控。
第三,没有行动入口。很多催收邮件只写了“请尽快付款”,却没有附上付款链接、对账单、公司收款账户信息,客户看到后还要再找财务核对,转化路径极长。
第四,没有发送记录。你到底给谁发过、发了什么内容、对方是否打开,这些信息完全靠 Excel 和邮件客户端手工记录。下次再催收时,你根本不知道上一次沟通到了什么程度。
所以,催收邮件的核心问题不是措辞好不好,而是它没有被当成一个工程问题来设计。真正有效的方案,应该是把模板按照逾期阶段拆分,把客户信息作为变量动态填充,再结合定时任务或财务系统事件自动触发发送,同时记录每一次发送状态。
2. 催收邮件的分级策略与模板设计原则
在写模板之前,先建立一套简单的分级规则。不要把“催收”当成一个动作,而是当成一条有梯度的沟通链路。
| 分级 | 触发条件 | 措辞基调 | 沟通目标 |
|---|---|---|---|
| 到期前提醒 | 发票到期前 3-7 天 | 温和、友好 | 提醒付款,避免逾期 |
| 逾期早期催收 | 逾期 1-7 天 | 礼貌、清晰 | 请对方确认付款时间 |
| 逾期中期催收 | 逾期 8-30 天 | 正式、坚定 | 推动对方优先处理 |
| 逾期长期通知 | 逾期 30 天以上 | 严肃、克制 | 明确后果,要求限期处理 |
分级的好处是可以避免一个常见误区:对所有欠款客户都发送同等强度的催促邮件。刚逾期 3 天的客户可能只是内部流程没走完,收到措辞强硬的邮件反而会引起反感;逾期 90 天的客户如果只收到一封“温馨提醒”,又起不到任何作用。
模板设计上有几个原则需要坚持:
- 主题行要让客户第一时间知道是哪家公司、哪张发票、涉及多少金额。不要写“催款通知”这种模糊标题,客户可能同时欠很多供应商的钱,模糊标题缺少做事优先级。
- 称呼必须个性化。邮件正文中要明确出现客户的联系人姓名和公司名称,而不是“尊敬的客户”这种明显群发痕迹。
- 金额、日期、逾期天数必须来自系统数据,不能写死在模板里。
- 每封邮件都要给出明确的下一步动作:是点击付款链接,还是回复邮件确认付款日期,或者是联系某个负责人的电话和邮箱。
- 措辞保持克制,不要威胁,不要侮辱,不要使用“你已经严重违约”“将立即起诉”等没有依据的表述。按照实际合同条款和公司规定来写。
另外需要提醒一句:不同地区和行业的催收要求不一样,落地前建议让法务或财务负责人审核一遍。本文提供的模板只是一般性商务沟通参考。
3. 可直接复制使用的催收邮件模板
下面提供四套模板,分别对应到期前、逾期早期、逾期中期和逾期长期。模板中使用 {变量} 作为占位符,实际发送前需要替换成真实数据。
3.1 到期前提醒模板
适用场景:发票还未逾期,在到期前 3-5 天发送,帮助客户不要遗漏付款安排。
这个模板的关键是不要把“催收”写得太有压迫感。它的目标是提前确认信息,让对方在付款计划中给这张发票排上队。
3.2 逾期早期催收模板
适用场景:发票已逾期 1-7 天,适合友好提醒,并给对方一个解释或确认延期的机会。
逾期早期模板最重要的是给出沟通出口。很多客户不是恶意拖欠,而是内部流程没有走完。这时一封态度友好的邮件反而更容易获得一个明确答复。
3.3 逾期中期催收模板
适用场景:发票逾期 8-30 天,措辞需要更正式,明确表达希望对方尽快安排付款。
逾期中期模板要传递两个信息:这笔款很重要,以及我们愿意沟通。措辞可以正式,但不要开始威胁,因为还有协商空间。
3.4 逾期长期通知模板
适用场景:发票逾期超过 30 天,且之前已经有过多次催收记录。这封邮件应保守使用,建议发送前由财务或管理人员确认。
长期通知模板要克制。它写的是“进一步处理措施”,而不是直接写“我们将起诉你”。具体能做什么、不能做什么,取决于合同条款和公司内部制度,不能靠模板随意发挥。
4. 把模板变成可维护的邮件模板工程
有了模板,下一步是把它从“一段文本”变成“程序可以渲染的模板”。
如果只是把模板放在 Word 或文本文件里,依然需要人工打开、复制、替换,效率提升有限。更合理的做法是把模板当成代码资源,把客户和发票数据单独存放,发送时用程序自动渲染。
首先准备一个客户数据文件。这里可以使用 JSON 存储,方便后续接入数据库或 API:
这里要注意一个容易被忽略的细节:金额字段不要直接使用浮点数做字符串拼接。财务场景下金额精度非常重要,建议在数据源统一使用精确数值,渲染时统一格式化到两位小数。
接着写一个简单的渲染脚本,把 JSON 中的字段填入模板:
这个脚本把数据准备、模板渲染、正文输出三个环节解耦了。后续只要维护 JSON 数据源和模板文件,不需要每次改动都动代码。
模板文件放在 templates/ 目录下,命名规则建议按照催收等级划分,例如 reminder_before_due.txt、overdue_7.txt、overdue_30.txt、overdue_90.txt,方便后续与代码一起做版本管理。
5. 环境准备与自动化发送实现
渲染模板只是第一步,真正让模板发挥作用的是“自动发出去”。
5.1 技术选型判断
邮件发送有几种常见路径:
- 直接用 SMTP 协议通过企业邮箱发信;
- 调用第三方邮件服务商的发送 API;
- 在 CRM、财务系统或低代码平台里配置邮件工作流。
如果项目还不存在,只是想快速验证自动化流程,直接用 Python 标准库 smtplib 是最轻量的选择。不需要安装额外依赖,代码量也很小。如果后续邮件量很大,或者对送达率有更高要求,再切换到邮件服务商的 API。
本文示例使用 Python 3 编写,运行环境可以是 Linux、macOS 或 Windows。版本以你本机实际安装为准,核心语法不依赖较新的特性。
5.2 最小发送函数
下面是一个基于 SMTP 的发送函数:
关键点有三个:
- SMTP 用户名和密码不要硬编码在代码里,从环境变量读取,避免密钥泄露。
- 端口 465 使用 SSL 连接,端口 587 使用 STARTTLS 连接,需要根据邮箱服务商配置调整。
- 正文使用纯文本时,用
MIMEText(body, "plain", "utf-8");做 HTML 模板时则可以改成"html"。
5.3 批量循环发送
把模板渲染和发送函数组合起来,就是一个最小可用的批量催收脚本:
运行前设置环境变量:
注意:很多邮箱服务商要求使用“授权码”而不是登录密码来登录 SMTP,这一点在调试时最容易卡住。如果登录失败,先检查邮箱设置里是否开启了 SMTP 服务,以及是否使用了正确的授权码。
5.4 触发策略
脚本写好后,怎么把它接入业务流?
比较简单的做法是在财务系统或 ERP 的发票模块增加一个定时任务,每天扫描一次逾期发票,自动生成催收任务。也可以用系统 cron 表达式每天执行一次脚本,脚本内部只处理处于某个逾期阶段且未发送过提醒的发票。
更推荐的做法是在脚本执行前查询数据库或业务系统的 API,而不是手工维护 clients.json。这样可以保证每次发送的数据都是最新的。
但要注意,生产环境建议先进入“测试模式”。可以在配置里增加一个 DRY_RUN 开关,开启后只渲染正文、记录日志,不真正发信。等确认模板和数据无误后,再关闭该开关。
6. 运行验证与效果判断
自动化催收脚本上线前,必须经过三轮验证:字段验证、发送验证、业务指标验证。
第一轮,字段验证。用 DRY_RUN 模式跑一遍,打印渲染后的正文,人工检查金额、日期、发票号、联系人名称是否正确。这一步最容易发现的是金额精度问题和日期格式问题。不同财务系统的金额精度不一样,建议统一格式化为 {:,.2f} 两位小数。
第二轮,发送验证。把收件人改成自己的邮箱或者同事的邮箱,发送一封真实邮件,检查三件事:
- 是否进入收件箱而不是垃圾箱;
- 主题行是否完整;
- 正文是否存在没有替换成功的
{}占位符。
如果邮件进入垃圾箱,优先检查发信域名的 SPF 和 DKIM 配置。企业邮箱通常会提供 DNS 解析记录,需要在域名服务商处完成配置。这部分属于发信基础设施,和模板本身同等重要。
第三轮,业务指标验证。上线后重点关注四个数字:
- 退信率:如果出现大量退信,可能是客户邮箱失效或发信频率过高。
- 打开率:打开率很低,问题大多出在主题行和发件人名称。
- 回复率:回复率低,说明邮件给出的沟通出口不够直接。
- 回款率:这是最终指标,观察发送催收邮件后 7 天内的回款情况。
初期建议先选一部分客户做灰度,不要一次性把所有逾期客户都催一遍。等数据证明模板效果稳定后,再逐步扩大发送范围。
7. 常见问题与排查方法
在实际落地过程中,下面几个问题出现频率非常高。
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 邮件进入垃圾箱 | 发信域名未配置 SPF/DKIM | 查看退信头,检查 DNS 记录 | 配置 SPF、DKIM,并设置统一的发件人签名 |
正文出现 {invoice_no} 未替换 |
模板占位符与数据字段不匹配 | 以 DRY_RUN 模式打印完整正文 | 统一字段命名,渲染前校验所有占位符 |
| 金额显示为 12800.0 | 浮点数未格式化 | 检查 JSON 中的数值类型和渲染格式 | 使用 format(amount, ".2f") 或 Decimal |
| 同一客户被重复发送 | 没有记录发票发送状态 | 检查脚本日志或数据库记录 | 增加 sent_status 状态,按 invoice_no 防重 |
| 收件邮箱不存在导致退信 | 客户邮箱地址过期或输入错误 | 查看发送日志中的退信原因 | 定期清理客户联系方式,拦截无效邮箱 |
| 客户投诉或回复不再联系 | 措辞过强或缺少退订说明 | 查看客户回复与投诉记录 | 调整分级措辞,增加联系负责人信息 |
排查时有一个通用原则:先看日志,再看数据,最后看模板。大多数问题不是出在发送代码,而是出在模板渲染前的数据准备。
8. 最佳实践与工程建议
8.1 发票与客户数据字段要统一
催收脚本依赖的数据字段往往分散在多个系统里:客户名称在 CRM,发票金额在财务系统,联系人邮箱可能还要查企业通讯录。建议在脚本入口统一封装一份标准字段清单,减少模板和业务系统的强耦合。
我建议至少包含这些字段:contact_name、company_name、email、invoice_no、invoice_date、due_date、days_overdue、amount、payment_link、sender_name、sender_phone、sender_email。模板新增字段时,先在数据层补齐,再改模板。
8.2 用数据库记录发送状态
不要只依赖发信脚本的打印日志。生产环境建议增加一张发送记录表,至少记录 invoice_no、recipient_email、template_version、send_time、status、error_msg 这几个字段。
这样既能防止重复发送,也能在客户回款后快速追踪历史沟通记录。如果团队有现成的 CRM,可以直接复用 CRM 中的邮件记录功能。
8.3 模板要纳入版本管理
模板也是代码的一部分。每次修改模板文案,都应该走 Git 提交,记录变更原因。不要直接在服务器上改文本文件,否则下次发布时会被覆盖,而且无法追溯。
模板文件命名也要清晰,建议用这样的结构:
8.4 敏感信息与安全边界
催收邮件涉及客户名称、发票金额、联系人邮箱等敏感信息。脚本运行日志不要打印完整正文,尤其是不要打印客户金额和付款链接。线上环境建议对日志做脱敏处理,只记录收件人、发票号和发送结果。
发送账号的权限也要遵循最小权限原则。如果使用企业邮箱,发给这个 SMTP 账号的权限应只限制在发信范围内,不要同时授予通讯录导出、财务数据查看等权限。
8.5 发送频率与回滚机制
对同一客户,不要一天内发送多封催收邮件。建议设置冷却时间,比如同一发票至少间隔 7 天才能再次催收。如果模板或数据出现问题,要能快速暂停整个发送任务。实现方式可以是一个全局开关,脚本启动时检查该标志,如果为 false 则直接退出。
8.6 与财务系统对接时的注意事项
如果要把脚本接入现网财务系统,首先确认发票逾期状态由哪个字段决定,避免出现“已回款但账单状态未更新导致误催”的情况。其次,付款凭证和报销流程通常比邮件系统复杂,发送前建议和财务确认哪些客户需要跳过自动催收。最后,对接 API 时要处理限流和超时,邮件发送服务对频率往往有限制。
9. 总结与后续学习方向
这篇文章真正想说明白的一件事情是:逾期发票催收邮件看起来是文案问题,做起来却是模板分级、数据变量化和发送自动化三个层面的工程问题。
文中给出的四套模板可以直接复制使用,但更值得带走的是模板背后的思路:先按逾期阶段分级,再把客户与发票数据抽成变量,最后用 Python 标准库完成渲染与发送。这套思路不绑定任何框架,适用于企业内部财务系统、CRM、以及未来要做的回款看板。
如果你接下来想把功能做得更完整,可以从这几个方向继续深入:
- 把
clients.json替换成财务系统或数据库查询,按发票状态实时生成催收任务。 - 增加 PDF 对账单附件,让客户在邮件里直接查看账单明细。
- 记录发送日志并处理客户回复,形成“催收-回复-回款”的完整闭环。
- 如果邮件量变大,把 SMTP 发送切换到专业邮件服务商 API,并做好送达率监控。
这套模板和脚本可以先收藏,等到真有催收需求时,直接照抄再改造,能少走很多弯路。