协同办公

Odoo 任务为什么能把邮件自动变成协作上下文:收件人认领、CC 留存、正文落描述与附件接力讲透

Odoo 项目任务的邮件入口并不只是“来信建 task”。源码同时处理了内部用户认领、外部联系人 CC、首封邮件正文落到任务描述,以及图片附件变封面这一整套协作接力。

协同办公
进阶 开发者 2 分钟阅读
0 评论 0 点赞 0 收藏 5 阅读

先说结论

很多人以为项目任务的邮件网关逻辑,无非就是:

  • 发一封邮件到项目 alias
  • Odoo 建一条 task

addons/project/models/project_task.py 里的 message_new()message_update()_message_post_after_hook() 说明, 官方真正想做的不是“把邮件存进去”,而是:

把一封邮件尽量完整地翻译成一个可以继续协作的任务上下文。

这包括:

  • 识别收件人里哪些是内部用户,并转成 assignee
  • 把非内部收件人保留在 email_cc
  • 避免把项目 alias 自己错误写进 CC
  • 用首封邮件正文初始化任务描述
  • 用图片附件补出任务展示图
  • 后续回信继续把新的相关人订阅进来

这已经不是简单建档,而是“邮件 → 协作对象”的接力设计。


一、为什么任务邮件入口要先区分“内部协作者”和“外部联系人”

project.task.message_new() 里很有意思的一段,是 _find_internal_users_from_address_mail()

它会拿邮件的 to 地址做一轮拆分与匹配,然后分成三类:

  • 能匹配到内部用户的邮箱
  • 能匹配到 partner 但没有内部用户身份的邮箱
  • 完全未匹配上的邮箱

然后 Odoo 做了一个非常符合协同现实的决定:

  • 内部用户 → 放进 user_ids,也就是任务负责人 / 协作者
  • 外部联系人与未匹配地址 → 保留进 email_cc

这说明官方非常清楚一件事:

同样出现在收件人里的人,并不属于同一协作层。

有人是团队内执行者, 有人只是需要被抄送或保留外部联系链路。

如果系统不做这层拆分,任务协作会很快失真。


二、为什么不能把项目 alias 自己也塞进 CC

_find_internal_users_from_address_mail() 还有个很细但非常实战的处理:

  • 如果当前有 project_id
  • 会把项目 alias 地址从 unresolved_emails 里剔掉

这看起来像小事,其实很关键。

因为在真实收件列表里,项目 alias 本来就常常出现在 To 或 Cc 中。

如果系统不把它剔掉,后面就会出现很怪的问题:

  • 任务上保存了一串无意义的 alias 地址
  • 系统像是把项目邮箱也当成外部联系人留档
  • 再往后发信时,地址链路越来越脏

所以这一步实际上是在保护任务的邮件上下文不被技术入口污染。


三、为什么首封邮件正文要落到任务描述,而不只是留在 Chatter

_message_post_after_hook() 里有一段非常有产品感的逻辑。

如果满足这些条件:

  • 任务当前还没有 description
  • 当前消息是 creation subtype
  • 任务 partner_id 与消息作者一致
  • 当前消息类型是 email
  • 并且 body 存在

那么 Odoo 会:

  • 清理邮箱签名
  • 对 HTML 做 sanitize
  • 把清洗后的正文写入 description

这个设计特别值得注意。

因为官方并没有满足于“邮件已经在 Chatter 里可见”。

它意识到对于任务来说, 首封邮件往往不只是沟通记录,还是任务本体的需求说明。

所以正文落到 description,意味着:

  • 任务打开后,核心上下文直接可读
  • 不必每次都翻第一条 Chatter 才知道来龙去脉
  • 邮件输入更自然地变成任务说明书

这就是“协作上下文同步”,不是单纯消息留痕。


四、为什么要主动去掉签名

同一段逻辑里,Odoo 还会专门处理:

  • id="Signature"
  • Gmail signature 标记
  • 以及仅有 -- 的签名分隔片段

这说明官方知道,如果不清理签名, 任务描述会迅速变成一团噪音:

  • 手机尾注
  • 公司免责声明
  • 自动签名横线
  • 联系方式重复堆叠

对于邮件线程来说,这些内容偶尔还能接受; 但对于任务 description,这些内容会直接降低可读性。

因此 Odoo 不是简单搬运原文, 而是在做一次“从邮件正文到任务说明”的内容净化。


五、为什么图片附件还能顺手变成任务展示图

_message_post_after_hook() 前半段还做了一件很适合协同场景的事:

  • 如果消息带附件
  • 且任务还没有 displayed_image_id
  • 就从图片附件里取第一张作为展示图

这背后的产品意义很强。

很多任务型协作都不是纯文字:

  • 设计稿
  • 现场照片
  • 截图
  • 缺陷复现图片

如果第一封邮件附带了关键图片, 把它顺手提炼成任务的可视化封面, 会让协作者更快理解任务内容。

这说明 Odoo 在任务邮件协作上,想保留的不只是“文本对话”,还包括可视化线索。


六、为什么后续回信还要继续 message_subscribe()

不论 message_new() 还是 message_update(),项目任务都会在处理邮件时继续找 To / Cc 里的 partner, 并调用 message_subscribe()

这意味着 Odoo 的思路不是:

  • 任务创建那一刻定下协作者名单
  • 后续对话永远不再变化

而是:

  • 邮件往来本身也在持续暴露新的参与者
  • 这些参与者应该被逐步纳入任务后续沟通圈

这很符合现实。

因为一个任务的参与边界往往会随着讨论逐步展开:

  • 最初只有发起人与项目入口
  • 后来加上执行人
  • 再后来可能加上客户联系人、产品经理、支持同事

Odoo 允许任务协作边界随着邮件链路自然增长,而不是一次性写死。


七、为什么这套设计比“邮件转任务”更高级

很多系统也支持“邮件转工单 / 转任务”, 但常见做法只是:

  • 建一条记录
  • 把原邮件存档

Odoo 在项目任务这里明显走得更远:

  • 收件人语义拆分:内部用户 vs 外部联系人
  • 正文语义升级:邮件正文不只是归档,还会成为任务描述
  • 附件语义升级:图片不只是附件,还可能成为展示图
  • 协作者边界扩展:后续邮件继续拉新参与者入场

这套设计的核心不是“邮件兼容”, 而是“让邮件成为任务协作的自然入口”。


八、这对文档与任务协同有什么启发

用户要求里提到“文档与任务协同”, 而这段源码给出的启发其实很直接:

  • 一封邮件正文,本质上就是一份临时需求文档
  • 附件里的截图和图片,本质上就是任务的上下文材料
  • To / Cc 本质上是在表达协作角色

Odoo 并没有另起一套“文档转任务”复杂流程, 而是让邮件在进入任务的那一刻,就尽量保留这些协作文档属性。

也就是说:

任务不是只接收一个标题,它接收的是一整包带人物、正文、附件和后续往来的上下文。


九、实战里最容易踩的坑

1. 把所有收件人都硬塞成 assignee

会把外部联系人错误内部化。

2. 忽略 project alias 自身地址

最后 email_cc 里会堆出脏地址。

3. 只把邮件留在 Chatter,不同步 description

任务正文可读性会差很多。

4. 不处理签名

描述区域会充满无效噪音。

5. 任务创建后不再根据邮件扩展参与者

后续协作者容易被排除在沟通圈外。


一句话记忆法

Odoo 项目任务的邮件入口不是“收到邮件就建 task”,而是把收件人、正文、附件和后续往来一起翻译成可继续协作的任务上下文。

DISCUSSION

评论区

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