In this page

What is a notification email template?

It is critical to send the exact, personalized information your recipients need, exactly at the right moment. Well-written notification email templates, with a custom subject and body, are crucial for that. Notification email templates don't work standalone. They work as part of a notification scheme.

Create, edit, and delete notification email templates

Configure notification email templates by navigating to Confluence Settings (cog icon "⚙" in the top right) → AppsBetter Content ArchivingConfigurationNotification configurationNotification email templates tab.

The notification email template list has the following columns:

  • Template name: The name and description of the notification email template.
  • Used in schemes: The number of notification schemes which use this template. Click it to show the list of those schemes on the Notification schemes tab.
  • Actions: Clone creates a copy of the template. Delete deletes the template, if it's not used in any notification scheme.

Edit a notification email template

Create a new notification email template by clicking the Add new template button on the right above the notification email template list. Click the name of a notification email template to edit it.

In the editor dialog, you can configure the following:

Name: Enter a name for the notification email template. Keep it concise and intuitive for users. It does not appear in the emails sent. It only identifies the template when editing notification schemes.

Description: Optionally, enter a description for the template. Similarly, it does not appear in the emails sent. It just explains the purpose of the template.

Subject: Enter the subject line of the notification email. It supports Handlebars expressions as template language.

Content: Enter the content of the notification email. It supports HTML markup for formatting and Handlebars expressions as template language.

Factory default notification email templates

There are factory default notification email templates for the most common use cases. To reset the factory defaults, you have to reset the notification schemes. Notification schemes and notification email templates are reset together.

Customize email subject and content

You can customize the factory default notification email templates to fit your needs, or clone them as a starting point for building your own templates.

Skip this part of the documentation if you just want to add some custom instructions to the email content, or remove or rephrase some text. You can do that without understanding the Handlebars syntax and the data types involved. Read on if you want to make significant changes to the logic, numbers, and lists.

Work with Handlebars

Handlebars is a lightweight templating language, based on Mustache, used to define the subject and content of a notification email. See the official Handlebars documentation for the full syntax reference.

You can use Handlebars expressions, written between double curly braces {{}}, to control the flow of generating a notification email's subject line and content. For example, you can iterate over lists, apply if-else conditions, and perform simple calculations.

Data types

You can use the following expressions in a template:

Expression Description
baseUrl The base URL of your Confluence site. Useful when creating links in the email.

Example (from the default notification email templates):
<html>
	<head>
		<!-- ... -->
		<base href="{{baseUrl}}"/>
	<!-- ... -->
	</head>
	<!-- ... -->
</html>
totalContentCount The overall count of all contents processed when creating the notification. For performance reasons, this number may be greater than the number of contents that you can actually list in the notification.

Example for a typical notification email subject (note the singular vs. plural form of the word "content"):
{{totalContentCount}} content{{#if(gt totalContentCount 1)}}s{{/if}} expired
contents The contents in your Confluence site that you can actually iterate over when generating a notification. Their backing Java data type is LimitedMap<NotificationSpace, LimitedList<NotificationContent>>. See below for more details on these types.

The following example iterates over the keys of the contents collection (whose keys are actually the spaces for which contents have been collected for the notification) in the outer each loop, and uses the key's key and name values in headings. It does so by referencing @key.key and @key.name. (The expression @key.key can be a little confusing. The first part (@key) references the map's key which is a space object, and the second part (.key) references the space's key field. These two fields are both named "key" accidentally, but they have completely different meanings.) It also prints some text with basic information.

Then, it iterates over the contents listed for each space in a nested loop. It accesses contents using this, which references the current element in the outer loop. Given that the current element in the outer loop is a list in this case, it can be iterated over in a nested loop.

Inside the nested loop, we can access the current content element's data. For example, @type.apiValue can be used to determine the content type (page or blogpost). Based on the type, a link is constructed that points to the content. When generating the link's label, {{title}} is used as a convenient way to access the content's title.

{{#each contents}}
	<h3><a href="wiki/spaces/{{@key.key}}">{{@key.name}}</a></h3>
	{{this.size}} content{{#if(gt this.size 1)}}s{{/if}} not viewed in {{abbreviate @key.key 23}}.
	{{#each this}}
		<div class="content-item">
			{{#if (eq @type.apiValue "page")}}
				<a href="wiki/spaces/{{../@key.key}}/pages/{{id}}">{{title}}</a>
			{{/if}}
			{{#if (eq @type.apiValue "blogpost")}}
				<a href="wiki/spaces/{{../@key.key}}/blog/{{id}}">{{title}}</a>
			{{/if}}
		</div>
	{{/each}}
{{/each}}

For performance and usability reasons, the email notification templates cannot access "large" amounts of data (10000 spaces, for example). Instead, they will receive size-limited views (a maximum of 20 spaces are detailed, with a maximum of 50 contents listed for each) of the data as instances of the following collection types:

Limited collection types
Type name Description
LimitedList A size limited decorator for the Java List type.

Think about it as a list that maximizes the number of items it actually holds, but also knows the total number of items it would contain if it were non-limited. Example: when the list receives 135 items, 100 as max size, then it will return 100 items and 35 as the remaining count.

It extends the java.util.List interface with:
  • list.size: the number of items actually contained in the list
  • list.totalSize: the number of items that would be contained in the list if it was not limited
  • list.remainingCount: the number of items beyond those that are contained in the list
LimitedMap A size limited decorator for the Java Map type.

It has the semantics with map entries, as LimitedList has with the list items.

It extends the java.util.Map interface with:
  • map.size: the number of items actually contained in the map
  • map.remainingCount: the number of entries beyond those that are contained in the map
DTO types

The items in the above collections are lightweight DTO objects of the following types:

Type name Description
NotificationSpace A lightweight replacement for a Confluence Space.

Available fields:
  • id: the numerical ID of the space
  • key: the space key
  • name: the name of the space
  • type: the type of the space (global or personal); use type.apiValue field to access the actual value
NotificationContent A lightweight replacement for a Confluence content (page or blog post).

Available fields:
  • id: the numerical ID of the content
  • title: the title of the content
  • type: the type of the content ("page" or "blogpost"), use type.apiValue field to access the actual value
  • status: the current content status
    • id: the numerical ID of the content status
    • name: the human-readable name of the content status
    • color: the hex color code of the content status (e.g. "#FF991F")
    • icon: the icon identifier of the content status (e.g. "warning")
    • description: the description of the content status
  • previousStatus: the previous content status (the one before the last change)
    • It has the same fields as status.
Helpers

Handlebars is a "logic-less" templating language, but it supports the definition of so-called helpers. Helpers are expressions that can be used in a template to implement simple logic like comparing two values or evaluating a true/false condition, backed by custom built-in functionality in the service that parses the template.

Handlebars offers block helpers and built-in helpers out of the box. Complementing these, the Better Content Archiving app introduces the following helpers that you can also use in your templates.

Helper Description
abbreviate Abbreviates a string to a given length (at least 4). Appends '...' to the end of the string. This suffix counts against the overall length the string is abbreviated to. Uses StringUtils.abbreviate() under the hood.
{{abbreviate "long string" 6}}
and Logical AND operator. Takes a list of expressions. Evaluates to true if all expressions are true, or false otherwise.
{{#if (and (gt contents.size 0) (gt totalContentCount 10))}}
	There is at least one space listed, and there are at least 11 contents overall
{{/if}}
eq Logical EQUALS operator. Takes two expressions. Evaluates to true if they are equal, false otherwise.
{{#if (eq contents.size 1)}}
	There is exactly one space listed
{{/if}}
gt Logical GREATER THAN operator. Takes two values. Evaluates to true if the first is greater than the second, false otherwise.
{{#if (gt contents.size 1)}}
	There are at least two spaces listed
{{/if}}
gte Logical GREATER THAN OR EQUALS operator. Takes two values. Evaluates to true if the first is greater than or equal to the second, false otherwise.
{{#if (gte contents.size 2)}}
	There are at least two spaces listed
{{/if}}
lt Logical LESS THAN operator. Takes two values. Evaluates to true if the first is less than the second, false otherwise.
{{#if (lt contents.size 10)}}
	There are less than 10 spaces listed
{{/if}}
lte Logical LESS THAN OR EQUALS operator. Takes two values. Evaluates to true if the first is less than or equal to the second, false otherwise.
{{#if (lte contents.size 10)}}
	There are no more than 10 spaces listed
{{/if}}
ne Logical NOT EQUALS operator. Takes two expressions. Evaluates to true if they are not equal, false otherwise.
{{#if (ne contents.size 0)}}
	There is at least one space listed
{{/if}}
not Logical NOT operator. Takes a boolean expressions. Evaluates to the opposite of the expression, i.e. to true if the original value was false, and to false if the original value was true.
{{#if (not (eq contents.size 0))}}
	There is at least one space listed
{{/if}}
or Logical OR operator. Takes a list of expressions. Evaluates to true if any of the expressions is true, or false otherwise.
{{#if (or (gte contents.size 2) (gt totalContentCount 10))}}
	There are at least two space listed, or there are at least 11 contents overall
{{/if}}

Combine and nest the above helpers to create complex conditions:

and (gt contents.size 0) (gt totalContentCount 10)
Error handling

If your email template contains Handlebars syntax errors, the notifications won't be sent, and an error will be logged for the job execution trying to send that notification. You can see the error by clicking the Logs link shown on the Jobs screen after the execution completed, or in the Job audit log.

Recipes

This section contains easy-to-follow guides to solve frequent use cases.

Display the current status for each content

If you are sending a notification email that includes multiple different statuses, such as "Expired", "Expiration date passed", and "To review", it is useful to display the current status next to each content:

Steps:

  1. To define the appearance of the "status lozenge", add the following fragment to the <style> section:
    <style>
    	<!-- ... styles omitted -->
    
    	<!-- add this fragment -->
    	.content-status {
    		margin: 0 0.5em;
    		padding: 0 0.5em;
    		font-weight: 500;
    		font-size: smaller;
    		border: 1px solid;
    		border-radius: 5px;
    		height: 100%;
    	}
    </style>
    
    (You can freely customize the style!)
  2. To display the status, add the following line to the end of the section which displays a single content:
    <div class="content-item">
    	<!-- ... code omitted -->
    
    	<!-- add this line -->
    	<span class="content-status" style="color:{{status.color}}">{{status.name}}</span>
    </div>
    
  3. You're done!
Display the last content status transition for each content

If you are sending a notification email which focuses on transitions (content status changes), it is useful to display both the previous status and the current one:

Steps:

  1. Add the style the same way as in step 1 of the previous recipe.
  2. To display the previous status, an arrow character and the current status, add the following fragment to the end of the section which displays a single content:
    <div class="content-item">
    	<!-- ... code omitted -->
    
    	<!-- add this fragment -->
    	{{#if previousStatus}}
    		<span class="content-status" style="color:{{previousStatus.color}}">{{previousStatus.name}}</span>
    		<span>&rarr;</span>
    	{{/if}}
    	<span class="content-status" style="color:{{status.color}}">{{status.name}}</span>
    </div>
    
  3. You're done!

Questions?

Ask us any time.