Send a Custom Email
Use this post function to send an email based on a custom condition. For example, you can use this post function to send an email to certain recipients when an issue with Critical or High priority is created. Further examples include using this post function to send an email that is requesting approval for a sub-task, for instance, or letting the QA team know an issue is ready for test.
If you would rather send a notification than an email, you could use our Fires an Event when Condition is True post function.
This post function has multiple elements to it, each of these are summarised here and, where necessary, detailed more below:
- Condition and configuration: You can set a condition to control when this post function fires. You can also pass additional variables to the body and subject template using the
configmap, and dynamically control recipients using themailvariable. - Email template: You can write an email template using plain text or the GStringTemplateEngine.
- Subject template: You can write the subject template using plain text or the GStringTemplateEngine.
- Email format: You can choose whether to send the email as plain text or HTML.
- To addresses/To issue fields: You can choose who to send the email to. When adding To issue fields, acceptable issue fields include user fields (for example assignee, reporter, watchers) and string fields containing valid email addresses. Recipients must be active users to receive emails. To bypass this restriction, add email addresses directly to the
mailobject's recipient list. - CC addresses/CC issue fields: You can choose who should be CC'd on the email. When adding CC issue fields, a cceptable issue fields include user fields (for example assignee, reporter, watchers) and string fields containing valid email addresses. Recipients must be active users to receive emails. To bypass this restriction, add email addresses directly to the
mailobject's recipient list. - Include attachments: You can choose whether to include attachments in the email.
- Custom attachment callback: You can enter a function which will be called with each
Attachmentobject. This option is only relevant if you select the Custom option when choosing to include attachments. - Reply-to email address: You can set the email address for replies.
- Preview Issue key: You can enter an issue key to preview what the mail will look like.
- Disable validation: You can choose to disable the validation of the configuration when you are set from/to/cc dynamically.
You can find step-by-step instructions on how to use this post function below.
Condition and configuration
In the Condition and configuration code editor you can enter a condition to ensure certain conditions are met before the email is sent. You can also use this code editor to pass additional variables to the Email template and Subject template using the config map, and dynamically control recipients using the mail variable. We provide the following examples that you can use in the Condition and configuration code editor:
Getting custom fields
To get custom fields that are accessible in your Email template and Subject template, you must use a config map instead of the import keyword, as this is not available in the template engine. This is done in the Condition and configuration code editor. You can also pass functions that you can call from the Email template.
As this code editor is also used for the condition, you must continue to return a boolean value to tell the system whether to send the email.
The following is a simple example of how to set up a config map in the Condition and configuration code editor:
config.storyPoints and config.capitalize(string) respectively.import com.atlassian.gzipfilter.org.apache.commons.lang.StringUtils
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.CustomFieldManager
def customFieldManager = ComponentAccessor.getComponent(CustomFieldManager)
def storyPointsCf = customFieldManager.getCustomFieldObjectByName("TextFieldB")
// add value of story points to config map
config.storyPoints = issue.getCustomFieldValue(storyPointsCf)
// add a closure
config.capitalize = { String str ->
StringUtils.capitalize(str)
}
return trueUsing the above, you could write your email template as follows:
Your config map may trigger static type checking warnings in your email template. These could be false positive warnings and your mappings should still function correctly. If you do see errors, we recommend you test your custom email to check it works as expected.
Dear User,
Story Points: ${storyPoints}
Function: ${capitalize.call('hello sailor')}def condition = issue.status.name == "Open" && ...
if (! condition) return false
def expensiveConfigVars = [foo: "bar"]
config.putAll (expensiveConfigVars)This code only populates the config map if the condition is met, implements an early return based on a condition check, and separates expensive operations into their own map. This approach prevents unnecessary computations when the script's conditions aren't met.
Controlling To and From addresses
In addition you must check the Disable validation option at the bottom of the form. By checking this box, you're telling Jira to skip its usual checks (for example, checking form fields) and allow the post function to be saved and executed based on your custom script logic.
Control over To addresses
You can dynamically set the email recipients and sender based on issue attributes or custom fields. This is done in the Condition and Configuration code editor using the mail object ( com.atlassian.mail.Email).
For example you can set recipients based on issue attributes as follows:
if (issue.priority.name == "Highest") {
mail.setTo("head-honcho@acme.com")
} else {
mail.setTo("chair-moistener@acme.com")
}You can also set recipients from a custom field as follows:
import com.atlassian.jira.component.ComponentAccessor
def multiSelectAddressesCF = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("Multi Select Email Adresses")
def recipients = issue.getCustomFieldValue(multiSelectAddressesCF)?.join(",")
mail.setTo(recipients)Control over From and Reply-to addresses
By default we typically use the From address associated with your configured SMTP server. This approach is adopted because many corporate mail relays are set up to accept emails from only one authorized sender. Allowing users to customize the From address has often led to confusion when the mail relay blocked these customized addresses. Therefore, instead of changing the From address, we recommend setting the Reply-to address. You can do this either within the form itself (using the Reply-to email address option) or by using the mail.setReplyTo(...) function in your code.
If you want to personalize how the sender's name appears in the recipient's mail client, you can use the mail.setFromName() function. For example, mail.setFromName("Example name"). If you needed to set the From address you could use the following:
mail.setFrom("example-name@example.com")Exclude watchers from custom email recipients
You may want to exclude watchers from the email recipients. For example, you can use the following code to set the email recipients programmatically in the Conditions and configuration code editor:
import com.atlassian.jira.component.ComponentAccessor
def locale = ComponentAccessor.getLocaleManager().getLocaleFor(currentUser)
def watchers = ComponentAccessor.getWatcherManager().getWatchers(issue, locale)
def cf = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("Multi User Picker CF")
//get the users' email addresses, in a comma separated string, that are members of the Multi User Picker custom field and are not watchers
def recipients = issue.getCustomFieldValue(cf)?.findAll { !watchers.contains(it) }?.collect {
it.emailAddress
}?.join(",")
mail.setTo(recipients)Adding generated attachments
You may wish to generate your own attachment and include it in the email. For example, you may want to add:
- an automatically generated invoice
- a custom PDF or Office document
- an Excel file with the output from a query
You can add the attachment in the Conditions and configuration code editor, for example:
import javax.mail.internet.MimeBodyPart
import javax.mail.internet.MimeMultipart
import javax.mail.internet.MimeUtility
import javax.activation.DataHandler
import javax.activation.FileDataSource
def mp = new MimeMultipart("mixed")
def bodyPart = new MimeBodyPart()
bodyPart.setContent("some text content", "text/plain")
//def attFds = new FileDataSource("/path/to/file.xls")
//bodyPart.setDataHandler(new DataHandler(attFds))
bodyPart.setFileName(MimeUtility.encodeText("foo.txt"))
mp.addBodyPart(bodyPart)
mail.setMultipart(mp)
trueEmail and subject templates
You can write the main body of your email in the Email template code editor. You can write the subject of your email in the Subject template code editor. Your templates can be plain text or use the GStringTemplateEngine. For example, your email template could look as follows:
Dear ${issue.assignee?.displayName},
The ${issue.issueType.name} ${issue.key} with priority ${issue.priority?.name} has been assigned to you.
Description: $issue.description
<% if (mostRecentComment)
out << "Last comment: " << mostRecentComment
%>
Custom field value: <% out << issue.getCustomFieldValue("TextFieldB") %>
Regards,
${issue.reporter?.displayName}Comments
You might want to reference comments in your email templates. The following variables are available for use in the email and subject templates:
| Variable name | Description |
|---|---|
lastComment | The comment made in this transition if there is one. If no comment is made this will be null, therefore you should wrap this in an if block, as shown in the example template. |
mostRecentComment | The comment made in this transition, or if there wasn't one, the most recent comment made prior to this transition. |
latestPriorComment | The latest comment made prior to this transition. Using this variable and lastComment can display a conversation thread. |
Rendering wiki markup fields
If you are sending HTML mails you will want fields containing wiki markup to be converted to HTML. You can use the following code in your templates to do this:
${helper.render(issue.description)}Including query results
You can include the results of a query in your email template - this will utilise the same velocity templates that Jira uses. For example:
${helper.issueTable("project = FOO and assignee = currentUser()", 10)}Getting old and new custom field values
You may want to retrieve a compare old and new custom field values to include this information in the custom email. For example, you could use this following code in your template:
<%
def change = transientVars.changeItems.find {it.field == "Name of custom field"}
if (change) {
out << 'Old: ' + change.oldstring + "
"
out << 'New: ' + change.newstring
}
%>Include attachments
The Include attachments function allows you to include issue attachments in your email. This feature is particularly useful for communicating with offsite collaborators who may not have Jira accounts. You have the following attachment options:
- None: Do not include any attachments
- New: Include only attachments added during this transition
Note: By default, New on the Issue Commented event will get any attachments found in the comment body. On Issue Created all attachments will be added. On other events, such as Issue Updated, any attachment that was added as part of that event's changeLog will be included.
- All: Include all attachments
- Custom: Define a custom attachment callback for precise control over attachment selection. Select Example scripts in the code editor for examples.
mail.mime.encodefilename=true
mail.mime.decodefilename=trueUse this post function
You can now test to see if this post function works.