Mail assets
One directory holds everything an operator provides for mail signatures and templates: the managed signature catalog (signatures.yaml), the managed template catalog (templates.yaml) and the Signature Designer's additional templates with their policy file (designs.yaml). The directory is mounted from a ConfigMap, so its contents can be changed without deploying a new application version.
What users see is described under Signatures and templates.
The mail assets directory
The mail assets directory is mounted into the container, by default at /etc/mail-assets. Its contents are read at request time. Three features share the directory, and each one is enabled separately:
| File | Used by | Feature flag |
|---|---|---|
signatures.yaml | Managed signatures | io.ox/core//features/managedSignatures |
templates.yaml | Managed templates | io.ox/core//features/managedTemplates |
designs.yaml and any .html files | Signature Designer | io.ox/core//features/signatureDesigner |
A feature whose file is absent simply contributes nothing, so include only the keys you need. The following ConfigMap shows all of them:
apiVersion: v1
kind: ConfigMap
metadata:
name: mail-assets
data:
# Signature Designer: additional HTML templates and policy
my-template.html: |
<table>...</table>
designs.yaml: |
disabledIds:
- template-003
# Managed signatures
signatures.yaml: |
company_default:
title: Company Default
content: "<p>{{ fullName }}</p>"
# Managed templates
templates.yaml: |
welcome:
title: Welcome
content: "<p>Hi {{ fullName }}</p>"
Reference the ConfigMap in values.yaml:
mailAssets:
configMapName: mail-assets
Managed signatures
Administrators can provide centrally managed signatures that appear in every user's signature list. They are read-only and rendered with the user's own contact data at compose time.
Enable the feature in the App Suite middleware:
io.ox/core//features/managedSignatures: true
Then provide a signatures.yaml file in the mail assets directory.
signatures.yaml format
signatures.yaml is a YAML object map keyed by a stable identifier:
company_default:
title: Company Default Signature
insertion: below
content: |
<p>{{ fullName }}<br>{{ position }}<br>{{ company }}</p>
<p>{{ phone.work | tel }}<br>{{ email | mailto }}</p>
legal_notice:
title: Legal Notice
content: |
<p>{{ legal.disclaimer }}</p>
| Field | Required | Description |
|---|---|---|
title | No | Display name in the signature list. Falls back to the map key. |
content | Yes | HTML with placeholders, see Placeholders. |
insertion | No | above or below quoted text. Falls back to the user's default. |
Behavior
- Managed signatures appear above user signatures in settings, in definition order, with a "Predefined" badge.
- They are read-only. Users cannot edit or delete them, but can pick them as default.
- Placeholders render at compose time. The settings list shows the raw
{{ }}template. - A missing or malformed
signatures.yamlresults in an empty list. No error is shown.
Managed templates
Administrators can provide centrally managed mail templates that users can insert from the compose dropdown. They are read-only and rendered with the user's contact data at insert time.
Enable the feature in the App Suite middleware:
io.ox/core//features/managedTemplates: true
Then provide a templates.yaml file in the mail assets directory.
templates.yaml format
templates.yaml is a YAML object map keyed by a stable identifier:
welcome:
title: Welcome Email
content: |
<p>Dear {{ fullName }},</p>
<p>Welcome to {{ company }}!</p>
<p>Best regards,<br>The {{ company }} Team</p>
| Field | Required | Description |
|---|---|---|
title | No | Display name in the template list. Falls back to the map key. |
content | Yes | HTML with placeholders, see Placeholders. |
Behavior
- Managed templates appear above user templates in settings and in the compose dropdown, in definition order, with a "Predefined" badge.
- They are read-only. Users cannot edit or delete them.
- Placeholders render at insert time. The settings list shows the raw
{{ }}template. - A missing or malformed
templates.yamlresults in an empty list. No error is shown.
Signature Designer
The Signature Designer is a wizard that lets users build branded HTML signatures from a template gallery, filled in with their own contact data. Six built-in templates (template-000 through template-005) ship by default. Operators can supply additional templates and policy without deploying a new application version.
Enabling the Signature Designer
io.ox/core//features/signatureDesigner: true
This flag gates the wizard itself. It is independent of managedSignatures and managedTemplates.
The Designer also has a hard prerequisite: the setting io.ox/mail//snippet/maxImageLimit must be 0. The signature templates use images, so any other value disables the wizard, even when the feature flag is on. The corresponding middleware option is com.openexchange.mail.signature.maxImageLimit, which must be 0 (disabled).
How it works
- Templates are read at request time from the mail assets directory, by default
/etc/mail-assets. - Each
.htmlfile in that directory becomes one additional template. - An optional
designs.yamlin the same directory controls visibility, ordering, custom fields, default values and per-template metadata. - The built-in templates are always present. Operator templates are appended after them.
Built-in templates
Six templates (template-000 through template-005) ship with the application. Operator-provided template IDs (filenames without .html) must not conflict with these. Conflicting operator templates are silently ignored.
Use disabledIds or enabledIds in designs.yaml to control which built-ins are shown.
designs.yaml reference
| Field | Type | Description |
|---|---|---|
enabledIds | string[] | If set, only these template IDs are shown. All others are hidden. |
disabledIds | string[] | Hide specific templates by ID. |
order | string[] | Display order. Unlisted templates appear after ordered ones. |
customFields | object[] | Additional fields in the wizard, see below. |
defaults | object | Pre-fill values for any template field, keyed by field name. Takes priority over the user's contact model data, but is overridden by data the user has previously saved in the designer. |
labels | object | Override sidebar labels for any field, e.g. display_name: Full Name. |
templates | object | Per-template metadata keyed by template ID (filename without .html). See previewTheme and imageSlots below. |
customFields
Defines additional fields that appear in the wizard alongside the standard contact fields.
| Field | Type | Description |
|---|---|---|
id | string | Field name used as the Mustache variable in templates. |
label | string | Label shown in the wizard UI. |
step | "text" or "links" | Which wizard step the field appears in. Defaults to "text". |
preview | string | Placeholder value shown in the template gallery preview. |
previewTheme
Defines the theme colors used when rendering a template in the gallery. The values are passed as {{#theme}}{{background}}{{/theme}} and {{#theme}}{{text}}{{/theme}}, so they affect elements that use the theme, such as the profession badge and icon button backgrounds.
When the user selects a different theme in the designer, their selection overrides previewTheme during live editing. Defaults to { "background": "#ffffff", "text": "black" } if not set.
| Field | Type | Description |
|---|---|---|
background | CSS color string | e.g. "#000000" |
text | "white" or "black" | Controls text color and which icon variant (white or black) is used. |
imageSlots
Declares image fields used by the template so the gallery can show a correctly shaped placeholder before the user uploads an image. Does not affect upload controls in the designer. Those are determined by the presence of {{imageUrl}} in the template HTML.
| Field | Type | Description |
|---|---|---|
field | string | The Mustache variable name, e.g. "imageUrl". |
aspect | "square" or "banner" | Placeholder shape. "square" for profile photos, "banner" for wide header images. |
Placeholders
Placeholders apply to signature and template content, both the managed catalogs above and signatures users write themselves. They are rendered only when a signature or template is inserted in compose. In settings, the raw template stays visible and editable.
Basic placeholder:
{{ firstName }}
Placeholder with explicit format:
{{ company.website | link }}
Supported formats:
| Format | Result |
|---|---|
text | Escaped text output. This is the default. |
link | HTML link, adds https:// if no protocol is present. |
image | HTML image tag. |
mailto | Mail link. |
tel | Telephone link. |
The following placeholders are supported directly from user profile data.
Name fields
| Placeholder | Source |
|---|---|
{{ firstName }} | first_name |
{{ secondName }} | second_name |
{{ lastName }} | last_name |
{{ fullName }} | Derived full name |
{{ suffix }} | suffix |
{{ title }} | title |
Company and job fields
| Placeholder | Source | Default format |
|---|---|---|
{{ position }} | position | text |
{{ department }} | department | text |
{{ room }} | room_number | text |
{{ roomNumber }} | room_number | text |
{{ company }} | company | text |
{{ url }} | url | link |
Communication fields
| Placeholder | Source | Default format |
|---|---|---|
{{ email }} | email1 | mailto |
{{ email1 }} | email1 | mailto |
{{ phone.cell }} | cellular_telephone1 | tel |
{{ phone.mobile }} | cellular_telephone1 | tel |
{{ phone.home }} | telephone_home1 | tel |
{{ phone.work }} | telephone_business1 | tel |
{{ fax }} | fax_business | tel |
Home address fields
| Placeholder | Source |
|---|---|
{{ address.home.street }} | street_home |
{{ address.home.code }} | postal_code_home |
{{ address.home.postalCode }} | postal_code_home |
{{ address.home.city }} | city_home |
{{ address.home.state }} | state_home |
{{ address.home.country }} | country_home |
Work address fields
| Placeholder | Source |
|---|---|
{{ address.work.street }} | street_business |
{{ address.work.code }} | postal_code_business |
{{ address.work.postalCode }} | postal_code_business |
{{ address.work.city }} | city_business |
{{ address.work.state }} | state_business |
{{ address.work.country }} | country_business |
Configured placeholder data
Additional placeholder values can be configured under:
io.ox/mail/signatures/data/**
These values are useful for company-wide data that should not come from the user profile, for example website, logo, hotline, legal text or campaign links.
io.ox/mail:
signatures:
data:
company:
website: portal.example.test
email: info@example.test
phone: +49 123 456789
logo: https://example.test/logo.png
legal:
disclaimer: Confidential. Internal use only.
campaign:
spring:
url: https://example.test/spring
This can be used in signatures like:
<p>{{ fullName }}</p>
<p>{{ position }}</p>
<p>{{ email }}</p>
<p>{{ company.website | link }}</p>
<p>{{ company.phone }}</p>
<p><img data-src="{{ company.logo }}"></p>
<p>{{ legal.disclaimer }}</p>
<p>{{ campaign.spring.url | link }}</p>
Notes:
company.website,company.email,company.phoneandcompany.logohave built-in default formats.- Other configured keys under
company.*,campaign.*orlegal.*default to plain text unless a format is given explicitly. - Unknown placeholders remain unchanged, so missing values stay visible.
Template variables
Signature Designer templates use their own variable set. They are rendered with Mustache, not with the placeholder syntax described above. Wrap every variable in a section guard so that rows with no value collapse rather than render empty:
{{#display_name}}<strong>{{display_name}}</strong>{{/display_name}}
Contact fields
All standard OX contact model fields are available and pre-filled from the user's own contact data. See the OX HTTP API contact model for the full list of field names.
Commonly used fields:
| Variable | Description |
|---|---|
{{display_name}} | Full display name |
{{first_name}} | Given name |
{{last_name}} | Surname |
{{title}} | Title, e.g. Dr. |
{{profession}} | Profession / role |
{{position}} | Position / job title |
{{department}} | Department |
{{company}} | Company name |
{{email1}} | Email address |
{{telephone_business1}} | Business phone |
{{cellular_telephone1}} | Mobile phone |
Designer-specific fields
These fields are not part of the contact model but are added by the Signature Designer:
| Variable | Description |
|---|---|
{{address}} | Postal address, derived from the user's business address (falls back to home, then other). Multi-line format is flattened to a single line with , as separator. |
{{disclaimer}} | Legal disclaimer text, entered by the user in the designer. |
{{imageUrl}} | Profile photo or logo URL, uploaded by the user. |
Icon fields
Ten fields have a corresponding icon URL variable that is automatically populated when the field has a value. The icon switches between a black and a white variant based on the active theme.
Use a double section guard. The outer guard hides the element when the field is empty, the inner guard ensures the icon URL is ready before rendering:
{{#email1}}{{#email1IconUrl}}
<a href="mailto:{{email1}}">
<img src="{{email1IconUrl}}" width="16" height="16" />
</a>
{{/email1IconUrl}}{{/email1}}
| Field | Icon URL variable | Description |
|---|---|---|
{{email1}} | {{email1IconUrl}} | Envelope icon |
{{telephone_business1}} | {{telephone_business1IconUrl}} | Phone (landline) icon |
{{cellular_telephone1}} | {{cellular_telephone1IconUrl}} | Phone (mobile) icon |
{{website}} | {{websiteIconUrl}} | Globe icon |
{{linkedin}} | {{linkedinIconUrl}} | |
{{x}} | {{xIconUrl}} | X (Twitter) |
{{facebook}} | {{facebookIconUrl}} | |
{{instagram}} | {{instagramIconUrl}} | |
{{youtube}} | {{youtubeIconUrl}} | YouTube |
{{chat}} | {{chatIconUrl}} | Internal chat |
Styling fields
| Variable | Description |
|---|---|
{{#theme}}background-color: {{background}};{{/theme}} | Theme background color |
{{#theme}}color: {{text}};{{/theme}} | Theme text color (white or black) |
{{#font}}font-family: {{font}};{{/font}} | User-selected font family as a CSS value |
{{#scale}}14{{/scale}} | Font size scaled by the user's size preference. Replace 14 with the desired base size in px. |
Example template
A minimal template demonstrating all variable patterns:
<table role="presentation" cellpadding="0" cellspacing="0" style="border-collapse: collapse; {{#font}}font-family: {{font}};{{/font}}">
<tr>
<td>
{{#display_name}}
<div style="font-weight: 600; font-size: {{#scale}}22{{/scale}};">{{display_name}}</div>
{{/display_name}}
{{#profession}}
<div style="display: inline-block; padding: 6px 10px; border-radius: 6px; margin-top: 8px; background-color: #000; color: #fff; {{#theme}}background-color: {{background}}; color: {{text}};{{/theme}}">
<span style="font-size: {{#scale}}12{{/scale}};">{{profession}}</span>
</div>
{{/profession}}
{{#email1}}{{#email1IconUrl}}
<table role="presentation" style="margin-top: 8px; border-collapse: collapse;">
<tr>
<td style="padding: 6px; border-radius: 50%; background-color: #000; {{#theme}}background-color: {{background}};{{/theme}}">
<img src="{{email1IconUrl}}" width="12" height="12" style="display: block;" />
</td>
<td style="padding-left: 8px; font-size: {{#scale}}14{{/scale}};">
<a href="mailto:{{email1}}" style="color: inherit; text-decoration: none;">{{email1}}</a>
</td>
</tr>
</table>
{{/email1IconUrl}}{{/email1}}
</td>
{{#imageUrl}}
<td style="padding-left: 16px;">
<img src="{{imageUrl}}" width="64" height="64" style="display: block; border-radius: 8px;" />
</td>
{{/imageUrl}}
</tr>
</table>
{{#disclaimer}}
<div style="border-top: 1px solid #E8E6E3; margin-top: 12px; padding-top: 8px; color: #707070; font-size: {{#scale}}11{{/scale}};">{{disclaimer}}</div>
{{/disclaimer}}
If this is saved as my-template.html in the ConfigMap, the matching designs.yaml entry to give it a black profession badge with white text and a square image slot is:
templates:
my-template:
previewTheme:
background: '#000000'
text: white
imageSlots:
- field: imageUrl
aspect: square