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.