How to Send an Email in Odoo

Email is a cheap option if we want to send notification to customer, compared to sms or whatsapp. With email we can also make a more attractive design and a longer message. So we can have more freedom in making message.

Before sending an email to customer, we must set up the Outgoing Email Server. In debug mode, enter Settings >> Technical >> Email >> Outgoing Email Servers menu. Then, make a configuration like shown below.

When we send an email to customer, odoo will use the email that we registered in Outgoing Email Servers. Fill in according to the email you use, and make sure to click the Test Connection button to check whether the configuration that we have made are correct or not. If the Test Connection fail, of course, the email can not be sent.

In order to send an email from the model, our model must inherit to the mail.thread model as shown in the code below.

# -*- coding: utf-8 -*-

from odoo import api, fields, models, _

class ProductRepair(models.Model):
    _name = 'product.repair'
    # we must inherit mail.thread model if we want to be able to send email from our model
    _inherit = ['mail.thread'] 
    _description = "Product Repair"

    product_id = fields.Many2one('product.product', string='Product')
    partner_id = fields.Many2one('res.partner', string='Customer')
    state = fields.Selection([
        ('draft', 'Draft'),
        ('in_progress', 'In Progress'),
        ('finish', 'Finished')
    ], default='draft')

There are several methods of the mail.thread model that can be used to send email, one of them is the message_post_with_template method. With this method we can send an email with a template in html format, so with the help of css we can create a nice email design. Here is an example of an email template for the product.repair model above.

<?xml version="1.0" encoding="utf-8"?>
<odoo>
    <data noupdate="0">        

        <record id="product_repair_finish_email_template" model="mail.template">
            <field name="name">Product Repair Finish Email Template</field>
            <field name="model_id" ref="tutorial_email.model_product_repair"/>
            <field name="email_from">Ngasturi Teknik <z.nry27@gmail.com></field>
            <field name="partner_to">${object.partner_id.id}</field>
            <field name="subject">Finished Repair Notification </field>
            <field name="body_html" type="html">
<div style="font-family: 'sans-serif'; padding: 10px; max-width:700px; background-color: white; border: 4px solid #0E9C48;">
    <h3 style="background-color: #0E9C48; color: white; text-align: center; padding: 20px 0px; margin-bottom: 10px;">
        NGASTURI TEKNIK
    </h3>
    <h4>Hai ${object.partner_id.name}</h4>
    <p>
        We hereby inform you that the repair for your ${object.product_id.name} product has:
    </p>

    <p style="text-align: center; margin-bottom: 20px; margin-top: 20px;">
        <span style="background-color: #0E9C48; color: white; padding: 10px 10px;">FINISHED</span>
    </p>

    <p>
        You can pick up the product during our working hours: <b>Monday - Friday 09:00 - 17:00</b>.
    </p>

    <p>Thank You.</p>
    
</div>
            </field>
        </record>
    </data>
</odoo>

When we finish installing the module, the template above can be seen in the preview from the Settings >> Technical >> Email >> Templates menu.

To insert dynamic data from our model to our email template, we can use the code as below.

# field_name is the name of our field in our model
${object.field_name}

The message that you want to display to customer can be created using html and css code. But remember, not all css code can be used in email, one of the css code that doesn’t work in email is position. So there is a possibility that the preview of the email might be different compared to when we open it in the email client application.

Next, to send an email, we just need to call the message_post_with_template method like in the code below.

def send_finish_email(self):
    # search the email template based on external id
    template_id = self.env['ir.model.data'].xmlid_to_res_id('tutorial_email.product_repair_finish_email_template', raise_if_not_found=False)
    if template_id:
        for rec in self:
            rec.with_context(force_send=True).message_post_with_template(template_id)

If the email is not received immediately, it can be checked in the Settings >> Technical >> Email >> Emails menu, maybe it’s still waiting to be sent by odoo. You can also set up the Email Queue Manager cron job in the Settings >> Technical >> Automation >> Scheduled Actions menu, then look for Mail: Email Queue Manager. The default cron job is to run every 1 hour, if you want the customer to receive an email immediately, lower the configuration, for example every 10 minutes.

The image below is the appearance of an email that I received in gmail.

You can see that there is still odoo branding in the email. To remove that branding we have to create a new template, like this.

<template id="message_no_odoo_branding">
    <div t-raw="message.body"/>
</template>

Then change the send_finish_email method to use the no branding template that we just created above as the layout parameter, like the code below.

def send_finish_email(self):
    # search the email template based on external id
    template_id = self.env['ir.model.data'].xmlid_to_res_id('tutorial_email.product_repair_finish_email_template', raise_if_not_found=False)
    if template_id:
        for rec in self:
            rec.with_context(force_send=True).message_post_with_template(template_id, email_layout_xmlid="tutorial_email.message_no_odoo_branding")

You can see now that the odoo branding is gone.

Download the source code here.

Related Article

8 Replies to “How to Send an Email in Odoo”

    1. yes. just use img tag, with src to your image URL. please use https url, i have issue some mail client not display the image with http url, but ok with https.

    1. We can send the binary field as attachment with message_post_with_template, here is how to do it:

      # the content of binary field is stored in ir.attachment model, we must get its id first, then save it as a list/tuple
      # please ensure the attachment attribute in your binary field is True like this
      # my_document = fields.Binary(attachment=True)
      
      attachment_ids = self.env['ir.attachment'].search([('res_model', '=', 'your.model.like.sale.order'), ('res_id', '=', your_record.id),('res_field', '=', 'your_binary_field_name_like_my_document')]).ids
      
      # then pass the attachment_ids variable to message_post_with_template function
      rec.with_context(force_send=True).message_post_with_template(template_id, attachment_ids=attachment_ids)
      
    1. It depends on your email provider, for Gmail we must create an App Password, for Microsoft Outlook 365 we must configure the OAuth client credential.

Leave a Reply to Djago Cancel reply

Your email address will not be published. Required fields are marked *