Email body templates
This directory holds the built-in HTML body of the email notifier, default-email.html.j2. This page covers what is specific to email body templates. For templates in general (rule templates and notifier templates, the variables, the valerter filters, Markdown bodies), see the template guide. For the email notifier settings, see Email (SMTP).
An email body template is a notifier template written with minijinja, a Jinja2 implementation. The body is sent as HTML (Content-Type: text/html).
Default template
Without body_template or body_template_file, emails use default-email.html.j2, embedded in the binary: a responsive layout with the alert title in the header (in the template’s accent_color when it has one), the body, and a footer with the rule name and the log time. The .deb package also installs a copy in /etc/valerter/templates/, to start a custom template from.
Custom templates
| Option | Description |
|---|---|
body_template |
Inline template string |
body_template_file |
Path to a template file, absolute or relative to the directory of the configuration file (at most 1 MB, UTF-8) |
Priority: body_template_file > body_template > default template. When both are set, valerter logs a warning and uses body_template_file.
We recommend the .html.j2 extension (for example my-alert.html.j2), but any extension works.
Available variables
An email body template sees the notifier template variables, plus accent_color. The event fields are under log (see Rule templates and notifier templates).
| Variable | Type | Description |
|---|---|---|
title |
string | Rendered title of the rule template |
body |
HTML | The body of the alert, already HTML: see The body variable |
rule_name |
string | Name of the rule that triggered |
vl_source |
string | Name of the VictoriaLogs source the event came from |
accent_color |
string or none | accent_color of the rule template (for example #ff0000), none when it has none |
log_timestamp |
string | Original log timestamp in ISO 8601 format (for VictoriaLogs search) |
log_timestamp_formatted |
string | Human-readable timestamp (follows the timestamp_timezone setting) |
log |
object | Every field of the event: {{ log.host }}, {{ log["k8s.pod"] }} (see Fields with special characters) |
subject_template sees the same variables, but it is plain text: it is not HTML-escaped, and its body is the plain-text rendering of the body.
The body variable
In the body template, body is, by priority:
- the rendered
email_body_htmlof the rule template, when it defines one; - otherwise, for a rule template with
body_format: markdown, the HTML rendering of its Markdownbody; - otherwise, the plain
body(in practice the fallback message sent when the rule template fails to render), HTML-escaped.
The first two are already HTML and are inserted unescaped: write {{ body }} alone, not <p>{{ body }}</p> and not {{ body | safe }}.
A rule template sent to an email notifier must define email_body_html, unless its body is Markdown (body_format: markdown): its HTML rendering is then the email body. --validate reports a rule template that breaks this rule (see The email_body_html requirement and Markdown bodies). The format key of an email notifier accepts only html, its default.
accent_color
accent_color is none, not undefined, when the rule template has no accent color. {{ accent_color | default('#ff0000') }} would therefore render None: pass true as the second argument of default, which also replaces none and empty values, or test the value like the default template does.
{{ accent_color | default('#ff0000', true) }}
{% if accent_color %}{{ accent_color }}{% else %}#111827{% endif %}
Examples
Default template
notifiers:
email-ops:
type: email
smtp:
host: smtp.example.com
port: 587
from: "valerter@example.com"
to:
- "ops@example.com"
subject_template: "[{{ rule_name }}] {{ title }}"
Custom template file
notifiers:
email-custom:
type: email
smtp:
host: smtp.example.com
port: 587
from: "valerter@example.com"
to:
- "ops@example.com"
subject_template: "[{{ rule_name | upper }}] {{ title }}"
body_template_file: "templates/my-alert.html.j2"
The file must exist when the configuration is loaded: --validate fails otherwise.
Inline template
notifiers:
email-inline:
type: email
smtp:
host: smtp.example.com
port: 587
from: "valerter@example.com"
to:
- "ops@example.com"
subject_template: "Alert: {{ title }}"
body_template: |
<html>
<body>
<h1 style="color: {{ accent_color | default('#cc0000', true) }}">{{ title }}</h1>
{{ body }}
<hr>
<small>Rule: {{ rule_name }} (source: {{ vl_source }})</small>
</body>
</html>
Writing templates
Basic structure
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ title }}</title>
</head>
<body>
<div style="padding: 20px; border-left: 4px solid {{ accent_color | default('#ff0000', true) }};">
<h1>{{ title }}</h1>
{{ body }}
<small>
Rule: <code>{{ rule_name }}</code><br>
Host: {{ log.host }}<br>
Log time: {{ log_timestamp_formatted }}
</small>
</div>
</body>
</html>
Tips
- Use inline CSS - Many email clients don’t support
<style>blocks well - Use tables for layout - Flexbox/Grid support is limited in email clients
- Test across clients - Gmail, Outlook, Apple Mail render differently
- Keep it simple - Complex layouts often break
Security
The body template is rendered with HTML auto-escaping: title, rule_name, vl_source, accent_color, the timestamps and every log field are escaped, so log data cannot inject markup into the email.
For example, <script>alert('xss')</script> in a log field becomes:
<script>alert('xss')</script>
body is the exception: when it comes from email_body_html or from a Markdown body, it is inserted unescaped, because it is already HTML. The values it contains were escaped when it was rendered: email_body_html is itself rendered with HTML auto-escaping, so only the markup written in the rule template stays HTML, and the HTML rendering of a Markdown body escapes all its text, HTML tags written in the Markdown included.