ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

listmonk 核心概念全解:订阅者、列表、活动、模板与追踪机制的架构解析

listmonk 核心概念全解:订阅者、列表、活动、模板与追踪机制的架构解析 listmonk 核心概念全解订阅者、列表、活动、模板与追踪机制的架构解析【免费下载链接】listmonkHigh performance, self-hosted, newsletter and mailing list manager with a modern dashboard. Single binary app.项目地址: https://gitcode.com/GitHub_Trending/li/listmonk导读listmonk 是一个高性能、自托管的新闻通讯与邮件列表管理器。理解其核心领域模型订阅者 Subscriber、列表 List、活动 Campaign、模板 Template、Messenger、追踪像素与点击追踪、退信 Bounce是使用该工具、编写查询表达式以及进行二次开发的基础。本文以官方概念文档为骨架结合仓库内 models 目录 的 Go 源码与 schema.sql 数据库定义逐层拆解 listmonk 的领域概念、状态机、数据存储方式与隐私相关的追踪机制帮助你建立对系统全局的准确认知。Subscriber以邮箱为标识的收件人一个订阅者Subscriber是通过电子邮件地址 姓名来唯一标识的收件人所有由 listmonk 发出的邮件都发送给订阅者。订阅者可以同时被加入任意数量的列表List而那些不属于任何列表的订阅者被称为孤儿记录orphan records。在源码层面订阅者的结构定义在 models/subscribers.gotype Subscriber struct { Base UUID string db:uuid json:uuid Email string db:email json:email form:email Name string db:name json:name form:name Attribs JSON db:attribs json:attribs Status string db:status json:status Lists types.JSONText db:lists json:lists }可以看到订阅者核心字段包括系统生成的随机UUID、Email、Name、Attribs属性 JSON、Status状态以及Lists所属列表。订阅者本身的状态SubscriberStatusEnabled enabled、SubscriberStatusDisabled disabled、SubscriberStatusBlockListed blocklisted与订阅状态Subscription status是两个不同的概念前者描述订阅者账号本身的可用性后者描述订阅者与某个列表之间的关系下文会详细区分。Attributes订阅者的任意扩展属性**属性Attributes**是附加在订阅者身上、除邮箱和姓名之外的任意自定义属性以 JSON 键值对JSON map形式存储。listmonk 不要求所有订阅者拥有相同的属性集合每个订阅者都可以有自己独立的属性结构。属性承担两大职责作为**查询与细分querying and segmentation**的依据——基于属性将订阅者过滤进列表作为邮件模板变量——在发送邮件时被插入到邮件内容中。一个典型的属性 JSON 示例如下{ city: Bengaluru, likes_tea: true, spoken_languages: [English, Malayalam], projects: 3, stack: { frameworks: [echo, go], languages: [go, python], preferred_language: go } }该示例展示了属性支持的丰富数据类型字符串、布尔值、字符串数组、整数甚至嵌套的 JSON 对象。在数据库中属性存储为attribs字段PostgreSQL 的 JSON 类型允许通过 Postgres 的 JSONB 操作符进行任意深度的查询——详见 querying-and-segmentation.md。订阅状态Subscription statuses订阅者与列表的关系状态一个订阅者可以被加入一个或多个列表每一次订阅者—列表关联都拥有以下三种状态之一。这些状态常量定义在 models/subscribers.go状态说明unconfirmed订阅者被直接加入列表未经其明确确认。尽管如此该订阅者仍会收到**单重确认single opt-in**活动发来的消息。confirmed订阅者点击确认邮件中的接受链接完成了订阅确认。只有处于confirmed状态的订阅者才会收到发送给**双重确认double opt-in**列表的活动消息。unsubscribed订阅者已从该列表退订不会再收到任何发送给该列表的活动消息。这一关系模型的底层体现在Subscription结构体models/subscribers.go它将List与SubscriptionStatus、SubscriptionCreatedAt等元数据组合在一起说明订阅状态是挂在订阅关系而非订阅者本身上的。正因为一个订阅者可以同时以不同状态存在于多个列表中查询细分时才需要关注subscription_status这一维度。Segmentation按任意条件过滤订阅者**细分Segmentation**是将一个大型订阅者列表基于任意条件主要依据属性过滤为更小群体的过程。例如当需要给某个特定城市的订阅者发邮件时只要城市信息存在于属性中就可以快速筛选出这批订阅者、将其归入新列表并发送邮件。listmonk 的细分并不是封闭的查询语言而是直接允许编写局部的 Postgres SQL 表达式来查询和过滤订阅者可查询的数据库字段包括subscribers.uuid、subscribers.email、subscribers.name、subscribers.status、subscribers.attribs、subscribers.created_at、subscribers.updated_at等。典型用法如-- 按属性筛选住在 Bengaluru 且项目数大于 3 的订阅者 subscribers.attribs-city Bengaluru AND (subscribers.attribs-projects)::INT 3完整的字段表、操作符用法与示例表达式请参考 querying-and-segmentation.md。List按名称分组的邮件列表**列表List即邮件列表 mailing list**是订阅者的集合被赋予一个名称例如clients。列表用于组织订阅者并针对特定群体发送邮件。从 models/lists.go 的常量可以看到列表的几组关键属性const ( ListTypePrivate private ListTypePublic public ListOptinSingle single ListOptinDouble double ListStatusActive active ListStatusArchived archived )类型Typeprivate私有与public公开。公开列表会出现在面向订阅者的订阅页面上供用户自主选择订阅。确认机制Optinsingle单重确认或double双重确认。双重确认列表要求订阅者必须点击收到的确认邮件中的链接来明确接受订阅在此之前订阅者不会收到任何活动消息单重确认列表则没有这一前置门槛。状态Statusactive激活与archived归档。列表结构体models/lists.go还包含Tags标签、Description描述、SubscriberCount与按订阅状态拆分的SubscriberCounts等字段后者支撑了 UI 上对每个列表按 unconfirmed / confirmed / unsubscribed 统计人数的能力。Campaign发送到列表的邮件或任意消息**活动Campaign**是发送给一个或多个列表的一封邮件或其他类型的消息。从源码 models/campaigns.go 可以看到活动的核心分类维度const ( CampaignStatusDraft draft CampaignStatusScheduled scheduled CampaignStatusRunning running CampaignStatusPaused paused CampaignStatusFinished finished CampaignStatusCancelled cancelled CampaignTypeRegular regular CampaignTypeOptin optin CampaignContentTypeRichtext richtext CampaignContentTypeHTML html CampaignContentTypeMarkdown markdown CampaignContentTypePlain plain CampaignContentTypeVisual visual )活动类型Typeregular常规活动与optin确认订阅活动即从列表页发起、用于向未确认订阅者发送确认邮件的活动。生命周期状态Statusdraft草稿→scheduled已排期→running发送中→finished完成其间可paused暂停或cancelled取消。内容格式ContentType支持富文本richtext、HTML、Markdown、纯文本plain与可视化编辑visual五种格式。其中 Markdown 内容会在编译模板时被转换为 HTML见 models/campaigns.go。Campaign结构体还包含Subject、FromEmail、Body、AltBody纯文本备用正文、Headers自定义邮件头、TemplateID引用的模板、Messenger发送渠道、Archive是否归档到公开页面等字段以及用于跟踪发送进度的CampaignMetaViews、Clicks、Bounces、ToSend、Sent 等计数。Transactional message事务消息事务消息Transactional message是通过 listmonk 的事务消息 API发送给单个订阅者的任意消息。它区别于面向整个列表的 Campaign典型场景包括用户在服务注册时收到的欢迎邮件购买商品后收到的订单确认邮件用户发起账号找回流程时收到的密码重置邮件。事务消息基于**模板Template**渲染可插入订阅者字段与属性具体 API 用法参见 transactional.md。Template可复用的 HTML 设计**模板Template**是一种可复用的 HTML 设计可跨多个活动使用也可用于发送任意事务消息。最常见的模板形态是固定的页头header与页脚footer区域承载 Logo 和品牌元素活动内容插入在中间区域。listmonk 支持Go template 表达式如{{ .Subscriber.Email }}可以构建强大、动态的 HTML 模板并内置集成 100 个 Sprig 中注册实现。⚠️安全警告Sprig 模板函数功能强大且图灵完备允许在模板中编写复杂逻辑但同时也意味着可以编写出非预期行为——例如通过循环拼接大字符串来耗尽主机内存。因此模板campaigns、templates相关权限应只授予可信用户。模板分为三类活动模板Campaign templates用于邮件活动在 UI 的Campaigns - Templates下创建和管理创建新活动时选择事务模板Transactional templates用于通过事务 API 发送任意事务消息同样在Campaigns - Templates下管理系统模板System templates用于渲染面向用户的公开页面如订阅管理页与系统自动邮件如双重确认邮件。系统模板内置在 static 目录中可通过./listmonk --static-diryour/custom/path参数替换为自定义目录。模板表达式的完整字段表订阅者字段、活动字段、函数清单与示例请参考 templating.md。Messenger非邮件的自定义消息通道在默认的 SMTP 邮件通道之外listmonk 还支持多个自定义消息后端Messenger从而不仅支持邮件活动还能支持任意消息类型的活动例如 SMS、FCM 通知等。一个Messenger本质上是一个 Web 服务listmonk 将活动消息以JSON 请求推送给该服务由该服务负责将其广播为 SMS、FCM 等具体形式。配置与接入方式详见 messengers.md。Tracking pixel追踪像素邮件打开统计追踪像素Tracking pixel是一张微小的、不可见的图片被插入邮件正文中用于追踪邮件的被查看打开情况从而测量邮件的阅读率read rate。这在邮件活动中极为常见但携带隐私影响使用时应遵守 GDPR 等法律法规的要求。在源码 internal/manager/manager.go 中TrackView函数实际生成一个 1×1 像素的透明图片标签TrackView: func(msg *CampaignMessage) template.HTML { if m.cfg.DisableTracking { return template.HTML() } ... return template.HTML(fmt.Sprintf(img src%s width1 height1 styledisplay:none;max-height:0;max-width:0;opacity:0 alt, fmt.Sprintf(m.cfg.ViewTrackURL, msg.Campaign.UUID, subUUID))) },注意两处关键配置DisableTracking若开启TrackView直接返回空字符串完全不注入追踪像素IndividualTracking若关闭则使用dummyUUID替代真实订阅者 UUID——即匿名追踪可以统计有 X 次打开而不把某次打开与具体订阅者关联。底层存储方面每次打开记录写入campaign_views表schema.sql其subscriber_id字段可空NULL注释明确说明订阅者可能被删除但查看计数应当保留——这与匿名追踪能力相呼应。Click tracking点击追踪listmonk 可以追踪邮件中每一个链接的点击从而测量邮件中链接的点击率clickthrough rate。与打开追踪一样点击追踪也携带隐私影响需合规使用如 GDPR同样可以通过配置实现匿名点击追踪不将点击与具体订阅者关联。点击追踪的链路实现如下模板中用{{ TrackLink https://link.com }}函数或https://link.comTrackLink简写把原始 URL 包装为追踪 URLinternal/manager/manager.go 中该函数同样受DisableTracking与IndividualTracking配置控制点击发生时listmonk 将 URL 去重记录到links表每次点击写入link_clicks表schema.sql两表分别按campaign_id、link_id、subscriber_id、created_at建立索引以支撑统计查询计数最终汇总到活动元数据CampaignMeta的Clicks字段展示在活动分析页面。links表中url字段带UNIQUE约束说明同一 URL 在所有活动中共享同一条记录点击计数按campaign, link, subscriber维度去重统计。Bounce退信处理**退信Bounce**发生在发送给收件人的邮件因各种原因被弹回时常见原因包括收件人地址无效收件人邮箱已满收件人的邮件服务商将该邮件标记为垃圾邮件。listmonk 可以自动处理退信退信来源有两种配置的POP 邮箱自动拉取并解析退信邮件SMTP 服务商的 API例如 AWS SES、SendGrid 等。根据设置退信订阅者可以被自动加入黑名单blocklisted或删除。完整的退信配置、类型与流程请参考 bounces.md。在源码 models/bounces.go 中退信被分为三种类型const ( BounceTypeHard hard BounceTypeSoft soft BounceTypeComplaint complaint )即硬退信hard地址无效、软退信soft临时性失败如邮箱满与投诉complaint收件人标记为垃圾邮件。Bounce记录通过email或SubscriberUUID关联到订阅者并可关联到具体活动CampaignUUID支撑了退信页面的归因分析。概念关系总览与下一步至此listmonk 的核心领域模型已清晰成形订阅者是携带邮箱、姓名与任意 JSON 属性的实体通过订阅关系unconfirmed / confirmed / unsubscribed挂接在列表上活动面向一个或多个列表发送或经Messenger转发为 SMS/FCM 等由模板定义版式正文可引用订阅者字段与属性追踪像素与点击追踪分别记录打开与点击事件campaign_views、link_clicks表并支持匿名模式以兼顾 GDPR 合规退信经由 POP 邮箱或 SES/SendGrid 等 API 回流触发黑名单或删除策略。如需深入建议继续阅读同目录下的专题文档querying-and-segmentation.mdSQL 查询与细分语法、templating.md模板函数全表与示例、messengers.md自定义消息通道、bounces.md退信处理与配置数据结构层面可对照 models 目录与 schema.sql 中的建表语句逐一印证。【免费下载链接】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),仅供参考
返回列表