en:otml

This is an old revision of the document!


How to develop e-mail templates for promio.connect?

The following document provides technical information for the development of e-mail templates for promio.connect.

General information

  • Special characters must use XML conform entities:
    • "
    • &
    • '
    • <
    • >
    • for all other entities you have to use decimal syntax; e.g.: use   instead of  
  • UTF-8 4-byte characters are not supported at the moment. You can check the byte length with several tools, e.g. UTF-8 Tool
  • The length of lines in the source code must not exceed 700 characters.

If you use an IDE to develop the template, use the following namespaces for correct syntax highlighting:

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:pme="http://www.promio.net/pmeType"
      xmlns:pm="http://www.promio.net/pmType">
</html>

OTML

OTML is an extension of the HTML standard, specifically created for usage in promio.connect's e-mail editor. Because of this, an undestanding of HTML and CSS is mandatory.

OTML serves the cause to make designated parts of an e-mail editable. The global structure of the e-mail will not be affected. At first, the e-mail developer creates the e-mail as usual. After this is done, all intended parts can be made editable with the usage of OTML.

The OTML elements are separated into two namespaces: pm and pme:

  • pm elements are used for automatic generation or integration of content, such as the table of contents or data sources.
  • pme elements are user editable elements, e.g. singleline and multiline editors.

Repeater

A repeater is represented by the OTML tag <pme:repeater />.

A repeater element defines an area of repeating blocks and must contain one or more <pme:layout /> elements. Each layout can then be added to the e-mail by the user via a selection list.

The repeater element can hold one or more <pme:repeatercontent /> elements.

Attribute Type Required Description
title string No Title of the repeater. This is useful, if you use more than one repeater in your template.

Example

<pme:repeater>
 
	<pme:layout name="Layout 1">
	<table border="0" cellpadding="0" cellspacing="0" width="100%">
		<tr>
			<td>Layout 1</td>
		</tr>
	</table>
	</pme:layout>
 
	<pme:layout name="Layout 2">
	<table border="0" cellpadding="0" cellspacing="0" width="100%">
		<tr>
			<td>Layout 2</td>
		</tr>
	</table>
	</pme:layout>
 
	<pme:repeatercontent>
	<table border="0" cellpadding="0" cellspacing="0" width="100%">
		<tr>
			<td>Layout 1</td>
		</tr>
	</table>
	</pme:repeatercontent>
 
</pme:repeater>

Layout

A layout is represented by the OTML tag <pme:layout />.

A layout element contains a template, which can be added to the e-mail. It's a sub-element of the <pme:repeater> element and can be added multiple times.

Attribute Type Required Description
name string Yes Unique name for the layout

Example

<pme:repeater>
 
	<pme:layout name="Layout 1">
	<table border="0" cellpadding="0" cellspacing="0" width="100%">
		<tr>
			<td>Layout 1</td>
		</tr>
	</table>
	</pme:layout>
 
</pme:repeater>

Repeatercontent

A repeatercontent is represented by the OTML tag <pme:repeatercontent />.

The repeatercontent determines a pre-defined part of a <pme:repeater /> element and acts exactly like a <pme:layout /> element. It's a sub-element of the <pme:repeater> element and can be added multiple times. With the <pme:repeatercontent /> element its possible, to pre-fill a <pme:repeater />.

Example

<pme:repeater>
 
	<pme:layout name="Layout 1">
	<table border="0" cellpadding="0" cellspacing="0" width="100%">
		<tr>
			<td>Layout 1</td>
		</tr>
	</table>
	</pme:layout>
 
	<pme:repeatercontent>
	<table border="0" cellpadding="0" cellspacing="0" width="100%">
		<tr>
			<td>Layout 1</td>
		</tr>
	</table>
	</pme:repeatercontent>
 
</pme:repeater>

Preheader

A preheader is represented by the OTML tag <pme:preheader />.

A preheader is the preview text which is shown beneath the sender in most e-mail clients. During the build process of the e-mail, the content of the preheader element will be put directly after the <body> tag. All tracking pixels provided by promio.connect will be embedded after the preheader. This way, there is no HTML source code visible to the end-user.

<pme:preheader>This is the preheader text.</pme:preheader>

Singleline

A singleline element is represented by the OTML tag <pme:singleline />.

The singleline element offers a simple text input field and is mostly used for short texts like a headline.

Attribute Type Required Description
data-pmclass string No The value will be set as class on the link element, if a link is added to the singleline element.
label string No The title of the element, which is shown in the edit view.
linkable boolean No If linkable is false, its not possible to add or change a link around the singleline element.
pmtoctitle string No Title for entry inside the TOC.<br>Set a value to preallocate a title or leave it blank to make it possible, to set a TOC title if desired.
max-length integer No Maximum lenght of characters. The user will not be able to exceed this limit.

Example

<pme:singleline label="Headline" max-lenght="30">My Headline</pme:singleline>
 
<a class="link" href="https://www.promio.net" target="_blank">
	<pme:singleline data-pmclass="link" label="Link">Click me</pme:singleline>
</a>

Multiline and Multiline-Config

A multiline element is represented by the OTML tag <pme:multiline />.

The multiline element offers an advanced text and HTML editor based on CKEditor 4. It is mostly used for long texts or where HTML input is desired.

Attribute Type Required Description
label string No The title of the element, which is shown in the edit view.
linkable boolean No Make it possible to add a link around the editor content. If you enable this, we recommend that you use a special multiline-config for these editors in which the link button is removed from the toolbar.
pmtoctitle string No Title for entry inside the TOC.<br>Set a value to pre-allocate a title or leave it blank to make it possible, to set a TOC title if desired.
max-length integer No Maximum lenght of characters. The user is able exceed this limit, but a warning will be shown.
config string No Name of the multiline-config, that should be used for this editor.

Example

<pme:multiline label="Text">Lorem ipsum dolor sit amet</pme:multiline>

The multiline editor can be configured with a multiline-config element, which is represented by the OTML tag <pm:multiline-config>.

Attribute Type Required Description
name string Yes The name of the config element.
default boolean No Set to true, if this config should be used for all pme:multiline elements, where no config is specified by name.

The content of a multiline-config must be a CKEditor configuration in JSON format.

Example

<pm:multiline-config default>
{
  "forcePasteAsPlainText": true,
  "toolbar": [
	{
	  "name": "basicstyles",
	  "items": [
		"Bold",
		"Italic",
		"-",
		"Subscript",
		"Superscript",
		"-",
		"RemoveFormat"
	  ]
	},
	{
	  "name": "links",
	  "items": [
		"Link",
		"Unlink"
	  ]
	},
	{
	  "name": "insert",
	  "items": [
		"Table",
		"SpecialChar"
	  ]
	},
	{
	  "name": "clipboard",
	  "groups": [
		"clipboard",
		"undo"
	  ],
	  "items": [
		"Cut",
		"Copy",
		"Paste",
		"-",
		"Undo",
		"Redo"
	  ]
	},
	{
	  "name": "promio",
	  "items": [
		"promioPersFunc",
		"promioTemplates"
	  ]
	},
	{
	  "name": "document",
	  "items": [
		"Source"
	  ]
	},
	{
	  "name": "tools",
	  "items": [
		"Maximize"
	  ]
	}
  ]
}
</pm:multiline-config>
 
<pm:multiline-config name="linkable-editor">
{
  "forcePasteAsPlainText": true,
  "toolbar": [
	{
	  "name": "basicstyles",
	  "items": [
		"Bold",
		"Italic",
		"-",
		"Subscript",
		"Superscript",
		"-",
		"RemoveFormat"
	  ]
	},
	{
	  "name": "insert",
	  "items": [
		"Table",
		"SpecialChar"
	  ]
	},
	{
	  "name": "clipboard",
	  "groups": [
		"clipboard",
		"undo"
	  ],
	  "items": [
		"Cut",
		"Copy",
		"Paste",
		"-",
		"Undo",
		"Redo"
	  ]
	},
	{
	  "name": "promio",
	  "items": [
		"promioPersFunc",
		"promioTemplates"
	  ]
	},
	{
	  "name": "document",
	  "items": [
		"Source"
	  ]
	},
	{
	  "name": "tools",
	  "items": [
		"Maximize"
	  ]
	}
  ]
}
</pm:multiline-config>
 
/* This editor uses the default config */
<pme:multiline>Text</pme:multiline>
 
/* This editor uses the "linkable-editor" config */
<pme:multiline config="linkable-editor">Text</pme:multiline>

Image

Images have no special OTML element representation. Instead they use the standard HTML <img /> tag with extended attributes.

Attribute Type Required Description
pmedit boolean No If pmedit is true, the image is editable.
pmscale string No Possible values: crop / height / width
pmscaleheight integer No Use an alternate height instead of the one defined in the height attribute. This is useful for presentation on HiDPI / Retina displays.
pmscalewidth integer No Use an alternate width instead of the one defined in the width attribute. This is useful for presentation on HiDPI / Retina displays.
pmtoctitle string No Title for entry inside the TOC.<br>Set a value to preallocate a title or leave it blank to make it possible, to set a TOC title if desired.

Values for pmscale

Value Description
crop
height Resize the image to the defined height. The width is calculated proportional to the dimensions of the original image.
width Resize the image to the defined width. The height is calculated proportional to the dimensions of the original image.

Example

<img alt="Image" height="200" src="image.png" pmedit="true" pmscale="crop" width="200" />
 
<img alt="Image" height="50" src="image.png" pmedit="true" pmscale="height"  />
 
<img alt="Image" src="image@3x.png" pmedit="true" pmscale="width" pmscalewidth="600" width="200" />

Appointment

To provide a link to an appointment, you can use the <pme:appointment> element. Based on the inserted data, an iCal calendar file will be generated.

Attribute Description
text Text that is visible in the e-mail
summary Title of the appointment
organizerName Name of the appointments organizer
organizerEmail E-mail of the appointments organizer
dateTimeStart Start date and time of the appointment
dateTimeEnd End date and time of the appointment
location Location of the appointment
description Description of the appointment
<pme:appointment>
 
</pme:appointment>

TOC

A TOC (table of contents) is represented by the OTML tag <pm:toc />.

The TOC element is used to automatically generate a table of contents based on the values and the order of used pmtoctitle attributes.

The TOC elements requires exactly one <pm:tocitem /> element, which represents the the value of the processed pmtoctitle attribute. The complete content of the TOC element is repeatedly inserted for each pmtoctitle attribute with a value.

Example

Template
<ul>
	<pm:toc>
		<li><pm:tocitem /></li>
	</pm:toc>
</ul>
 
<pme:singleline pmtoctitle="Headline 1">Content</pme:singleline>
<pme:singleline pmtoctitle="Headline 2">Content</pme:singleline>
Rendered code
<ul>
	<li>
		<a href="#link_to_anchor_1">Headline 1</a>
	</li>
	<li>
		<a href="#link_to_anchor_2">Headline 2</a>
	</li>
</ul>

External data sources

External data sources make it possible to embed content from RSS feeds into an e-mail.

The setup of external data sources is individually realized by promio.net GmbH. If you are interested in the usage, please contact our support team via ticket.

Source

The source element is represented by the OTML tag <pm:source />.

It serves as wrapper for the different source items and may contain one or more <pm:sourceitem /> elements.

Attribute Required Type Description
pmedit No boolean If true, users are allowed to change datasources.

Source item

A source item is represented by the OTML tag <pm:sourceitem />.

It serves as the connection between the e-mail and the setup data source.

Attribute Required Type Description
name Yes string Unique name of the data source.
refreshmode Yes string Possible values: build / refresh
Values for refreshmode
Value Description
build Refresh data source on build of the e-mail.
refresh Refresh data source before sending the campaign.

Data section

A data section is represented by the OTML tag <pm:datasection />.

Data sections are used to fill the template with content from the data source with the help of data items. Each data section must contain at least one <pm:data /> element.

Attribute Required Type Description
source Yes string The name of the datasource.
items No json A json object. Use one entry per data item inside the current data section, to define, how the next data item will be chosen.<br>If no option is chosen, it defaults to “next”.

With the items attribute, it is possible to define the selection of content for each data item.

Value Description
(itemId) Choose a data item on the base of its unique id.
next Choose the next data item in the list. This is the most used option.
rand Choose a random data item.
Example

If you want to set the content of the first data item to the unique id 12345 and random data for the second one, use this string:

{ 1: 12345, 2: "rand" }

Data item

A data item is represented by the OTML tag <pm:data />.

Data items are placed inside a data section. Each one represents one record from the data source.

Inside a data item, it's possible to use the placeholder [pm:item:field_name] to get access to a field of the data source record. With the cut function, it is also possible, to shorten the content of a placeholder to a specified amount of characters.

E.g.: [cut([pm:item:title], 20)] shortens the title to a maximum of 20 characters.

It's only possible to access each data item one time. If you want to access the same item multiple times, it is necessary to use multiple data sources with the same content. In this case, please contact our support team via ticket.

Example

Sample data source "Top 10 Products"
id title price image link
123 Smartphone 350.00 € smartphone.jpg www.sample.com/shop?productid=123
124 Watch 150.00 € watch.jpg www.sample.com/shop?productid=124
125 Powerbank 50.00 € powerbank.jpg www.sample.com/shop?productid=125
Template code
<html>
<head>
	<pm:source pmedit="true">
		<pm:sourceitem refreshmode="build" name="Top 10 Products"></pm:sourceitem>
	</pm:source>
</head>
<body>
	<pm:datasection source="Top 10 Products" items='{ "1": "124", "2": "next", "3": "next" }'>
 
		<pm:data>
			<table>
				<tr>
					<td>
						<a href="[pm:item:link]" target="_blank">[pm:item:title]</a>
					</td>
				</tr>
				<tr>
					<img alt="[pm:item:title]" src="[pm:item:image]" width="200">
				</tr>
				<tr>
					<td>Price: [pm:item:price]</td>
				</tr>
			</table>
		</pm:data>
 
		<pm:data>
			<table>
				<tr>
					<td>
						<a href="[pm:item:link]" target="_blank">[pm:item:title]</a>
					</td>
				</tr>
				<tr>
					<img alt="[pm:item:title]" src="[pm:item:image]" width="200">
				</tr>
				<tr>
					<td>Price: [pm:item:price]</td>
				</tr>
			</table>
		</pm:data>
 
 
		<pm:data>
			<table>
				<tr>
					<td>
						<a href="[pm:item:link]" target="_blank">[pm:item:title]</a>
					</td>
				</tr>
				<tr>
					<img alt="[pm:item:title]" src="[pm:item:image]" width="200">
				</tr>
				<tr>
					<td>Price: [pm:item:price]</td>
				</tr>
			</table>
		</pm:data>
 
	</pm:datasection>
</body>
</html>
Rendered e-mail code
<html>
<body>
	<table>
		<tr>
			<td>
				<a href="www.sample.com/shop?productid=124" target="_blank">Watch</a>
			</td>
		</tr>
		<tr>
			<img alt="Watch" src="watch.jpg" width="200">
		</tr>
		<tr>
			<td>Price: 150.00 €</td>
		</tr>
	</table>
 
 
	<table>
		<tr>
			<td>
				<a href="www.sample.com/shop?productid=125" target="_blank">Powerbank</a>
			</td>
		</tr>
		<tr>
			<img alt="Powerbank" src="powerbank.jpg" width="200">
		</tr>
		<tr>
			<td>Price: 50.00 €</td>
		</tr>
	</table>
 
	<table>
		<tr>
			<td>
				<a href="www.sample.com/shop?productid=123" target="_blank">Smartphone</a>
			</td>
		</tr>
		<tr>
			<img alt="Smartphone" src="smartphone.jpg" width="200">
		</tr>
		<tr>
			<td>Price: 350.00 €</td>
		</tr>
	</table>
 
</body>
</html>

If-conditions within data items

It is possible to use If-conditions within data items.

<pm:datasection source="Datasource 1" items='{ 1: "rand" }'>
 
	<pm:data>
		<table>
			<tr>
				<td>
					<a href="[pm:item:link]" target="_blank">[pm:item:title]</a>
				</td>
			</tr>
			<tr>
				<img alt="Product" src="[pm:item:image]" width="200">
			</tr>
			<tr>
				<td>
					 <pm:dynamic>
						<pm:if>
							<pm:condition>
								[pm:item:priceReduced] == ""
							</pm:condition>
							Price: [pm:item:price]
						</pm:if>
						<pm:else>
							Price: [pm:item:priceReduced]<br />
							instead of <span style="color: #f00; text-decoration: line-through;"[pm:item:price]</span>
						</pm:else>
					</pm:dynamic>
				</td>
			</tr>
		</table>
	</pm:data>
 
</pm:datasection>

External content

pm:include-url-content is a very special tag. Use it to include the source code of a website into your e-mail.

It is also possible to use this tag in the subject of an e-mail.

Attribute Type Required Description
url string Yes The URL of the content you want to include.
title boolean No If true, the content of the URL's title tag is returned.

Example

As content of an e-mail:

<pm:include-url-content url="https://www.promio.net/my-template.html">
	This default text is only visible if the url does not return any content.
</pm:include-url-content>

As subject:

<pm:include-url-content url="https://www.promio.net/my-template.html" title="true">
	This default title is only visible if the url does not return any content.
</pm:include-url-content>

CSS

Automatic transformation from CSS to inline CSS

CSS from <style /> blocks can only be transformed to inline CSS for isolated selectors. Also, the CSS inlining only works on HTML elements with one selector.

Example

<head>
<style>
	/*******************
	* Working examples * 
	*******************/
 
	.foo {
		font-size: 12px;
		line-height: 1.4;
	}
 
	.bar {
		background-color: #fff;
	}
 
	img {
		border: 0;
	}
 
 
	/***********************
	* Non-working examples * 
	************************/
 
	.baz, .boz {
		font-size: 15px;
	}
 
	table td {
		background-color: #ff0
	}
</style>
</head>
<body>
	/*******************
	* Working examples * 
	*******************/
	<table>
		<tr>
			<td class="bar">
				<span class="foo">Lorem ipsum dolor sit amet</span>
			</td>
		</tr>
		<tr>
			<img alt="" src="image.jpg" width="200" />
		</tr>
	</table>
 
 
	/***********************
	* Non-working examples * 
	************************/
	<table>
		<tr>
			<td class="foo bar">
				Lorem ipsum dolor sit amet
			</td>
		</tr>
	</table>
</body>

User editable CSS

To give users the freedom to edit the CSS, there are some prerequisites:

* The style tag must use the id pn-js-css-editor. Only one style tag with this id is allowed. * Each selector must use a comment block with the descriptors @nav, @navItem and @info.

  • @nav represents the category inside the CSS editor and groups the different @navItem elements.
  • @navItem represents the element inside the category. **This name must be unique for all CSS selectors within the same @nav category.
  • @info serves as decription for the @navItemelement.
<style id="pn-js-css-editor" media="all" type="text/css">
	/*
	@nav Article
	@navItem Text
	@info Change the font settings of article texts.
	*/
	.article-text {
		/*@edit*/color: #000;
		/*@edit*/font-family: Arial, Helvetica, sans-serif;
		/*@edit*/font-weight: 300;
		/*@edit*/font-size: 13px;
		/*@edit*/line-height: 1.4;
		/*@edit*/text-align: left;
		/*@edit*/text-decoration: none;
		/*@edit*/text-transform: none;
	}
 
	/*
	@nav Article
	@navItem Link
	@info Change the font settings of links inside article texts.
	*/
	.article-link {
		/*@edit*/color: #000;
		/*@edit*/font-weight: 300;
		/*@edit*/text-decoration: none;
	}
</style>

Dynamic content

Placeholders

With the help of placeholders, it's possible to access the fields of your user data or include dynamic content.

You can access each user data field, if you place a $ character in front of the field name. E.g.: access the field name with $name.

A list of all universal available placeholders is available with click on the placeholder button inside the toolbar of a multiline editor.

If custom placeholders are requried, please contact our support team via ticket.

Example

$salutation_en_formal will be replaced with “Dear Mr Doe,” if the recipient is male or “Dear Ms Doe,” if the recipient is female. If no gender is given, it will fall back to “Dear Sir or Madam,”

Conditions

It is also possible to personalize content with conditions.

Example

Personalized salutation with fallback
{!--<dynamicContent>
	<if>
		<condition>gender = 1 AND name != ""</condition>
		<data>Dear Mr $name,</data>
	</if>
	<elseif>
		<condition>gender = 2 AND name != ""</condition>
		<data>Dear Ms $name,</data>
	</elseif>
	<else>
		<data>Dear Sir or Madam,</data>
	</else>
</dynamicContent>//--}

Functions

pn_substr

With the function pn_substr is possible to shorten the value of placholders to a specified amount of characters.

E.g.: pn_substr(name, 10) shortens the name to 10 characters.

Config Tags

Config tags make it possible to control the behaviour of the e-mail editor.

Attribute Type Default Description
cssinline boolean true Inline CSS from the \<style\> block.
cssinlinetype string legacy Set the type of the CSS inliner.
storage string (frame / shadow) frame Possible values: frame / shadow
ignoreerror boolean false Ignore errors on save.

Example

<pm:config>
    <pm:config-value name="cssinline" value="true"/>
    <pm:config-value name="cssinlinetype" value="ng"/>
    <pm:config-value name="storage" value="frame"/>
    <pm:config-value name="ignoreerror" value="true"/>
</pm:config>

Values for cssinlinetype

Value Description
legacy Use the legacy CSS inliner.
ng Use the new CSS inliner.

Values for storage

Value Description
frame Save the contents from the preview iframe. This will save changes made via the browsers development tools but is also susceptible to foreign code e.g. made by browser plugins, which could destroy the presentability of the e-mail.
shadow Save the contents from a shadow copy of the e-mail. This assures that the e-mails source code could not be changed by browser plugins.
en/otml.1679061171.txt.gz · Last modified: 2023/03/17 14:52 by promio