目录
- [Odoo 邮件系统整体架构](#Odoo 邮件系统整体架构)
- 邮件发送方式
- 邮件模板配置
- [SMTP 邮件服务器配置](#SMTP 邮件服务器配置)
- 邮件发送过程
- 开发中常见邮件发送需求
- 常见问题排查
- 提示与最佳实践
- 完整示例:审批通过自动发邮件
- 门户表单自动邮件通知案例
- 邮件队列与异步发送
- 邮件添加附件
- 邮件日志与调试
- 多语言邮件模板
- 邮件安全与反垃圾建议
- 常见报错案例
- 参考链接
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 |
配置完成后可测试邮件发送是否正常。
🧪 五、邮件发送过程(背后流程)
mail.template.send_mail()
创建mail.mail
记录mail.mail.send()
通过 SMTP 发出邮件- 发送成功状态为
sent
,失败为exception
- 可通过计划任务定期处理
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_cc
、email_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 的项目,并发送邮件。
🧪 十、测试步骤
- 在自定义模块中添加上述 XML、Python 和控制器代码
- 安装模块并确保 SMTP 设置正确
- 创建项目记录(填写
name
和user_id
) - 浏览器访问
/project/approve/1
- 检查收件人邮箱是否收到邮件
💡 十一、门户表单自动邮件通知案例
适用于 Odoo 14~18,常见于"项目申请"、"需求提交"、"报名"等门户场景。
1. 场景描述
用户(如客户、员工)在门户网站提交"项目申请表单"后:
- 项目记录保存进
project.project
模型 - 自动通知相关负责人(如管理员)
- 返回提交成功页面
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. 测试流程
- 浏览器访问:http://yourdomain.com/project/apply
- 填写并提交表单
- 邮件自动发送到设置的收件人邮箱(如
[email protected]
) - 页面跳转到感谢页
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 邮件系统功能强大且灵活,既能满足日常通知,也能支撑复杂的业务自动化。建议开发者优先使用模板统一管理邮件格式,合理利用队列机制提升性能,并关注邮件日志与异常处理,保障邮件送达率。欢迎在评论区留言交流更多实战经验!