联系人与同意
一份经得起追问的名单,而不只是你手里的一份名单
任何人都能存下一万个电子邮件地址。真正重要的问题——监管机构、服务商和你自己的良知会用略有不同的措辞问出的那个问题——是每个地址从何而来,以及你凭什么可以给它写信。ClickSomo 把这一点变成一条已存储的事实,而不是需要你事后重建的东西。
身份就是电子邮件地址
每个项目、每个地址仅限一个联系人,由数据库强制执行,而不是靠运气。地址在写入时即被规范化,而不是在读取时——若在读取时规范化,这条约束就只是个摆设,会让 Anna@ 和 anna@ 同时混进来。
电话号码存在时以 E.164 格式存储,但电话号码是一个属性,不是身份。这里没有身份解析图,没有合并协议,也没有合并的审计记录,因为每个联系人都来自一个本身已带有地址的渠道:导入、表单、订阅,或你自己的代码。
姓名整体存储
display_name 按原样保存,从不拆分成部分。拆分姓名是 bug 工厂——"van der Berg"、"Kim Min-jun"、单名、头衔,以及所有非盎格鲁的姓名顺序惯例——而错误的拆分会在合并标签中显示为 "Dear van,",这比完全没有个性化还要糟。
结构化的姓名部分只存在于来源本身已分开提供的情况。任何内容都不会推导它们。而且某人自己输入的姓名永远不会被后来碰巧记录了不同内容的 CSV 覆盖,因为“最后写入者胜”会让最马虎的导入获胜。
- 1身份电子邮件,已规范化。项目内唯一。
- 2姓名整体存储。
first_name在渲染时推导,从不存储。 - 3属性任意内容,以 JSON 形式。属于你,并可作为
attrs.*插值。 - 4标签和列表标签是一等公民,存放在同一个存储中;列表则是显式的成员关系。
- 5同意每个渠道一行,包含合法依据及其证据。
- 6事件这个人所做一切的只追加日志。整个产品所依赖的表。
- ×从不没有密码、没有哈希、没有会话、没有 API 密钥。一个能验证某人身份的列将是一起事故,而不是一个功能。
同时限定于租户和项目
同意台账
缺失不等于许可
每个联系人、每个渠道一行——电子邮件、短信、信函、推送——每行携带一个状态、一个合法依据、一个来源、证据、时间戳和司法管辖区。某个渠道没有依据行的联系人,在该渠道上无法发送任何内容。不是“被标记”。是不能。
consent
某人主动提出。一次表单提交并保存了证据、一次双重确认、一个他们自己勾选的复选框。这是最强的依据,也是表单唯一能产生的依据。
legitimate_interest
CSV 导入所能达到的最好结果。电子表格无法记住某人同意过某事,因此它永远不允许声称对方同意过——重新上传同一个文件也不会升级它。
contract
你之所以联系他们,是因为你们双方共同参与某事。服务提醒、续订通知,以及他们收不到会恼火的东西。
在活动发送之前,你会看到其受众的依据构成:这些人中有多少是主动同意的,有多少是在合法利益下触达的,又有多少是因为合同。这一个数字阻止的糟糕发送,比任何警告横幅都多。
为什么这对你来说比必要的更严格:这其实不是针对你。批量发送的信誉是一种共享资源,一个粗心的列表会毒害同一基础设施上所有发送者的水源。每个租户的投诉率和退信率都会被监控,超出阈值的账户会在这里被限速——在服务商对所有人一锅端之前。

列表中每一行的背后,都有某个人说了“好”。
四种进入方式
进入你列表的每条路径,都是你在操作自己的数据
没有服务令牌的摄取通道,也没有兄弟产品悄悄写入你的联系人。如果你想让某人进入某个列表,只有这四种方式之一能把他们放进去。
CSV 导入
逐列映射,写入时规范化,经 MX 检查以便在硬退信之前捕获失效和拼错的域名,并以你明确设置的依据入库。导入会获得一个 id,它创建的每个联系人都指向它。
一个 ClickSomo 表单
与其他一切一样由同一文档渲染,带有验证、蜜罐和速率限制。表单提交是唯一能合法产生 consent 的路径,因为它是唯一本人亲自在场的路径。
你在 dash-b 中构建的页面
仪表板设计器发布页面;页面上的表单会使用你自己的凭据提交到这里。同样的验证,同样的同意处理,无需维护第二个集成。
公开 API
POST /v1/contacts,使用你自己的令牌,upsert 语义,支持幂等键。你的应用已经知道谁注册了;这是从这一事实到漏斗的最短路径。
细分是一种谓词,会被编译
细分是一棵存储的谓词树,覆盖联系人字段、属性、标签、列表归属和行为,编译为 SQL 并连同计数一起缓存。运算符都是常见的那些——等于、不等于、属于、不属于、以…开头、以…结尾、包含、已设置、未设置——并用 and、or 和 not 组合到任意深度。
使用前先预览。该端点返回的是真实联系人,所以“里面到底有谁”这个问题靠看就能回答,而不是发出去才知道。
细分还有多重用途:作为营销活动的受众、作为漏斗分支上的条件,也可以独立作为触发器——segment_enter 会在某人符合条件的那一刻启动一次运行。
- 1标签
tags contains "regular" - 2属性
attrs.total_orders >= 3—— 你的字段,你给它起的名字。 - 3行为最近 90 天内没有
order.paid事件。 - 4同意一个可用的电子邮件依据。没有依据的联系人不计入数量,反正也无法给他们发送。
- i预览已列出 412 位联系人。发送时会重新计数,因为细分是一个问题,而不是一张快照。
编译为 SQL计数已缓存,答案实时
抑制,以及何时检查
抑制是项目级和全局的:硬退信、投诉、退订、手动条目和角色地址。它们会在发送时被检查,然后在发送服务内部再检查一次。
第二个检查点才是关键。一个包含三天等待的漏斗,就有三天的窗口期让人可以退订;一个在消息入队时检查抑制的系统照样会把邮件发给他们。在发送时检查,是尊重退订和仅仅记录退订之间的区别。
删除也是同样的道理:删除请求会在这里移除联系人及其消息历史,并通过家族其他成员使用的同一条内部通道,送达每一个持有副本的兄弟服务。只有一个地方可以提出请求,也只发生一件事。