其他深度

Odoo 群发联系人为什么不能只是一张邮箱表:subscription 中间表、opt-out 时间与默认名单同步讲透

Odoo 把 mailing.contact 和 mailing.list 之间专门拆出 mailing.subscription,并额外记录 opt_out_reason、opt_out_datetime 和 default_list_ids 上下文同步,这说明它把名单关系当成业务对象,而不是一个普通 many2many。

其他
进阶 开发者 1 分钟阅读
0 评论 0 点赞 0 收藏 5 阅读

先说结论

很多系统一做邮件名单,就把“联系人”和“名单”之间做成一张平平无奇的关联表。但 Odoo 明显不这么想,它给这层关系起了正式模型名,还让它承担退订原因、退订时间等状态语义。

第一层:为什么 mailing.subscription 必须是显式模型

只要名单关系里出现“是否退订”“何时退订”“为什么退订”,它就不再是纯连接关系,而是业务事实。Odoo 把 mailing_subscription 独立成模型,本质上是在承认:联系人和名单之间的关系本身,也是需要被管理和审计的。

第二层:opt_out 为什么依赖上下文里的 active list

mailing.contact 上的 opt_out 是个计算字段,而且明确要求当前上下文里只有一个 default_list_ids。这说明 Odoo 不把“联系人是否退订”理解成全局属性,而是理解成“针对某一张名单是否退订”。如果没锁定当前名单,这个问题本身就没有清晰答案。

第三层:为什么 create 要同步 default_list_ids 与 subscription_ids

mailing.contact.create() 里有一段看似啰嗦的同步逻辑:如果上下文已经带了默认 list,而你只传了 subscription_ids,它会帮你补齐缺失名单。这是在给 UI 和 ORM 打补丁,避免因为入口不同,最终联系人落到的名单关系不一致。

第四层:退订时间为什么自动写入

mailing.subscriptionopt_out 为真时会自动写 opt_out_datetime,创建和写入时如果给了退订原因或退订时间,也会反推 opt_out=True。这说明退订不是一个单独布尔值,而是一条带时间语义的事件。后续做合规审计或名单清洗时,这个时间点非常有价值。

第五层:这套模型最适合防什么坑

它主要防两类坑:一类是同一联系人在不同名单上的状态混淆;另一类是导入、快速创建、名单页操作等不同入口造成的关系不一致。只有把 subscription 当成正式对象,这些坑才好堵。

最容易误解的三个点

  • 误区一:联系人退订就是全局退订。很多业务其实需要按名单分别管理。
  • 误区二:many2many 足够了。只要关系上挂状态,就不该再把它当纯连接表。
  • 误区三:退订时间不重要。没有时间,你就很难证明某次退订何时发生。

实战上怎么用更稳

  • 做邮件名单系统时,优先考虑“联系人-名单关系”是否需要独立建模。
  • 如果 UI 入口很多,最好像 Odoo 一样做默认名单同步,减少漏挂名单。
  • 做合规或运营复盘时,退订时间和退订原因往往比布尔值更有用。

最后总结

Mailing Contact 真正复杂的地方,不是联系人字段,而是联系人与名单之间那层带状态、带时间、带上下文的关系。Odoo 把它单独建模,是非常清醒的设计。

DISCUSSION

评论区

想参与讨论?先 登录 再发表评论。
还没有评论,你可以成为第一个留言的人。