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.