Email Template Rendering with Jinja and Safe Evaluation in Odoo


✅ Overview

Odoo uses Jinja2 templating and safe evaluation context to dynamically render email content such as:

  • Subject
  • Body (HTML/text)
  • Sender and recipient addresses

This allows emails to be personalized per record (e.g., customer name, product details) using secure and controlled access to model fields and functions.



🔧 Where Jinja Is Used

Jinja expressions are commonly used in:


Field

Used In

Subject

{{ object.name }}

Email Body (HTML)

<p>Hello {{ object.partner_id.name }}</p>

Sender Email

{{ user.email }}

Email To / CC

{{ object.user_id.email }}



📘 Basic Syntax of Jinja​


{{ object.name }}                   → Field value

{{ object.amount_total | float }}  → With filters

{% if object.state == 'draft' %}   → Conditional logic

  Draft Order

{% endif %}



🔒 Safe Evaluation (safe_eval)

Odoo restricts evaluation context to safe variables and methods only, to avoid security risks (e.g., executing arbitrary Python).



📌 Variables Available in Templates


Variable

Meaning

object

Current record (e.g., sale.order)

user

Current user (record of res.users)

ctx

Current context

format_tz()

Format datetime with timezone

format_date()

Format date

format_amount()

Format currency


Example 1: Custom Email Body

<p>Hello {{ object.partner_id.name }},</p>

<p>Your order <strong>{{ object.name }}</strong> has been confirmed with a total of 

<strong>{{ format_amount(object.amount_total, object.currency_id) }}</strong>.</p>

<p>Thanks,<br/>{{ user.company_id.name }}</p>


Example 2: Subject with Condition

{{ 'New Quotation' if object.state == 'draft' else 'Confirmed Order' }}


Example 3: Dynamic From Address

{{ user.email }}


🛠 How Rendering Works in Python​


Odoo uses the render_template() function from mail.template:

template = self.env.ref('sale.email_template_edi_sale')

body_html = template._render_template(template.body_html, 'sale.order', order.id)



🚫 Common Mistakes

Issue

Cause

UndefinedError: 'object' is undefined

Template used outside proper record context

Jinja syntax error

Missing {% endif %}, wrong brackets

HTML not rendering properly

Wrong field used (body_text instead of body_html)



✅ Summary Table

Concept

Description

Jinja2

Templating engine for email templates

object

Refers to the current record

user

Current user (sender)

format_* funcs

Helper functions to format values securely

safe_eval

Limits evaluation to safe variables

render_template()

Programmatic rendering of templates



🧠 Best Practices

  • Always use {{ }} for expressions and {% %} for control logic.
  • Use helper functions like format_amount() and format_date() instead of raw Python.
  • Avoid calling unsafe or complex methods directly inside the template.
  • Test templates via the "Send Test Email" feature in Developer Mode.