Email Template Rendering Errors
When sending emails or previewing templates, you encounter:
QWebException: 't-esc' evaluation error:
NameError: name 'object' is not defined
ValueError: Template rendering failed:
UndefinedError: 'sale.order' object has no attribute 'partner_name'
QWebException: Error while rendering template 'mail.message_notification_email'
jinja2.exceptions.TemplateSyntaxError: unexpected '}' at line 5Understanding Odoo Email Templates
Odoo uses two template engines for emails:
| Engine | Syntax | Used In |
|---|---|---|
| QWeb | t-esc, t-if, t-foreach | Mail templates (Odoo 17+) |
| Jinja2 | {{ }}, {% %} | Legacy templates, dynamic placeholders |
Fix 1: QWeb Template Errors
Fix 2: Jinja2 Template Errors
# Jinja uses {{ }} for expressions and {% %} for control flow
# Wrong: missing closing bracket
Dear {{ object.partner_id.name },
# Right:
Dear {{ object.partner_id.name }},
# Wrong: using Python methods not available in Jinja sandbox
{{ object.order_line.sorted(key=lambda x: x.price) }}
# Right: use simpler expressions
{{ object.order_line }}
# Wrong: accessing non-existent field
{{ object.total_price }}
# Right: use correct field
{{ object.amount_total }}Fix 3: Dynamic Placeholder Syntax
# In the email template body editor:
# Use the "Dynamic Placeholder" button to insert correct references
# Correct placeholder syntax:
# {{ object.name }} — order name
# {{ object.partner_id.name }} — customer name
# {{ object.amount_total }} — total amount
# {{ object.date_order }} — order date
# Format dates:
# {{ format_date(object.date_order) }}
# {{ format_datetime(object.create_date) }}
# Format currency:
# {{ format_amount(object.amount_total, object.currency_id) }}Fix 4: Template Preview Crashes
# The preview needs a real record to render against
# Settings > Technical > Email Templates > select template
# Click "Preview"
# Select a record (e.g., a specific sale order)
# If preview crashes:
# The template references a field that doesn't exist on the model
# Or the selected record has missing related data
# Debug: try with different records
# Some records may have NULL values that cause rendering errors
# Safe access pattern:
# {{ object.partner_id and object.partner_id.name or 'N/A' }}Fix 5: Inherited Template Errors
# If a custom module modified the email template:
# The modification may reference removed or renamed fields
# Find template overrides:
sudo -u postgres psql -d mydb -c "
SELECT mt.name, mt.model, mt.subject, imd.module
FROM mail_template mt
JOIN ir_model_data imd ON imd.res_id = mt.id AND imd.model = 'mail.template'
WHERE mt.model = 'sale.order';
"
# Reset to default:
# Settings > Technical > Email Templates > select template
# If there's a "Reset to Default" option, use it
# Or manually fix the template bodyFix 6: Missing Context Variables
# Some variables are only available in specific contexts:
# 'object' — the record being emailed
# 'ctx' or 'context' — the Odoo context dictionary
# 'user' — the current user
# 'company' — the current company
# 'website' — only in website email context
# If a variable is undefined, it may be:
# - A context variable not passed by the sending method
# - A variable from a different template engine version
# - A custom variable from a module that was uninstalledFix 7: Test Email Sending
# Always test templates before using in production:
# Method 1: Preview in template editor
# Settings > Technical > Email Templates > Preview
# Method 2: Send test email
# Open a record (e.g., sale order) > Send by Email
# Verify the rendered email before sending
# Method 3: Check mail queue
# Settings > Technical > Emails > check for failed emails
# Failed emails show the rendering error in the bodyPrevention
DeployMonkey's AI agent validates email template syntax during module deployment. The agent tests template rendering against sample records and detects field reference errors before they cause email failures.