【odoo14】【好书学习】第二十三章、管理邮件
老韩头的开发日常 ☞ 【好书学习】系列
邮件集成是odoo最重要的特性。我们可以通过odoo收发邮件。我们甚至可以管理业务文档上的电子邮件,如潜在客户、销售订单和项目。本章,我们将探讨在odoo中处理邮件的方式。
- 配置邮件服务器
- 管理文档中的chatter
- 管理文档中的活动
- 通过Jinja模板发送邮件
- 通过QWeb模板发送邮件
- 管理邮件别名
- 记录在聊天中用户改变的内容
- 定期发送摘要邮件
配置邮件服务器
在收发邮件前,我们需要配置邮件服务器。
准备
本节,并不需要进行代码开发,我们需要邮件服务器的相关信息。比如,服务器url,端口,服务器类型,用户名,密码。
小贴士
如果你使用Odoo Online或者Odoo.sh,你无需配置邮件服务器。
步骤
配置传入和传出的电子邮件服务器涉及到传入和传出服务器流程中常见的几个步骤,以及每种服务器特有的几个步骤。因此,首先我们将看到常见的配置步骤,然后我们将分别配置传入和传出的电子邮件服务器。以下是输入和输出邮件服务器都需要的步骤:
-
在Settins|General Settins的form视图下打开General Settins
-
在Discuss区域打开External Email Servers,如下:
-
在Alias Domain字段,输入我们的邮件服务器domain名。
配置收邮件服务器
-
打开General Settings,点击Incoming Email Servers链接,将打开收邮件服务器的列表视图
。 -
点击新建,将打开form视图。输入相关内容如下:
-
点击Test & Confirm验证配置。
配置发邮件服务器
-
打开General Settings,使能External Email Servers,点击Outgoing Email Servers链接。
-
点击新建,将打开form视图。输入服务器细节如下:
-
点击Test Connection验证配置。
原理
The steps given in this recipe are self-explanatory and do not require further explanation.But the outoging and incoming email records have several fields, so let`s see their purpose.
Here is a list of the fields used to configure the incoming eamil server:
- Name:服务器的名称,在我们添加了多个收邮件服务器的时候,标识不同的服务器。
- Server Type: 根据我们的邮件服务器选择POP、IMAP、Local中的一个。
- Server Name: 服务器的domain。
- Port: 邮件服务器的端口。
- SSL/TLS: 如果邮件服务器使用SSL/TLS加密,则选择该项。
- Username: 邮箱地址。
- Password: 邮件密码。
- Active 标识是否启用邮件服务器。
- Keep Attachment: 如果你不想管理附件可关闭该项。
- Keep Original: 如果你想保留原始邮件,可启动该项。
如下是配置发送邮件服务器:
- Description: 服务器的描述,用于区分不同的服务器。
- Priority: 用于定义发送邮件服务器的优先级。数字越低,优先级越高。
- SMTP Server: 服务器的domain。
- SMTP Port: 服务器的端口。
- Connection Security: 在发送邮件时使用的安全类型。
- Username: 发送邮件的账户。
- Password: 发送邮件的密码。
- Active: 启停发送邮件服务器。
更多
默认邮件服务器每5分钟更新一次。你可以修改该配置:
- 激活开发者模式。
- 在Settings | Technical | Automation | Scheduled | Actions,打开 Scheduled Actions。
- 搜索名为Mail:Fetchmail的动作。
- 改变间隔(Execute Every)。
管理文档中的chatter
本节,我们将了解如何在文档中管理沟通记录。
准备
本节,我们使用my_library模块,我们新增library.book.rent模型。
步骤
- 在__manifest__.py中添加mail模型
...
'depends': ['base', 'mail'],
...
- 在library.book.rent模型中继承mail.thread
class LibraryBookRent(models.Model):
_name = 'library.book.rent'
_inherit = ['mail.thread']
...
- 在library.book.rent模型的form视图添加chatter小部件
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_
followers"/>
<field name="message_ids" widget="mail_thread"/>
</div>
</form>
- 更新模块,显示如下:
原理
为了确保模型中的chatter可用,我们需要安装mail模块。
与chatter相关的字段及方法定义在mail.thread模型中。mail.thread模型是虚拟类仅用作继承。步骤2,我们继承了mail.thread模型,可以为library.book.rent模型添加必要的字段及方法。
在前两个步骤中,我们添加了chatter所需的所有字段和方法。步骤3,我们添加了message thread及follower widget。其中message_follower_ids及message_ids字段自定义mail.thread中。
更多
当我们在chatter中发送了消息,odoo将会自动给followers发送邮件。在我们本节的例子中,借阅人并不是图书记录的follower,因此他们并不会受到消息。如果需要给他们发邮件提醒,我们需要将他们添加到借阅列表中。我们可以通过 message_subscribe() 函数实现自动添加。如下:
@api.model
def create(self, vals):
res = super(LibraryBookRent, self).create(vals)
res.message_subscribe(partner_ids=[res.borrower_id.id])
return res
同样,我们可以通过 message_unsubscribe() 移除follower。
管理文档中的活动
当使用chatter时,还可以添加活动
。类似于代做列表清单的东西。本节,我们将学习如何激活活动
。
准备
步骤
为library.book.rent模型添加活动:
- 在library.book.rent模型中添加继承mail.activity.mixin。
class LibraryBookRent(models.Model):
_name = 'library.book.rent'
_inherit = ['mail.thread', 'mail.activity.mixin']
...
- 在library.book.rent模型中添加mail_activity小部件
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_
followers"/>
<field name="activity_ids" widget="mail_activity"/>
<field name="message_ids" widget="mail_thread"/>
</div>
- 更新模块,显示如下:
原理
活动
是mail模块中的一部分,我们可通过继承mail.activity.mixin实现在chatter中选择性的启用该功能。与mail.thread模型类似,mail.activity.mixin也是抽象模型。
步骤1,我们在library.book.rent中继承了mail.activity.mixin,因此library.book.rent获得了管理活动所必须的方法及字段。
步骤2,我们添加了mail_activity小部件,用于展示活动的相关内容,通过继承,我们在library.book.rent模型中添加了activity_ids字段。
活动有不同的类型。默认我们可以创建诸如Email、Call、Meeting和To-Do。我们可以在Settings | Technical | Email | Activity Types添加新的活动类型。
更多
如果你想实现自动关联活动,我们可以通过mail.activity.mixin模型中的activity_schedule()方法实现。如下:
@api.model
def create(self, vals):
res = super(LibraryBookRent, self).create(vals)
if res.return_date:
res.activity_schedule('mail.mail_activity_data_call', date_deadline=res.return_date)
return res
如上例子可以在图书被借用的时候可自动实现添加一个提醒活动。可以在借阅截止日期的时候,管理员提醒下借阅人。
通过Jinja模板发送邮件
odoo支持通过Jinja模板创建动态邮件。Jinja是基于文本的模板引擎,用于解析HTML内容。本节,我们将创建Jinja邮件模板并发送邮件。
准备
步骤
- 创建my_library/data/mail_template.xml文件如下:
<?xml version="1.0" encoding="utf-8"?>
<odoo noupdate="1">
<record id="book_return_reminder" model="mail. template">
<field name="name">Book Return Reminder</field>
<field name="email_from">${object.book_id.create_ uid.email}</field>
<field name="email_to">${object.borrower_ id.email}</field>
<field name="subject">Reminder for book return</field>
<field name="model_id" ref="my_library.model_ library_book_rent"/>
<field name="body_html">
<![CDATA[
<p>Dear ${object.borrower_id.name},</p> <p>You had rented the
<b>${object.book_id.name}</b> book on ${format_date(object.rent_date)}
<br/>
The due date of book is <b style="color:red;">${format_date(object.return_date)}.</b>
</p> <br/>
<p>Best regards,
<br/> Librarian</p>
]]>
</field>
</record>
- 注册文件
'data':[
...
'data/mail_template.xml'
]
- 在library.book.rent模型的form视图添加Send reminder按钮
<header>
<button name="book_return" string="Return the Book" states="ongoing" type="object"/>
<button name="book_return_reminder" string="Send reminder" states="ongoing" type="object"/>
<field name="state" widget="statusbar"/>
</header>
- 添加book_return_reminder()方法:
def book_return_reminder(self):
template_id = self.env.ref('my_library.book_return_
reminder') self.message_post_with_template(template_id.id)
更新模块,展示如下:
原理
步骤1,我们创建了基于数据的动态生成的Jinja模板。邮件模板存储在mail.template模型中。主要字段如下:
- name: 模板的名称
- email_from: 邮件发送人
- email_to: 收件人
- email_cc: 抄送人
- subject: 主题
- model_id: 邮件模板所关联的对象
- body_html: 邮件的模板的正文。在正文中,我们可以使用基于Jinja语法的变量、循环、条件等。可在Jinja 详细了解。通常我们使用CDATA标签包裹正文,将其标记为字符数据。
- auto_delete: 标识是否在邮件发送后自动删除。默认为False。
- scheduled_date: 邮件计划发送的时间。
信息
我们可以使用${}来设置动态值,比如email_form, email_to, email_cc, subject, scheduled_date和lang。
在body_html字段中,我们使用了${object.borrower_id.name}。此处的object就是library.book.rent的记录。在渲染的时候,${object.borrower_id.name}将被替换为借阅者的姓名。还有几个类似于Object的变量或函数,如下:
- object: 代表当前模型的记录。
- format_date: 代表格式化date-time的方法。
- format_datetime: 代表将UTC时间转化为另一个时区的方法。
- format_amount: 将float类型转化为带有货币类型的字符串。
- format_duration: 将float转化为时间格式,比如,1.5=>01:30。
- user: 代表当前用户。
- ctx: 代表环境上线文的字典。
小贴士
我们可以在开发这模式下,点击Settings | Technical | Email | Templates菜单查看到邮件模板列表。form视图下还提供了预览模板的功能。
步骤2,在manifest文件中注册模板。
步骤3,添加激活book_return_reminder()方法的按钮,可用于给关注者发送邮件。
步骤4,message_post_with_template()方法用于发送邮件模板。该方法是通过继承模型mail.thread实现的。为了发送邮件,我们需要将模板的ID作为参数传递给函数。
更多
message_post_with_tempalte()函数用于发送Jinja格式的邮件。如果我们想发送纯文本的邮件,可如下:
self.message_post(body="Please return your book on time")
所有的关注者都将收到Please return your book on time的消息。如果我们想记录该信息,可在调用函数的时候添加subtype_id参数。
通过QWeb模板发送邮件
本节,我们将学习发送QWeb样式的邮件。
准备
步骤
- 添加my_library/data/mail_template.xml QWeb模板文件:
<template id="book_return_reminder_qweb">
<p>Dear <span t-field="object.borrower_id.name"/>,</p>
<p>You had rented the<b><span t-field="object.book_id.name"/></b> book on <span t-field="object.rent_date"/>
<br/>
The due date of book is <b style="color:red;">
<span t-field="object.return_date"/>
</b>
</p>
<br/>
<p>Best regards, <br/>
Librarian
</p>
</template>
- 添加按钮:
<header>
<button name="book_return" string="Return the Book" states="ongoing" type="object"/>
<button name="book_return_reminder" string="Send reminder" states="ongoing" type="object"/>
<button name="book_return_reminder_qweb" string="Send reminder(QWeb)" states="ongoing" type="object"/>
<field name="state" widget="statusbar"/>
</header>
- 在library.book.rent模型中添加book_return_reminder_qweb()方法:
def book_return_reminder_qweb(self):
self.message_post_with_view('my_library.book_return_reminder_qweb')
- 更新模块,点击按钮后邮件如下:
原理
步骤1,我们创建了ID为book_return_reminder_qweb的QWeb模板。在模板中,我们并没有使用format_date()方法,这是因为QWeb渲染引擎将会自动根据用户的语言处理时间。同样的情况还有format_amount()方法。
步骤2,我们添加了可触发book_return_reminder_qweb()的按钮。
步骤3,message_post_with_view()用于发送邮件,该方法定义在mai.thread模型中。
QWeb模板与Jinja模板有如下几点不同:
- 在邮件模板中,我们可通过定义在Object变量获取动态值。另一方面,在QWeb模板中,我们可以在渲染的时候在上下文通过values传递变量值。
self.message_post_with_view(
'my_library.book_return_reminder_qweb', values={'extra_data': 'test'}
)
-
在Jinja模板中,我们需要使用format_date、format_tz、format_amount方法管理日期、时区及货币的格式化。但在QWeb模板中,渲染器将自动转化。
-
在Jinja中,是不能修改已有的Jinja模板的。而在QWeb中,我们可以通过继承实现对模板的修改。详细内容可在第14章中学习。
-
您可以直接从消息生成器中选择和使用Jinja模板。在下面的屏幕截图中,右下角的下拉菜单用于选择Jinja模板:
-
但在我们无法直接在消息生成器中使用QWeb模板。
更多
message_post、message_post_with_template及message_post_with_view均可在用户配置中实现。当用户在配置页面修改了通知方式,用户将无法收到邮件,而是在odoo的通知系统中收到消息提醒。此外,Odoo消息线程遵循一个称为子类型的概念。
子类型仅用于接收您感兴趣的信息的电子邮件。您可以在message_post_*方法中传递额外的参数subtype_id,以根据子类型发送电子邮件。通常,用户将从Follow按钮的下拉列表中管理其子类型。假设用户将其子类型设置为:
- 管理邮件别名
邮件别名是odoo中的一个特性,可通过接收到的邮件创建记录。最简单的例子是销售团队。我们只需要发邮件给sale@yourdomain.com,odoo就会在销售团队的crm.lead模型中创建一条新的记录。本节,我们将创建一个用于创建图书借阅记录的邮件别名。
准备
本节我们将继续使用my_library模块。我们将创建邮件地址为rent@yourdomain.com的邮件别名。如果你发邮件给这个地址,邮件主题为图书的名字,那么odoo将会自动创建一个library.book.rent的记录。
步骤
- 在my_library/data/mail_template.xml文件中创建邮件别名:
<record id="mail_alias_rent" model="mail.alias">
<field name="alias_name">rent</field>
<field name="alias_model_id" ref="model_library_book_prent"/>
<field name="alias_user_id" ref="base.user_admin"/>
<field name="alias_contact">partners</field>
</record>
- 在my_library/models/library_book_rent.py文件中添加引用:
import re
from odoo.tools import email_split, email_escape_char
- 在library.book.rent模型中重写message_new()方法:
@api.model
def message_new(self, msg_dict, custom_values=None):
self = self.with_content(default_user_id=False)
if custom_values is None:
custom_values = {}
regex = re.compile("^\[(.*)\]")
match = regex.match(msg_dict.get('subject')).group(1)
book_id = self.env['library.book'].search([
('name', '=', match),
('state', '=', 'available')
], limit=1)
custom_values['book_id'] = book_id.id
email_from = email_escape_char(email_split(msg_dict.get('from'))[0])
custom_values['borrower_id'] = self._search_on_partner(email_from)
return super(LibraryBookRent, self).message_new(msg_dict, custom_values)
更新my_library模块,给rent@yourdomain.com发送邮件。确保邮件的主题符合要求,比如[Odoo 14 Development Cookbook] Request to borrow this book
。这将会创建一条新的借阅记录,如下:
原理
步骤1,我们创建了mail.alias记录。这个别名将会处理rent@yourdomain.com邮件地址的内容。如果我们给这个地址发送邮件,odoo将会在Library.book.rent模型中创建一条新的记录。我们可以在Settings | Technical | Email | Aliases查看邮件别名列表。
- alias_name: 代表邮件地址的别名。
- alias_model_id: 代表将根据接收到的邮件后所创建记录的模型。
- alias_user_id: 代表当邮件过来的时候,用哪个账户进行创建新纪录。
- alias_contact: 代表表名的权限配置。可选项为everyone, partners, followers, employees.
- alias_defaults: 当接收到邮件后,odoo将会自动创建一条新的记录。该字段可用于设置默认值。
步骤2,添加必要的引用。
步骤3,重写message_new()方法。该方法将在接收到新邮件的时候自动触发。该方法有两个参数:
- msg_dict: 包含到接收到的邮件的相关内容,比发件人地址、接收人地址、主题及邮件正文。
- custom_values: 代表创建记录时的自定义值。与alias_defaults的作用类似。
更多
一些业务模型有时需要针对每一条记录进行区分别名。比如,在销售团队模型中,针对不同的团队创建不同的别名。比如,为印度的团队创建sale-in@example.com,为比利时的团队创建sale-be@example.com。如果我们打算在模型中管理别名,我们可以在我们的模型中继承mail.alias.mixin。
class Team(models.Model):
_name = 'crm.team'
_inherit = ['mail.alias.mixin', 'mail.thread']
现在,我们可以在form视图中添加alias_name字段了,这用终端用户可以自行添加别名内容了。
记录在聊天中用户改变的内容
Odoo框架提供了一个内置的工具来记录chatter中的字段更改。本节我们将启用邮件日志功能,用于记录某些字段的修改。
准备
步骤
调整某些字段的定义,这样可以在改变字段内容的时候实现自动记录日志。如下:
class LibraryBookRent(models.Model):
_name = 'library.book.rent'
_inherit = ['mail.thread', 'mail.activity.mixin']
book_id = fields.Many2one('library.book', 'Book', required=True)
borrower_id = fields.Many2one('res.partner', 'Borrower', required=True)
state = fields.Selection([('ongoing', 'Ongoing'),('returned','Returned')],'State', default='ongoing', required=True, tracking=True)
rent_date = fields.Date(default.fields.Date.today, tracking=True)
return_date = fields.Date(tracking=True)
更新模块,创建一条新的记录并修改,可如下内容:
当我们修改state, rent_date, return_date时,都可以清晰的看到修改的内容。
原理
当您设置tracking=True属性时,每当您更新字段值时,Odoo将添加一个在chatter中更改的日志。如果对多个记录启用跟踪,并且希望在跟踪值中提供序列,还可以在跟踪参数中传递如下数字:tracking=20。当传递tracking=True时,将使用默认序列,即100。
track_visibility特性相关的代码定义在mail.thread模型中。
定期发送摘要
odoo框架内置了定期发送摘要邮件的功能。通过摘要邮件,我们可以发送商业KPI的相关内容。本节,我们将给管理员发送已借阅的图书。
准备
步骤
- 继承digest.digest模型并添加KPI字段:
class Digest(models.Model):
_inherit = 'digest.digest'
kpi_book_rent = fields.Boolean('Book Rent')
kpi_book_rent_value = fields.Integer(compute='_compute_kpi_book_rent_value')
def _compute_kpi_book_rent_value(self):
for record in self:
start, end, company = record._get_kpi_compute_parameters()
record.kpi_book_rent_value = self.env['library.book.rent'].search_count([
('create_date', '>=', start),
('create_date', '<', end)
])
- 继承digest.digest模型的form视图并添加KPI字段:
<?xml version='1.0' encoding='utf-8'?>
<odoo>
<record id="digest_digest_view_form" model="ir. ui.view">
<field name="name">digest.digest.view.form. inherit.library</field>
<field name="model">digest.digest</field>
<field name="inherit_id" ref="digest.digest_ digest_view_form"/>
<field name="arch" type="xml">
<xpath expr="//group[@name='kpi_general']" position="after">
<group name="kpi_library" string="Library">
<field name="kpi_book_rent"/>
</group>
</xpath>
</field>
</record>
</odoo>
更新模块,可在Settings | Technical | Emails | Digest Emails中查看如下内容:
但我们启用了该功能并订阅了摘要邮件后,我们将收到相关提醒邮件喽。
原理
为了创建自定义的摘要邮件,我们需要Boolean字段(用于启停KPI功能)及compute字段(用于获取KPI的值)。我们compute字段中使用了_get_kpi_compute_parameters()函数。这个函数由三个返回值,开始日期、结束日期以及公司记录。我们可以使用这三个值生成KPI。在本例中,我们返回了特定周期内借阅图书的数量。如果我们的KPI是多站点的,那么我们还需要使用company参数。
步骤2,我们在digest form视图添加了用于启停摘要邮件的字段。如果启用了该功能,则可以收到摘要邮件了。
本文来自博客园,作者:老韩头的开发日常,转载请注明原文链接:https://www.cnblogs.com/xushuotec/p/14587849.html