mail alias 生命周期

Odoo 的 mail.alias.mixin 为什么不只是“加个邮箱别名”:别名创建、同步与删除生命周期讲透

很多人知道 Odoo 可以通过邮件别名自动进线,却不知道模型侧是如何把业务记录和 mail.alias 绑定起来的。本文结合官方源码,讲清 mail.alias.mixin 与 mail.alias.mixin.optional 的创建、写入、域名同步和删除边界。

Odoo 开发
进阶 开发者 2 分钟阅读
0 评论 0 点赞 0 收藏 6 阅读

先说结论

很多人提到 Odoo 邮件进线,首先想到的是:

  • 邮件发到某个地址
  • 系统自动建单或挂到某个对象上

但从开发视角看,更值得弄清的是:

业务模型到底怎样和 mail.alias 建立一对一或可选绑定关系。

这正是 mail.alias.mixinmail.alias.mixin.optional 要解决的问题。

它们不是“收邮件功能按钮”,而是:

  • 帮模型管理 alias 生命周期
  • 把 alias 字段与业务记录字段拆分处理
  • 在 create / write / unlink 时自动保持一致性

mail.alias.mixin 解决的是什么问题

/home/ubuntu/odoo-temp/addons/mail/models/mail_alias_mixin.py 里,官方注释已经说得很清楚:

  • 这个 mixin 用于让业务模型继承 mail.alias
  • 目标是形成 模型记录与 alias 的一对一关系

它通过:

_inherits = {'mail.alias': 'alias_id'}

mail.alias 挂到业务模型上。

而且 alias_id 是必填的。

这意味着:

只要你用了这个重型 mixin,alias 就不是一个“可有可无的附属信息”,而是该记录结构的一部分。


为什么官方还提供一个 optional 版本

很多场景下,alias 并不是每条记录都必须有。

比如:

  • 有的 team 要收邮件
  • 有的 team 不需要
  • 有的记录先创建,后面才决定是否开放进线

所以官方在 /home/ubuntu/odoo-temp/addons/mail/models/mail_alias_mixin_optional.py 又提供了一个轻量版本。

它的注释直接写明:

  • 字段不是强制的
  • alias 会根据 alias_name 等输入动态创建
  • 目的是避免产生大量“空别名”记录

这就是两者最核心的设计分野:

mail.alias.mixin

  • 强绑定
  • alias 是模型结构一部分
  • 没 alias 不行

mail.alias.mixin.optional

  • 弱绑定
  • alias 按需出现
  • 更适合渐进式开通邮件入口

create 时到底发生了什么

optional 版本的 create() 很值得读。

它大致分成四步:

1. 先判断哪些记录需要新 alias

如果:

  • 没传 alias_id
  • 同时又给了 alias_name

就认为这条记录需要新建 alias。

2. 先把 alias 相关字段从业务字段里拆出去

源码里的 _alias_filter_fields() 会把:

  • 属于 mail.alias 的值
  • 和属于业务模型本身的值

拆成两份。

这一步很重要,因为它说明:

create 时不是“所有字段一起写进去”,而是 alias 和业务记录分层处理。

3. 用 sudo() 批量创建 alias

源码明确对 mail.alias 侧使用 sudo().create()

原因也不难理解:

  • 邮件网关入口往往是系统级资源
  • 普通业务用户未必有权直接管理 alias 对象

4. 创建完业务记录后,再回写依赖 record 自身的信息

例如 _alias_get_creation_values() 里会带:

  • alias_parent_thread_id = self.id
  • alias_parent_model_id = ir.model 对应 id

也就是说,有些 alias 值只有在业务记录已经真正创建后,才能完整补齐。


write 为什么也这么复杂

write() 不是简单的字段更新,而是在处理两类对象同步。

官方源码里有几个关键动作:

1. 如果原来没 alias,但这次写入了 alias_name

那就现场补建 alias。

这说明 optional 版本支持“先有业务记录,后开启邮件入口”。

2. alias 字段和业务字段继续拆开写

  • 业务字段正常 super().write()
  • alias 字段走 self.mapped('alias_id').sudo().write(alias_vals)

3. 如果公司环境变了,还要同步 alias domain

源码里专门会根据公司去取 alias domain,再把 alias_domain_id 写回去。

这非常重要,因为邮件地址不是只有 alias_name,还包含:

  • 哪个域名
  • 哪家公司语境

所以它处理的不是“邮箱昵称”,而是完整邮件入口身份


optional 版本在 unlink() 里会:

  • 先记住 aliases = self.mapped('alias_id')
  • 删除业务记录
  • aliases.sudo().unlink()

这意味着别名生命周期不是独立悬空的。

如果业务对象没了,对应 alias 也应当一起清掉,避免:

  • 残留入口
  • 邮件继续打到无效对象
  • 系统里越积越多孤儿 alias

这类 mixin 真正常见的误解

误解 1:mail alias 只是一个展示字段

不是。

它背后有自己的模型、权限、域名、父对象绑定和删除链。

误解 2:给模型加个 alias_name 就等于支持邮件进线

不够。

真正难的是:

  • 何时建 alias
  • 谁来建
  • 建完怎么回写
  • 改公司后域名怎么同步
  • 记录删掉后 alias 怎么收口

误解 3:alias 和业务记录可以随便分开维护

理论上能手改,但官方 mixin 的整个设计方向,其实就是尽量避免两边状态漂移。


开发时该怎么选

适合 mail.alias.mixin

  • 每条记录都应该天然拥有邮件入口
  • alias 是对象结构的一部分
  • 你明确要强约束一对一关系

适合 mail.alias.mixin.optional

  • 只有部分记录需要 alias
  • 你想允许后期开通
  • 你不想因为空 alias 造成数据噪声

一句话收尾

mail.alias.mixin 系列真正解决的不是“收邮件”,而是“业务记录与邮件入口对象怎样在创建、修改、删掉时保持生命周期一致”。

DISCUSSION

评论区

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