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

news2025/6/8 8:10:17

目录

  1. Odoo 邮件系统整体架构
  2. 邮件发送方式
  3. 邮件模板配置
  4. 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_serverSMTP 邮件服务器配置
res.partner接收者(通常为联系人)
mail.thread支持消息、跟踪和通知的模型继承类

🛠️ 二、邮件发送方式

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

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

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

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

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

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

mail = self.env['mail.mail'].create({
    'subject': '通知标题',
    'body_html': '<p>这是一封自动邮件</p>',
    'email_to': 'abc@example.com',
    'email_from': 'no-reply@yourcompany.com',
})
mail.send()

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

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

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
Modelproject.project指定模型
Email To${object.user_id.email}收件人

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
登录名you@example.com
密码yourpassword

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


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

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

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

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

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

<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 'admin@example.com')}</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

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

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

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

<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">admin@example.com</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

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

<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

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

'data': [
    'data/email_template.xml',
    'views/portal_form_templates.xml',
],

7. 测试流程

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

8. 可选扩展

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

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

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

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

self.env['mail.mail'].process_email_queue()

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


📎 十三、邮件添加附件

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

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': 'abc@example.com',
    'attachment_ids': [(4, attachment.id)],
})
mail.send()

📝 十四、邮件日志与调试

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

🌏 十五、多语言邮件模板

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


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

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

❓ 十七、常见报错案例

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

🔗 参考链接

  • Odoo 官方文档 - 邮件
  • Odoo 邮件模板开发指南

结语




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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2403906.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HarmonyOS:Counter计数器组件

一、概述 计数器组件&#xff0c;提供相应的增加或者减少的计数操作。 说明 该组件从API Version 7开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 二、属性 除支持通用属性外&#xff0c;还支持以下属性。 enableInc enableInc(value: b…

sqlsugar WhereIF条件的大于等于和等于查出来的坑

一、如下图所示&#xff0c;当我用 .WhereIF(input.Plancontroltype > 0, u > u.Plancontroltype (DnjqPlancontroltype)input.Plancontroltype) 这里面用等于的时候&#xff0c;返回结果一条数据都没有。 上图中生成的SQL如下&#xff1a; SELECT id AS Id ,code AS …

Pandas 技术解析:从数据结构到应用场景的深度探索

序 我最早用Python做大数据项目时&#xff0c;接触最早的就是Pandas了。觉得对于IT技术人员而言&#xff0c;它是可以属于多场景的存在&#xff0c;因为它的本身就是数据驱动的技术生态中&#xff0c;对于软件工程师而言&#xff0c;它是快速构建数据处理管道的基石&#xff1…

数据库系统概论(十七)超详细讲解数据库规范化与五大范式(从函数依赖到多值依赖,再到五大范式,附带例题,表格,知识图谱对比带你一步步掌握)

数据库系统概论&#xff08;十七&#xff09;超详细讲解数据库规范化与五大范式&#xff08;从函数依赖到多值依赖&#xff0c;再到五大范式&#xff0c;附带例题&#xff0c;表格&#xff0c;知识图谱对比带你一步步掌握&#xff09; 前言一、为什么需要规范化1. 我们先想一个…

并发编程实战(生产者消费者模型)

在并发编程中使用生产者和消费者模式能够解决绝大多数的并发问题。该模式通过平衡生产线程和消费线程的工作能力来提高程序整体处理数据的速度。 生产者和消费者模式&#xff1a; 在线程的世界中生产者就是产生数据的线程&#xff0c;而消费者则是消费数据的线程。在多线程开…

git小乌龟不显示图标状态解决方案

第一步 在开始菜单的搜索处&#xff0c;输入regedit命令&#xff0c;打开注册表。 第二步 在注册表编辑器中&#xff0c;找到HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers 这一项。 第三步 让Tortoise相关的项目排在前…

获取 OpenAI API Key

你可以按照以下步骤来获取 openai.api_key&#xff0c;用于调用 OpenAI 的 GPT-4、DALLE、Whisper 等 API 服务&#xff1a; &#x1f9ed; 获取 OpenAI API Key 的步骤&#xff1a; ✅ 1. 注册或登录 OpenAI 账号 打开 https://platform.openai.com/ 使用你的邮箱或 Google/…

【Android基础回顾】五:AMS(Activity Manager Service)

Android 的 AMS&#xff08;Activity Manager Service&#xff09;是 Android 系统中的核心服务之一&#xff0c;负责管理整个应用生命周期、任务栈、进程和四大组件&#xff08;Activity、Service、BroadcastReceiver、ContentProvider&#xff09;的运行。它运行在系统进程 s…

pycharm中提示C++ compiler not found -- please install a compiler

1.最近用pycharm编译一个开源库,编译的依赖c compiler 2.单单使用pycharm编译&#xff0c;编译器报错C compiler not found – please install a compiler 3.需要在配置环境中引入对应库 4.从新编译后没有提示:C compiler not found – please install a compiler错误。

一站式直播工具:助力内容创作者高效开启直播新时代

近年来&#xff0c;随着互联网技术的不断进步和短视频、直播行业的爆发式增长&#xff0c;越来越多的企业和个人投入到直播电商、互动娱乐、在线教育等场景。直播运营过程中&#xff0c;涉及到数据统计、弹幕互动、流程自动化、内容同步等诸多环节。如何提升运营效率、减少人工…

以智能管理为基础,楼宇自控打造建筑碳中和新路径

在全球气候变化的严峻形势下&#xff0c;“碳中和”已成为各国发展的重要战略目标。建筑行业作为能源消耗与碳排放的“大户”&#xff0c;其运行阶段的能耗占全社会总能耗近40%&#xff0c;碳排放占比与之相当&#xff0c;实现建筑碳中和迫在眉睫。传统建筑管理模式下&#xff…

day029-Shell自动化编程-计算与while循环

文章目录 1. read 交互式初始化变量1.1 案例-安装不同的软件1.2 案例-比较大小 2. 计算2.1 bc2.2 awk2.3 expr2.4 let2.5 案例-计算内存的空闲率2.6 案例-检查域名过期时间和https整数过期时间 3. 循环3.1 循环控制语句3.2 for循环-c语言格式3.3 while循环3.3.1 案例-猜数字3.3…

Linux命令基础(2)

su和exit命令 可以通过su命令切换到root账户 语法&#xff1a;su [-] 用户名 -符号是可选的&#xff0c;表示是否在切换用户后加载环境变量&#xff0c;建议带上 参数&#xff1a;用户名&#xff0c;表示要切换的用户&#xff0c;用户名可以省略&#xff0c;省略表示切换到ro…

vue3 + vite实现动态路由,并进行vuex持久化设计

在后台管理系统中&#xff0c;如何根据后端返回的接口&#xff0c;来动态的设计路由呢&#xff0c;今天一片文章带你们解 1、在vuex中设置一个方法 拿到完整的路由数据 const state {routerList: []}; const mutations { dynameicMenu(state, payload) {// 第一步 通过glob…

学习路之php--性能优化

一、php周边优化 二、代码级优化 变量管理‌ 及时unset()释放大数组/对象&#xff0c;减少内存占用局部变量访问速度比全局变量快约2倍&#xff0c;优先使用局部变量大数组采用引用传递&#xff08;&$var&#xff09;避免内存 循环优化‌ 预计算循环次数&#xff1a; …

GC1808:高性能24位立体声音频ADC芯片解析

1. 芯片简介 GC1808 是一款24位立体声音频模数转换器&#xff08;ADC&#xff09;&#xff0c;支持96kHz采样率&#xff0c;集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器&#xff0c;适用于家庭影院、蓝牙音箱等场景。 核心特性 高精度&#xff1a;24位分辨率&#xff0c;…

echarts使用graph、lines实现拓扑,可以拖动增加effect效果

options.js // import React from react // import * as echarts from echartsimport ./index.lessexport const useEchartsOptionFun ({ nodeDataList, getNodeLinksDataList, getLinesCoordsFun }) > {const option {title: {text: 拓扑关系图,top: top,left: center,}…

产品经理课程(九)

从需求到功能设计 &#xff08;一&#xff09;复习 产品规划&#xff1a;产品定位、阶段性计划 产品定位&#xff1a;产品画布&#xff08;9个步骤&#xff1b;最重要的是先解决什么问题&#xff09; &#xff08;Roadmap&#xff09;目标要素&#xff1a;时间、事项、里程碑…

从零开始开发纯血鸿蒙应用之网络检测

从零开始开发纯血鸿蒙应用 〇、前言一、认识 connection 模块1、获取默认网络2、获取网络能力信息3、解析网络能力信息3.1、NetCap3.2、NetBearType 二、实现网络检测功能1、申请权限2、获取默认网路的 NetCap 数组 三、总结 〇、前言 在之前的博文里&#xff0c;介绍了如何实…

向 AI Search 迈进,腾讯云 ES 自研 v-pack 向量增强插件揭秘

作者&#xff1a;来自腾讯云刘忠奇 2025 年 1 月&#xff0c;腾讯云 ES 团队上线了 Elasticsearch 8.16.1 AI 搜索增强版&#xff0c;此发布版本重点提升了向量搜索、混合搜索的能力&#xff0c;为 RAG 类的 AI Search 场景保驾护航。除了紧跟 ES 官方在向量搜索上的大幅优化动…