Creating and sending email templates

< / / / / / >
Intermediate
Framework Email
V13.0
V 13.0
+/- 14 minutes
Written by Yenthe Van Ginneken
(0)

Quick scroll

1. Introduction

For a lot of interactions with customers you'll need email features. In most cases these emails are very generic though and you only want a few values to be personalised, such as the name. In this tutorial you will learn how to create email templates and how to add variables in the template to show dynamic values. Finally you'll learn how to load an email template in the email dialog from Odoo.

In this tutorial we will create an email template to wish people a happy birthday. The email template will have variables to add in the contact its name and the company name. Finally we will add a "Send happy birthday" button on the contact form that loads our email template by default.

2. Adding the dependency

Before you can start creating email templates you will need to create a new module and configure the manifest.py correctly. Open up your manifest.py and add 'mail' as a dependency. As we'll use email features in our module we'll need this dependency. Otherwise we would not be able to use mail templates and dialogs. Let us also add a dependency to 'contacts' so that we can modify the contact form:

                    'depends': ['contacts', 'mail'],                                    

3. Creating the email template

The first thing that we need is an email template. Let's create a new file named 'mail_template_data.xml' in the 'data' folder of your custom module. Now that you have the correct dependencies it is time to create the email template itself. In Odoo email templates are build in XML and the moment that you would send the email template to somebody the Jinja2 will render your email and fill it up with the corresponding data. Since we're creating an email template we should use the noupdate="1" tag though. So, why do we use this tag? If you wouldn't use it the email template would be updated (and overridden) every time that you would update the module, which would result in you losing data if you've changed something. Your XML file should now look like this:

                                                                                

The next step is to create a new XML record. Just have a look at the following code and try to understand it, I will explain every line in detail under the code:

                                                                                

3.1 Understanding the email template

So, what exactly does this do? The very first line, which holds the record id and record model are very important. Every email template that you ever want to create should be to the model 'mail.template'. This is where all email templates are saved and you should add yours there too. Now, let us go over it line by the line.

  • The 'name' field: This gives your email template a name, which is also shown if you look at all templates under Settings > Technical > Email > Templates.
  • The 'model_id' field: This field will tell your email template on which model it will be used and where it should get data from. It always starts with 'model_' and should then contain the model name. It is important to replace the dots in a model name by underscores. So the model 'res.partner' should become 'res_partner'.
  • The 'email_from' field: This will contain the email address from where the email is being sent. In this example it is the email from the person that clicks on the send button.
  • The 'partner_to' field: links to the ID of the current contact, it will automatically load the email from this contact and send the email to that user.
  • The 'subject' field: This will be the title of the email that is being sent to the user.
  • The 'body_html' field: This is where you can design the content of the email. You can use HTML and Jinja2 variables in this part too so you can style the template and pre-fill data before it is being sent.

3.2 Understanding Jinja2 variables

So, what about those Jinja2 variables? Jinja is basically a modern and designer-friendly templating language for Python that has been integrated in Odoo. You can get values from any field by simpling using ${object.your_field_name}. When the email is being sent out Odoo/Jinja will then automatically convert these calls to the value set on the field of this specific record. You can also get values from another model, for example ${object.user_id.name}, to get the name of the salesperson. You can find a lot of documentation and examples on the Jinja website.

4. Adding a send button on the form

4.1 Inheriting the form view

Now that we have the email template created we also want an easy way to send it to our contact(s). The easiest way to do this in Odoo is to create a button on the form, add a function to it and then return the email dialog from this function. Create a new XML file named 'res_partner_view.xml' in the 'views' folder of your custom module. In this file we'll inherit the contacts form and we will add a header with a button inside that contains a function name:

                                                                                

This view will add a button with the text "Send birthday email" at the top of the contacts form. Because of the type="object" and the button name we can call a Python function now.

4.2 Creating the function

Now create a new Python file named 'res_partner.py' in your 'models' folder. In this Python file we'll inherit the 'res.partner' model and we will create a new Python function named 'action_send_birthday_email':

                    # -*- coding: utf-8 -*-from odoo import api, fields, modelsclass ResPartner(models.Model):    _inherit = 'res.partner'    def action_send_birthday_email(self):        self.ensure_one()                                    

Before we can open the email dialog with our email template loaded by default we need four things. We need to find the email template, then load the composer and then set context values on it. Finally we will need to return an action to show the dialog to the end user. First we need to find the template id with the 'get_object_reference' function. If it is found we should set the ID, otherwise we should set it to False:

                    ir_model_data = self.env['ir.model.data']try:    template_id = ir_model_data.get_object_reference('tutorial_create_email_template', 'email_template_happy_birthday')[1]except ValueError:    template_id = False                                    

As you can see you can find the template by combining the technical name of your app, in this example 'tutorial_create_email_template', and the name of your email template. Now we need to find the composer, also with the 'get_object_reference'. If it is found we should set the ID, otherwise we should set it to False:

                    try:    compose_form_id = ir_model_data.get_object_reference('mail', 'email_compose_message_wizard_form')[1]except ValueError:    compose_form_id = False                                    

The next step is to set some context values for our mail dialog. Without this Odoo wouldn't know how to load the dialog:

                    ctx = {    'default_model': 'res.partner',    'default_res_id': self.ids[0],    'default_use_template': bool(template_id),    'default_template_id': template_id,    'default_composition_mode': 'comment',    'force_email': True}                                    

And, finally, we have to return all our values to the frontend so that the user gets the email dialog with our template shown by default:

                    return {    'type': 'ir.actions.act_window',    'view_type': 'form',    'view_mode': 'form',    'res_model': 'mail.compose.message',    'views': [(compose_form_id, 'form')],    'view_id': compose_form_id,    'target': 'new',    'context': ctx,}                                    

To return the dialog we need the above values by default. We return an action window to load the dialog and we tell Odoo that we want to use the default composer. Because of the context being set Odoo also knows from which model we want to render the template and which default template we want to have set. Your final function should now look like this:

                        def action_send_birthday_email(self):        """        This function opens a window to compose an email, with the happy birthday template message loaded by default        """        self.ensure_one()        ir_model_data = self.env['ir.model.data']        try:            """            Find the email template that we've created in data/mail_template_data.xml            get_object_reference first needs the module name where the template is build and then the name            of the email template (the record id in XML).            """            template_id = ir_model_data.get_object_reference('tutorial_create_email_template', 'email_template_happy_birthday')[1]        except ValueError:            template_id = False        try:            """            Load the e-mail composer to show the e-mail template in            """            compose_form_id = ir_model_data.get_object_reference('mail', 'email_compose_message_wizard_form')[1]        except ValueError:            compose_form_id = False        ctx = {            # Model on which you load the e-mail dialog            'default_model': 'res.partner',            'default_res_id': self.ids[0],            # Checks if we have a template and sets it if Odoo found our e-mail template            'default_use_template': bool(template_id),            'default_template_id': template_id,            'default_composition_mode': 'comment',            'force_email': True        }        # Will show the e-mail dialog to the user in the frontend        return {            'type': 'ir.actions.act_window',            'view_type': 'form',            'view_mode': 'form',            'res_model': 'mail.compose.message',            'views': [(compose_form_id, 'form')],            'view_id': compose_form_id,            'target': 'new',            'context': ctx,        }                                    

That's it! If you now save all your changes and install your custom module you will see the "Send birthday email". If you click on it you'll see the email dialog being loaded with our custom email template: Send email preview dialog

5. Conclusion

Email templates are a great way to save time and send consistent emails to your customers. If you create an email template and add a button you can make it very easy and fast for your users to send emails to customers. If you have a process that always sends an email and if the email is quite unique you should really try to add email templates. They'll make the process easier for everybody and they'll save your company a lot of money and time. It will take you some time to create the template and function but once you get the hang of it you'll notice how easy and flexible it is!