✅ Overview
- Subject
- Body (HTML/text)
- Sender and recipient addresses
🔧 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 }}
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.