资讯详情

listmonk 事务邮件 API 完全指南:用 POST /api/tx 发送订单确认、密码重置等即时邮件

📅 2026/9/12 11:47:52 | 华诺云谱 👁 阅读
listmonk 事务邮件 API 完全指南:用 POST /api/tx 发送订单确认、密码重置等即时邮件
listmonk 事务邮件 API 完全指南用 POST /api/tx 发送订单确认、密码重置等即时邮件【免费下载链接】listmonkHigh performance, self-hosted, newsletter and mailing list manager with a modern dashboard. Single binary app.项目地址: https://gitcode.com/GitHub_Trending/li/listmonk导读listmonk 的**事务邮件Transactional Messages**是区别于定时新闻通讯Campaign的另一类邮件它面向单个或多个收件人即时发送例如注册欢迎信、订单确认、密码重置、验证码通知等由系统事件触发的邮件。本文基于 listmonk 官方 API 文档transactional.md结合仓库中的 Go 源码cmd/tx.go、models/messages.go与示例模板sample-tx.tpl完整讲解POST /api/tx端点的全部参数、三种订阅者解析模式、模板数据注入、文件附件上传方式以及认证与权限要求。读完本文你将能直接编写出可运行的 curl 或脚本调用把 listmonk 集成为业务系统的事务邮件发送服务。1. 端点总览一次调用即时投递事务邮件 API 仅有一个端点MethodEndpointDescriptionPOST/api/txSend transactional messages该端点允许通过一个预先配置好的事务模板向一个或多个订阅者发送事务消息transactional.md。与需要创建 Campaign 并排队分发的批量邮件不同事务邮件是同步调用请求到达后listmonk 立即为每个收件人渲染模板、组装消息并推入发送管道。从路由注册可以看到该端点位于经过认证的私有 API 分组内并受tx:send权限保护cmd/handlers.gog.POST(/api/tx, pm(a.SendTxMessage, tx:send))1.1 认证方式与 listmonk 其余 API 一致/api/tx支持两种认证详见 apis.mdBasicAuthcurl -u api_user:token http://localhost:9000/api/tx ...Authorization 头curl -H Authorization: token api_user:token http://localhost:9000/api/tx ...API 用户及其 token 需在管理后台 Admin - Users 中创建并在该用户角色中勾选tx:send权限该权限归属于 subscribers 权限组见 permissions.json 与 roles-and-permissions.md。2. 请求参数详解请求体为 JSON字段如下完整继承自官方文档参数表NameTypeRequiredDescriptionsubscriber_emailstring订阅者的 Email可用subscriber_id替代。subscriber_idnumber订阅者 ID可用subscriber_email替代。subscriber_emailsstring[]多个订阅者 Email作为subscriber_email的替代。subscriber_idsnumber[]多个订阅者 ID作为subscriber_id的替代。subscriber_modestring订阅者解析模式default、fallback或external。template_idnumberYes用于生成消息的事务模板 ID。from_emailstring可选发件人地址。留空时使用实例默认发件人。subjectstring可选主题。留空则使用模板中定义的主题。dataJSON可选嵌套 JSON map在模板中以{{ .Tx.Data.* }}访问。headersJSON[]可选邮件头数组。messengerstring发送消息的 Messenger默认为email。content_typestring邮件格式选项html、markdown、plain。altbodystring可选纯文本备用正文用于 multipart HTML 邮件。2.1 参数之间的互斥与默认值源码中的校验函数validateTxMessagecmd/tx.go揭示了文档未明说但实际生效的规则subscriber_email与subscriber_emails不能同时出现subscriber_id与subscriber_ids同理。若同时提供请求会被拒绝。单数形式的subscriber_email/subscriber_id会被自动追加进对应的复数数组参与后续处理即它们本质上是复数参数的语法糖。subscriber_mode留空时默认取default。from_email留空时回退到实例配置a.cfg.FromEmail。messenger留空时默认使用emailMessenger若指定了不存在的 Messenger返回 400 错误。所有 Email 会经过importer.SanitizeEmail清洗校验非法地址直接导致请求失败。解析收件人时Email 优先于 ID只要subscriber_ids非空即以 ID 查询cmd/tx.go。3. 三种订阅者解析模式subscriber_modesubscriber_mode决定收件人是如何被解析的。官方文档定义了三种模式ModeDescriptiondefault收件人必须已作为订阅者存在于数据库中。传入subscriber_emails或subscriber_ids二者之一。fallback只接受subscriber_emails先在数据库中查找订阅者若未找到仍将邮件发送到该地址。此时模板中除{{ .Subscriber.Email }}外其他订阅者字段如.Name为空请改用{{ Tx.Data.* }}。external直接向给定的subscriber_emails发送不做数据库订阅者查询。模板中除{{ .Subscriber.Email }}外其他订阅者字段如.Name为空请改用{{ Tx.Data.* }}。三种模式的常量定义位于 models/messages.goconst ( TxSubModeDefault default TxSubModeFallback fallback TxSubModeExternal external )3.1 各模式的源码行为差异在SendTxMessage的收件人循环中cmd/tx.go三种模式的实现差异清晰可见external直接构造一个只含 Email 的临时订阅者ephemeral subscriber完全跳过数据库查询if m.SubscriberMode models.TxSubModeExternal { // external: Always create an ephemeral subscriber and dont // lookup in the DB. sub models.Subscriber{ Email: m.SubscriberEmails[n], } }default/fallback都会调用a.core.GetSubscriber(subID, , subEmail)查询数据库。查询失败时fallback模式会退化为临时订阅者继续发送default模式则记录notFound并跳过该收件人最后若存在未找到的订阅者整个请求返回 400并附上所有未找到项的拼接信息cmd/tx.go。校验层还保证了fallback和external模式禁止使用subscriber_ids因为 ID 查询本身就需要数据库中存在该订阅者且必须提供subscriber_emailscmd/tx.go。4. 完整调用示例4.1 基础示例按 Email 发送向数据库中的订阅者usertest.com发送模板 ID 为 2 的事务邮件并注入订单数据完整继承自官方文档示例curl -u api_user:token http://localhost:9000/api/tx -X POST \ -H Content-Type: application/json; charsetutf-8 \ --data-binary - EOF { subscriber_email: usertest.com, template_id: 2, data: {order_id: 1234, date: 2022-07-30, items: [1, 2, 3]}, content_type: html } EOF4.2 响应格式发送成功后返回 JSON 布尔值{ data: true }失败时返回对应的 4xx/5xx 状态码与错误信息例如模板不存在返回 400a.manager.GetTpl找不到模板时default模式下订阅者未找到也返回 400 并列出原因。更完整的 HTTP 错误码约定400/403/404/405/410/422/429/500 等见 apis.md。4.3 external 模式示例发给非订阅者不要求收件人存在于订阅者库中适合验证码、通知等场景curl -u api_user:token http://localhost:9000/api/tx -X POST \ -H Content-Type: application/json; charsetutf-8 \ --data-binary - EOF { subscriber_mode: external, subscriber_emails: [recipientexample.com], template_id: 2, data: {name: John, order_id: 1234}, content_type: html } EOF5. 模板中的数据访问{{ .Tx.Data.* }} 与订阅者字段事务模板与 Campaign 模板一样支持 Go 模板表达式详见 templating.md。在事务邮件中模板可用的数据根对象为data : struct { Subscriber Subscriber Tx *TxMessage }{sub, m}这一结构定义在TxMessage.Render方法中models/messages.go它说明了模板里两棵数据树的来源{{ .Subscriber.* }}收件人信息如{{ .Subscriber.Email }}、{{ .Subscriber.Name }}、{{ .Subscriber.FirstName }}、{{ .Subscriber.LastName }}、{{ .Subscriber.UUID }}、{{ .Subscriber.Attribs.city }}等。注意在fallback/external模式下由于收件人不是数据库订阅者除 Email 外这些字段均为空。{{ .Tx.Data.* }}请求中data参数注入的自定义数据。官方文档明确在模板中使用{{ .Tx.Data.name }}、{{ .Tx.Data.order_id }}等访问数据transactional.md。5.1 官方内置示例模板仓库自带的 sample-tx.tpl 是事务模板的标准示范其中同时使用了订阅者字段与事务数据pHello {{ .Subscriber.Name }}/p p strongOrder number: /strong {{ .Tx.Data.order_id }}br / strongShipping date: /strong {{ .Tx.Data.shipping_date }}br / /p该模板强调事务模板支持任意参数使用.Tx.Data.YourParamName渲染它们。因此一个典型的订单确认邮件可以这样设计业务系统调用/api/tx时传入data模板负责把{{ .Tx.Data.order_id }}、{{ .Tx.Data.shipping_date }}渲染到邮件正文。5.2 主题与 altbody 的模板化Render方法还处理了主题和纯文本备用正文models/messages.go主题请求的subject非空时优先使用若其中含{{ }}表达式则先渲染否则回退到模板定义的主题tpl.Subject。altbodyaltbody字符串若包含模板表达式也会作为 Go text/template 渲染后再作为 multipart HTML 邮件的纯文本部分发出。这意味着你可以在subject中写Order {{ .Tx.Data.order_id }} confirmation让主题也随数据动态变化。6. 文件附件multipart/form-data 上传事务邮件支持附带任意数量的文件附件。调用时需改用multipart/form-data编码所有上文提到的 JSON 参数整体放入一个名为data的表单字段值为 JSON 字符串每个附件通过名为file的表单字段上传可重复出现多次。官方示例完整继承自 transactional.mdcurl -u api_user:token http://localhost:9000/api/tx -X POST \ -F data{ \subscriber_email\: \usertest.com\, \template_id\: 4 } \ -F file/path/to/attachment.pdf \ -F file/path/to/attachment2.pdf6.1 附件的源码处理链路SendTxMessage首先根据Content-Type判断是否为 multipartcmd/tx.goif strings.HasPrefix(c.Request().Header.Get(Content-Type), multipart/form-data) { form, err : c.MultipartForm() ... // Parse the JSON data. if err : json.Unmarshal([]byte(data[0]), m); err ! nil { ... } // Attach files. for _, f : range form.File[file] { ... m.Attachments append(m.Attachments, models.Attachment{ Name: f.Filename, Header: manager.MakeAttachmentHeader(f.Filename, base64, f.Header.Get(Content-Type)), Content: b, }) } } else if err : c.Bind(m); err ! nil { ... }两点值得注意data表单字段必须恰好出现一次且为合法 JSON否则返回 400附件会与模板自身的附件tpl.Attachments合并后再推入发送管道cmd/tx.go因此模板中预先挂载的附件同样会随每封事务邮件发出。7. 发送链路从请求到出站理解完整调用链有助于排障。一次/api/tx请求的处理流程cmd/tx.go解析按 Content-Type 区分 JSON 绑定或 multipart 解析校验validateTxMessage检查字段互斥、模式合法性、Email 清洗并填充from_email/messenger默认值取模板a.manager.GetTpl(m.TemplateID)从缓存读取已编译的事务模板失败返回 400 template {id} not found解析收件人按subscriber_mode查询订阅者或构造临时订阅者default模式未找到时记录并跳过渲染m.Render(sub, tpl, a.manager.GenericTemplateFuncs())渲染正文、altbody 与主题组装消息构造models.Message附加请求头headers逐条写入 MIMEHeader与附件投递a.manager.PushMessage(msg)将消息推入 messenger默认 email的发送队列返回全部收件人处理完毕后返回{data: true}若default模式存在未找到的订阅者则返回 400 及错误汇总。值得注意的是PushMessage是异步队列投递——API 返回成功仅代表消息已成功入队实际投递由后台 messenger worker 完成消息渲染与入队阶段的错误模板语法错误、Messenger 不可用等则会在请求内直接报错返回。8. 与 Campaign 邮件的关键区别维度事务邮件/api/txCampaign 邮件触发方式业务系统实时调用 API后台按计划或手动发送收件人单个/多个订阅者或任意外部 Emailexternal通过查询Query筛选的订阅者列表追踪/退订无 Campaign 式追踪像素与退订链接如需请自行在模板中添加内置 TrackLink、TrackView、UnsubscribeURL模板类型事务模板Transactional templateCampaign 模板权限tx:sendcampaigns:*系列权限事务模板与 Campaign 模板在管理后台Campaigns - Templates中统一创建与管理templating.md区别在于事务模板被/api/tx引用时按{{ .Tx.* }}上下文渲染。两者的预览逻辑在 cmd/templates.go 中分开处理事务模板使用TxMessage.Render配合虚拟订阅者生成预览。9. 典型集成场景与注意事项适用场景concepts.md 中对事务消息的定义注册欢迎信、购买订单确认、密码重置、账号恢复等由事件触发的即时邮件。实践建议业务系统只需维护模板 ID 与data参数契约收件人既可复用订阅者库default也可直接投递外部地址external大量非订阅者收件人优先使用external模式省去每次请求的数据库查询在fallback/external模式下模板设计应避免依赖.Subscriber.Name等字段全部个性化数据经.Tx.Data.*传入附带 PDF、发票等文件时改用 multipart 请求file字段可重复为调用方分配专用 API 用户仅授予tx:send权限实现最小权限隔离roles-and-permissions.md。事务邮件 API 是 listmonk 作为程序化邮件发送服务对外输出的核心通道配合事务模板的 Go 模板能力可以完全承接业务系统中的各类即时通知需求。【免费下载链接】listmonkHigh performance, self-hosted, newsletter and mailing list manager with a modern dashboard. Single binary app.项目地址: https://gitcode.com/GitHub_Trending/li/listmonk创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。