Last updated Apr 19, 2024

JIRA email template changes

In JIRA 6.1-OD3, the email templates for JIRA have changed to sport a new ADG-compliant look and feel.

The new look

The parts of JIRA's emails that have changed most significantly are:

  • The font size has increased to match the ADG specification of 14 pixels.
  • The site banner at the top of the email has been removed in favour of a JIRA watermark in the bottom-right.
  • The user who triggered the email notification is now placed outside of the white "chrome" of the email.
  • For any notifications that include comments, the comment appears above the issue's name and project.
  • Actions relevant to each email notification are now listed as the last thing inside the email's chrome. They are always a combination of an icon + text, separated by a middot.

The full guidelines for ADG-compliant emails are forthcoming and will be published to developer.atlassian.com/design in the coming months.

New resources

The JIRA email templates are now run through a utility called Botocss. Botocss applies CSS rules as inline styles to a given HTML input.

This has enabled the separation of the CSS styling of emails from the templates, significantly simplifying the task of achieving a consistent look and feel for emails.

If you're tired of handcrafting and double-checking every inline style, this should be a breath of fresh air for you.

Applying the JIRA email CSS to its email templates is achieved through the BotocssMailUtility#applyStyles method.

Use of Botocss is opt-in - you may either use BotocssMailUtility to apply JIRA's email CSS, invoke Botocss#inject manually, or continue to code your email styles inline in your templates.

For reference, the JIRA email CSS is stored in the following files and applied in the following order:

  • jira-components/jira-core/src/main/resources/templates/email/css/aui-styles.css
  • jira-components/jira-core/src/main/resources/templates/email/css/all-clients.css
  • jira-components/jira-core/src/main/resources/templates/email/css/wiki-renderer.css
  • jira-components/jira-core/src/main/resources/templates/email/css/jira-styles.css

Email template changes

The email templates are still velocity templates, and are located in the same folder they were placed in for JIRA 4.4.

However, the structure of each email template has changed, along with the semantics of some of the helper templates such as header.vm and footer.vm.

Sample differences

Here is a comparison of some of the old and new templates:

issuegenericevent.vm

OLD

1
2
e#disable_html_escaping()
#parse("templates/email/html/includes/emailconstants.vm")
#parse("templates/email/html/includes/header.vm")
<tr valign="top">
    <td id="email-banner" style="padding:32px 32px 0 32px;">
        #if ($changelogauthor)
            #set ($changelogauthorLink = "#authorlinkkey($changelogauthor.key $linkstyle)")
        #else
            #set ($changelogauthorLink = "#authorlinkname($remoteUser.name $linkstyle)")
        #end
        #set ($issueType = $issue.getIssueTypeObject())
        #set ($issueLink = "#renderIcon(${issueType.iconUrlHtml} ${issueType.getNameTranslation($i18n)}) <a style='color:${textLinkColour};text-decoration:none;' href='${baseurl}/browse/${issue.getKey()}'>$issue.getKey()</a>")
        #emailbanner($changelogauthor "email.event.activity.updated" $changelogauthorLink $issueLink "")
        
    </td>
</tr>
#if ($changelog || $comment)
<tr valign="top">
    <td id="email-fields" style="padding:0 32px 32px 32px;">
        <table border="0" cellpadding="0" cellspacing="0" style="padding:0;text-align:left;width:100%;" width="100%">
            <tr valign="top">
                <td id="email-gutter" style="width:64px;white-space:nowrap;"></td>
                <td>
                    <table border="0" cellpadding="0" cellspacing="0" width="100%">
                        #parse("templates/email/html/includes/fields/comment.vm")
                        #parse("templates/email/html/includes/fields/changelog.vm")
                    </table>
                </td>
            </tr>
        </table>
    </td>
</tr>
#end
#parse("templates/email/html/includes/footer.vm")

NEW

1
2
#disable_html_escaping()
#defaultMailHeader('jira.email.title.activity.updated', $changelogauthor)
#if ($comment)
    #parse('templates/email/html/includes/patterns/comment-top.vm')
#end
#rowWrapperNormal("#parse('templates/email/html/includes/patterns/issue-title.vm')")
#if ($changelog && $changelogItemIssueDescription)
    #rowWrapperNormal("#parse('templates/email/html/includes/fields/changelog.vm')" '' 'wrapper-special-margin')
#elseif ($changelog)
    #rowWrapperNormal("#parse('templates/email/html/includes/fields/changelog.vm')")
#end
#parse('templates/email/html/includes/changelog-issue-description.vm')
#set ($commentActionBody="#parse('templates/email/html/includes/patterns/comment-action.vm')")
#rowWrapperNormal($commentActionBody)
#parse('templates/email/html/includes/footer.vm')

issuecommentedited.vm

OLD

1
2
#disable_html_escaping()
#parse("templates/email/html/includes/emailconstants.vm")
#parse("templates/email/html/includes/header.vm")
<tr valign="top">
    <td id="email-banner" style="padding:32px 32px 0 32px;">
        #if ($changelogauthor)
            #set ($changelogauthorLink = "#authorlinkkey($changelogauthor.key $linkstyle)")
        #else
            #set ($changelogauthorLink = "#authorlinkname($remoteUser.name $linkstyle)")
        #end
        #set ($issueType = $issue.getIssueTypeObject())
        #set ($issueLink = "#renderIcon(${issueType.iconUrlHtml} ${issueType.getNameTranslation($i18n)}) <a style='color:${textLinkColour};text-decoration:none;' href='${baseurl}/browse/${issue.getKey()}'>$issue.getKey()</a>")
        #emailbanner($changelogauthor "email.event.activity.comment.edited" $changelogauthorLink $issueLink "")
        
    </td>
</tr>
#if ($comment)
<tr valign="top">
    <td id="email-fields" style="padding:0 32px 32px 32px;">
        <table border="0" cellpadding="0" cellspacing="0" style="padding:0;text-align:left;width:100%;" width="100%">
            <tr valign="top">
                <td id="email-gutter" style="width:64px;white-space:nowrap;"></td>
                <td>
                    <table border="0" cellpadding="0" cellspacing="0" width="100%">
                        #parse('templates/email/html/includes/fields/comment.vm')
                    </table>
                </td>
            </tr>
        </table>
    </td>
</tr>
#end
#parse("templates/email/html/includes/footer.vm")

NEW

1
2
#disable_html_escaping()
#defaultMailHeader('email.event.activity.comment.edited.on.issue', $changelogauthorLink)
#set ($commentTopPatternClasses = 'comment-top-special-margin')
#set ($htmlComment = $!diffutils.diff($originalcomment.body, "background-color:${auiErrorBackgroundColour};text-decoration:line-through;", $comment.body, "background-color:${auiSuccessBackgroundColour};"))
#parse('templates/email/html/includes/patterns/comment-top.vm')
#set ($issueTitleBody="#parse('templates/email/html/includes/patterns/issue-title.vm')")
#rowWrapperNormal($issueTitleBody)
#set ($commentActionBody="#parse('templates/email/html/includes/patterns/comment-action.vm')")
#rowWrapperNormal($commentActionBody)
#parse('templates/email/html/includes/footer.vm')

issuementioned.vm

OLD

1
2
#disable_html_escaping()
#parse("templates/email/html/includes/header.vm")
<tr valign="top">
    <td id="email-banner" style="padding:32px 32px 0 32px;">
        #set ($authorLink = "#authorlinkname($remoteUser.name $linkstyle)")
        #set ($issueType = $issue.getIssueTypeObject())
        #set ($issueLink = "#renderIcon(${issueType.iconUrlHtml} ${issueType.getNameTranslation($i18n)}) <a style='color:${textLinkColour};text-decoration:none;' href='${baseurl}/browse/${issue.getKey()}'>$issue.getKey()</a>")
        #emailbanner($remoteUser "jira.mentions.email.header" $authorLink $issueLink '')
    </td>
</tr>
#if ($comment)
<tr valign="top">
    <td id="email-fields" style="padding:0 32px 32px 32px;">
        <table border="0" cellpadding="0" cellspacing="0" style="padding:0;text-align:left;width:100%;" width="100%">
            <tr valign="top">
                <td id="email-gutter" style="width:64px;white-space:nowrap;"></td>
                <td>
                    <table border="0" cellpadding="0" cellspacing="0" width="100%">
                        #parse("templates/email/html/includes/fields/comment.vm")
                        #parse("templates/email/html/includes/mention-actions.vm")
                    </table>
                </td>
            </tr>
        </table>
    </td>
</tr>
#end
#parse("templates/email/html/includes/footer.vm")

NEW

1
2
#disable_html_escaping()
#set($extraFooterContent = "${i18n.getText('jira.mentions.email.hint')}: ${i18n.getText('jira.mentions.email.hint.message')}")
#genericChangelogMailWithComment('jira.email.title.mention')

Rendering the email header (aka header.vm, emailconstants.vm)

With the move of the notification actor's details outside of the email chrome, header.vm has taken on a drastically different meaning than it had in JIRA 5. 

You should never need to invoke header.vm yourself.

In the simplest case - rendering the actor details and the email's title - you only need to call:

1
2
#defaultMailHeader('my.email.i18n.key.title', $notificationActorUserObject)

If you need to pass additional data to your header, use the following:

1
2
#defaultMailHeaderWithParam('my.email.i18n.key.with.a.variable.title', $notificationActorUserObject, $variableValueInHtml)

It should be very rare to need to invoke header.vm yourself. If you do decide to, ensure you #set the following variables before calling #parse for header.vm:

  • You have called #parse('templates/email/html/includes/emailconstants.vm')
  • $actionerUser = the user who triggered the email notification
  • $authorLink = a rendered HTML link to the user that includes their avatar (typically, the output of the #authorlinkname macro)
  • $headerTitle = the rendered HTML for the email's title. Typically this will be the result of the $i18n.getText() call for your email's title.

Rendering content rows within email

There are several ways you can render content in the body of your email.

Rendering textual content

There is a new macro -  #textParagraph - that outputs HTML passed to it in a paragraph within the email's body.

For example, this:

1
2
#textParagraph("$i18n.getText('my.important.message','<strong>','</strong>')")

Renders the following HTML content (before Botocss is invoked):

1
2
<table class='text-paragraph-pattern' cellspacing='0' cellpadding='0' border='0' width='100%'>
    <tr>
        <td class='text-paragraph-pattern-container mobile-resize-text'>
            This message is <strong>super</strong> important.
        </td>
    </tr>
</table>

You can also invoke the text-paragraph.vm template manually:

1
2
#set ($textParagraph = "$i18n.getText('my.important.message','<strong>','</strong>')")
#parse('templates/email/html/includes/patterns/text-paragraph.vm')

Render HTML by passing values

The first approach is to pass some rendered HTML to the #rowWrapperNormal macro:

1
2
#set ($issueTitleBody="#parse('templates/email/html/includes/patterns/issue-title.vm')")
#rowWrapperNormal($issueTitleBody)
#rowWrapperNormal("#parse('templates/email/html/includes/patterns/comment-action.vm')")

Note the use of double quotes around the calls to #parse, which ensure the nested template is evaluated at that point and stored as a String value.

Rendering inline

The second approach is to use the two macros -  #rowWrapperNormalBegin and #rowWrapperNormalEnd - within your template, which will output the appropriate markup to render the structure around your content:

1
2
#rowWrapperNormalBegin()
#textParagraph($i18n.getText('template.user.forgotusername.requestedusernames'))
#rowWrapperNormalEnd()

Rendering options

All three 'rowWrapperNormal' macros accept two additional optional parameters: an ID to attach to the row in the email, and any additional classes to add to the element. Both are useful to hook CSS styles to the email elements.

1
2
#rowWrapperNormalBegin('more-info-section' 'wrapper-special-margin my-custom-css-class')
<p>Hi thar!</p>
#rowWrapperNormalEnd()

#set($textParagraph = 'Lorum ipsum sit dolor amet')
#rowWrapperNormal("#parse('templates/email/html/includes/patterns/text-paragraph.vm')", '', 'issue-description-container')

This is unchanged from JIRA 4 or 5. Simply place #parse('templates/email/html/includes/footer.vm') at the end of your email template file.

Rate this page: