第23讲、Odoo18 邮件系统整体架构

目录

  1. [Odoo 邮件系统整体架构](#Odoo 邮件系统整体架构)
  2. 邮件发送方式
  3. 邮件模板配置
  4. [SMTP 邮件服务器配置](#SMTP 邮件服务器配置)
  5. 邮件发送过程
  6. 开发中常见邮件发送需求
  7. 常见问题排查
  8. 提示与最佳实践
  9. 完整示例:审批通过自动发邮件
  10. 门户表单自动邮件通知案例
  11. 邮件队列与异步发送
  12. 邮件添加附件
  13. 邮件日志与调试
  14. 多语言邮件模板
  15. 邮件安全与反垃圾建议
  16. 常见报错案例
  17. 参考链接

Odoo 18 的邮件系统基于强大的邮件引擎,广泛应用于用户通知、自动化邮件、营销推广、模板化邮件及附件发送等多种场景。本文将从系统架构、发送方式、配置方法、开发实践等多个维度,系统梳理 Odoo 邮件功能的原理与实战技巧,助你高效掌握企业级邮件自动化。


🧱 一、Odoo 邮件系统整体架构

Odoo 的邮件系统围绕以下核心模型构建:

模型 说明
mail.mail 单条待发送邮件记录(每封邮件生成一条)
mail.message 邮件消息记录(通知、聊天、讨论、评论等)
mail.template 邮件模板,支持变量替换
ir.mail_server SMTP 邮件服务器配置
res.partner 接收者(通常为联系人)
mail.thread 支持消息、跟踪和通知的模型继承类

🛠️ 二、邮件发送方式

Odoo 支持多种邮件发送方式,满足不同业务需求:

1. 使用 mail.template 模板发送(推荐,适合业务通知)

适用于大多数业务场景,支持变量替换和批量发送。

python 复制代码
# 通过模板发送邮件,force_send=True 表示立即发送,否则进入队列
template = self.env.ref('your_module.email_template_project_approval')
template.send_mail(record_id, force_send=True)

2. 使用 mail.mail 模型手动构建邮件

适合自定义内容、附件等特殊场景。

python 复制代码
mail = self.env['mail.mail'].create({
    'subject': '通知标题',
    'body_html': '<p>这是一封自动邮件</p>',
    'email_to': '[email protected]',
    'email_from': '[email protected]',
})
mail.send()

3. 使用 record.message_post() 发送内部通知

适合在模型记录上快速发送系统消息或评论。

python 复制代码
record.message_post(
    body="您的申请已审批通过。",
    subject="审批通过通知",
    message_type='notification',
    subtype_xmlid='mail.mt_comment',
    partner_ids=[user.partner_id.id],
)

⚙️ 三、邮件模板配置(mail.template)

邮件模板支持灵活的变量替换和 HTML 格式,便于统一管理邮件内容。

字段 示例 说明
Subject 项目 ${object.name} 已通过 支持 Jinja 表达式
Body HTML <p>尊敬的 ${object.partner_id.name}...</p> 支持 HTML
Model project.project 指定模型
Email To ${object.user_id.email} 收件人

XML 示例:

xml 复制代码
<record id="email_template_project_approval" model="mail.template">
  <field name="name">Project Approved</field>
  <field name="model_id" ref="project.model_project_project"/>
  <field name="subject">项目 ${object.name} 审批通过</field>
  <field name="email_to">${object.user_id.email}</field>
  <field name="body_html">
    <![CDATA[
      <p>您好,${object.user_id.name}:</p>
      <p>您的项目申请 <strong>${object.name}</strong> 已通过审批。</p>
    ]]>
  </field>
</record>

📡 四、SMTP 邮件服务器配置

路径:设置 > 技术 > 邮件 > 外发邮件服务器

字段 示例
SMTP 服务器 smtp.gmail.com
端口 587
使用 TLS
登录名 [email protected]
密码 yourpassword

配置完成后可测试邮件发送是否正常。


🧪 五、邮件发送过程(背后流程)

  1. mail.template.send_mail() 创建 mail.mail 记录
  2. mail.mail.send() 通过 SMTP 发出邮件
  3. 发送成功状态为 sent,失败为 exception
  4. 可通过计划任务定期处理 mail.mail 队列

📌 六、开发中常见邮件发送需求

场景:审批通过后自动发送通知邮件

python 复制代码
def action_approve(self):
    self.state = 'approved'
    template = self.env.ref('your_module.email_template_project_approval')
    template.send_mail(self.id, force_send=True)

🧩 七、常见问题排查

问题 解决方案
邮件发不出 检查 SMTP 设置、日志、是否有未发 mail.mail
收件人收不到 检查 email_to、SMTP 服务器是否被拒发
模板变量渲染失败 检查模型/字段拼写,建议开发模式调试
HTML 内容乱码 使用 CDATA 标签包裹 HTML

📌 八、提示与最佳实践

  • 优先使用 mail.template 统一管理邮件格式
  • 可用 email_ccemail_bcc 设置抄送
  • 立即发送用 force_send=True
  • 大量邮件建议用队列机制异步处理

📄 九、完整示例:审批通过自动发邮件

以下为审批通过后自动发送邮件的完整流程,包括模板、模型方法和控制器:

1. 邮件模板 XML(data/email_template.xml

xml 复制代码
<odoo>
  <data>
    <record id="email_template_project_approved" model="mail.template">
      <field name="name">Project Approval Notification</field>
      <field name="model_id" ref="your_module.model_project_project"/>
      <field name="subject">[Odoo] Project "${object.name}" Approved</field>
      <field name="email_to">${object.user_id.email or ''}</field>
      <field name="email_from">${(user.email or '[email protected]')}</field>
      <field name="body_html" type="html">
        <![CDATA[
        <p>Dear ${object.user_id.name},</p>
        <p>Your project <strong>${object.name}</strong> has been <strong>approved</strong>.</p>
        <p>Thank you,<br/>The Management Team</p>
        ]]>
      </field>
    </record>
  </data>
</odoo>

2. 模型方法发送邮件(models/project.py

python 复制代码
from odoo import models, fields, api

class ProjectProject(models.Model):
    _name = 'project.project'
    _inherit = ['mail.thread']  # 支持消息通知

    name = fields.Char(string='Project Name')
    user_id = fields.Many2one('res.users', string='Responsible')
    state = fields.Selection([
        ('draft', 'Draft'),
        ('approved', 'Approved'),
    ], default='draft')

    def action_approve(self):
        for rec in self:
            rec.state = 'approved'
            # 发送邮件
            template = self.env.ref('your_module.email_template_project_approved')
            if template:
                template.send_mail(rec.id, force_send=True)
            # 记录系统消息
            rec.message_post(body="项目已审批通过,通知已发送。")

3. 控制器触发发送(controllers/main.py

python 复制代码
from odoo import http
from odoo.http import request

class ProjectController(http.Controller):

    @http.route('/project/approve/<int:project_id>', type='http', auth='user', website=True)
    def approve_project(self, project_id):
        project = request.env['project.project'].sudo().browse(project_id)
        if project.exists():
            project.action_approve()
            return request.render('your_module.project_approval_success', {'project': project})
        else:
            return request.not_found()

你可以在浏览器访问 /project/approve/1 来审批 ID 为 1 的项目,并发送邮件。


🧪 十、测试步骤

  1. 在自定义模块中添加上述 XML、Python 和控制器代码
  2. 安装模块并确保 SMTP 设置正确
  3. 创建项目记录(填写 nameuser_id
  4. 浏览器访问 /project/approve/1
  5. 检查收件人邮箱是否收到邮件

💡 十一、门户表单自动邮件通知案例

适用于 Odoo 14~18,常见于"项目申请"、"需求提交"、"报名"等门户场景。

1. 场景描述

用户(如客户、员工)在门户网站提交"项目申请表单"后:

  1. 项目记录保存进 project.project 模型
  2. 自动通知相关负责人(如管理员)
  3. 返回提交成功页面

2. 模型定义(models/project.py

python 复制代码
from odoo import models, fields

class ProjectProject(models.Model):
    _name = 'project.project'
    _description = 'Project Application'
    _inherit = ['mail.thread']

    name = fields.Char("Project Name", required=True)
    description = fields.Text("Description")
    applicant_email = fields.Char("Applicant Email")
    state = fields.Selection([
        ('draft', 'Draft'),
        ('submitted', 'Submitted'),
    ], default='draft')

3. 邮件模板(data/email_template.xml

xml 复制代码
<odoo>
  <data>
    <record id="email_template_project_submit_notice" model="mail.template">
      <field name="name">New Project Application</field>
      <field name="model_id" ref="your_module.model_project_project"/>
      <field name="subject">[Odoo] New Project Application: ${object.name}</field>
      <field name="email_to">[email protected]</field> <!-- 可用对象字段替换 -->
      <field name="body_html" type="html">
        <![CDATA[
          <p>Dear Admin,</p>
          <p>A new project has been submitted:</p>
          <ul>
            <li><strong>Name:</strong> ${object.name}</li>
            <li><strong>Email:</strong> ${object.applicant_email}</li>
            <li><strong>Description:</strong> ${object.description}</li>
          </ul>
        ]]>
      </field>
    </record>
  </data>
</odoo>

4. 控制器 + 表单页面(controllers/main.py

python 复制代码
from odoo import http
from odoo.http import request

class ProjectFormController(http.Controller):

    @http.route('/project/apply', type='http', auth='public', website=True)
    def show_form(self, **kwargs):
        return request.render('your_module.project_form_template')

    @http.route('/project/apply/submit', type='http', auth='public', website=True, csrf=False)
    def submit_form(self, **post):
        project = request.env['project.project'].sudo().create({
            'name': post.get('name'),
            'description': post.get('description'),
            'applicant_email': post.get('email'),
            'state': 'submitted',
        })
        # 发送邮件通知
        template = request.env.ref('your_module.email_template_project_submit_notice')
        if template:
            template.sudo().send_mail(project.id, force_send=True)
        return request.render('your_module.project_form_thankyou', {'project': project})

5. 前端模板 QWeb(views/portal_form_templates.xml

xml 复制代码
<template id="project_form_template" name="Project Apply Form">
  <t t-call="website.layout">
    <div class="container mt-5">
      <h2>Project Application</h2>
      <form action="/project/apply/submit" method="post">
        <div class="form-group">
          <label>Project Name</label>
          <input type="text" name="name" class="form-control" required="required"/>
        </div>
        <div class="form-group">
          <label>Email</label>
          <input type="email" name="email" class="form-control" required="required"/>
        </div>
        <div class="form-group">
          <label>Description</label>
          <textarea name="description" class="form-control" rows="4"></textarea>
        </div>
        <button type="submit" class="btn btn-primary mt-3">Submit</button>
      </form>
    </div>
  </t>
</template>

<template id="project_form_thankyou" name="Thank You Page">
  <t t-call="website.layout">
    <div class="container mt-5">
      <h2>Thank You!</h2>
      <p>Your project "<t t-esc="project.name"/>" has been submitted successfully.</p>
    </div>
  </t>
</template>

6. 模块加载配置(__manifest__.py

确保加载视图、模板、邮件模板:

python 复制代码
'data': [
    'data/email_template.xml',
    'views/portal_form_templates.xml',
],

7. 测试流程

  1. 浏览器访问:http://yourdomain.com/project/apply
  2. 填写并提交表单
  3. 邮件自动发送到设置的收件人邮箱(如 [email protected]
  4. 页面跳转到感谢页

8. 可选扩展

  • 使用 res.users 查找管理员动态收件人
  • 设置 email_from 为申请人邮箱(如 ${object.applicant_email}
  • 后端审批后自动通知申请人

🕒 十二、邮件队列与异步发送

Odoo 默认通过队列机制异步发送邮件,适合大批量场景。可在"设置 > 技术 > 自动化 > 计划任务"找到 Email Queue Manager,定时处理 mail.mail 队列。

如需手动触发队列发送,可在 Odoo shell 执行:

python 复制代码
self.env['mail.mail'].process_email_queue()

大批量发送建议不要用 force_send=True,避免阻塞事务。


📎 十三、邮件添加附件

发送邮件时可通过 attachment_ids 字段添加附件:

python 复制代码
attachment = self.env['ir.attachment'].create({
    'name': 'example.pdf',
    'datas': base64.b64encode(b'file content'),
    'type': 'binary',
    'mimetype': 'application/pdf',
})
mail = self.env['mail.mail'].create({
    'subject': '带附件的邮件',
    'body_html': '<p>请查收附件</p>',
    'email_to': '[email protected]',
    'attachment_ids': [(4, attachment.id)],
})
mail.send()

📝 十四、邮件日志与调试

  • 所有邮件发送记录可在"设置 > 技术 > 邮件 > 外发邮件"查看
  • 邮件失败时可在"外发邮件"列表中查看异常原因
  • 开发调试时可在 Odoo 日志中搜索 mail.mail 相关日志,定位问题

🌏 十五、多语言邮件模板

Odoo 支持多语言邮件模板。可在模板表单页切换语言,分别填写不同语言内容。发送时会自动根据收件人语言选择模板内容。


🔒 十六、邮件安全与反垃圾建议

  • 建议配置 SPF、DKIM、DMARC 提升送达率,防止被判为垃圾邮件
  • 邮件内容避免敏感词或大量外链
  • email_from 建议用已验证域名邮箱

❓ 十七、常见报错案例

  • SMTPAuthenticationError:检查邮箱账号和密码,部分邮箱需开启"应用专用密码"
  • ConnectionRefusedError:检查 SMTP 服务器地址和端口,服务器是否允许外部连接
  • 模板变量渲染失败:确认字段拼写、模型是否正确,建议开发者模式调试

🔗 参考链接


结语




Odoo 邮件系统功能强大且灵活,既能满足日常通知,也能支撑复杂的业务自动化。建议开发者优先使用模板统一管理邮件格式,合理利用队列机制提升性能,并关注邮件日志与异常处理,保障邮件送达率。欢迎在评论区留言交流更多实战经验!

相关推荐
远方16092 小时前
14-Oracle 23ai Vector Search 向量索引和混合索引-实操
数据库·ai·oracle
打码人的日常分享3 小时前
物联网智慧医院建设方案(PPT)
大数据·物联网·架构·流程图·智慧城市·制造
白水baishui4 小时前
搭建强化推荐的决策服务架构
架构·推荐系统·强化学习·决策服务·服务架构
雪碧聊技术4 小时前
将单体架构项目拆分成微服务时的两种工程结构
微服务·架构·module·project·工程结构
从零开始学习人工智能5 小时前
Doris 数据库深度解析:架构、原理与实战应用
数据库·架构
阿部多瑞 ABU5 小时前
主流大语言模型安全性测试(三):阿拉伯语越狱提示词下的表现与分析
人工智能·安全·ai·语言模型·安全性测试
程序员JerrySUN6 小时前
[特殊字符] 深入理解 Linux 内核进程管理:架构、核心函数与调度机制
java·linux·架构
孔令飞6 小时前
Kubernetes 节点自动伸缩(Cluster Autoscaler)原理与实践
ai·云原生·容器·golang·kubernetes
Theodore_10226 小时前
大数据(2) 大数据处理架构Hadoop
大数据·服务器·hadoop·分布式·ubuntu·架构