Script runner mail handler - Read Body and find the custom field values to set it in jira

Omprakash Thamsetty
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
December 15, 2021

Hi,

 

I am trying to modify my existing Mail Handler script to find the custom field value in Email Body and then update in Jira. Example format is here 

 

Customer Name: Omprakash Thamsetty  ( This field is text field )

Severity: 1 Critical    ( This field is single selection field)

Description: TEST: Sending this email to create jira ticket via email reader

 

So how I can read Customer Name, Severity and description information from Body using script and then create the jira ticket with that info?

 

As of now we are using issueObject.setDescription(body) to set description but now I need to have some email template body as above and then add the values to custom field. How can I achieve this using Mail Handler?

 

Thanks,

Om

1 answer

1 accepted

1 vote
Answer accepted
Radek Dostál
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
December 16, 2021

Not really dealing with mail handlers, but assuming we're looking at something similar to this: https://scriptrunner.adaptavist.com/latest/jira/mail-handler.html#_change_issue_status

 

So I played around the proof of concept a little bit and got to this kind of an idea - and just to point out, I did not deal with the actual handler or anything, just the console.

import com.atlassian.jira.bc.issue.IssueService
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.config.IssueTypeManager
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.issue.IssueInputParameters
import com.atlassian.jira.issue.context.IssueContext
import com.atlassian.jira.issue.context.IssueContextImpl
import com.atlassian.jira.issue.customfields.manager.OptionsManager
import com.atlassian.jira.issue.customfields.option.Option
import com.atlassian.jira.issue.customfields.option.Options
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.issue.fields.config.FieldConfig
import com.atlassian.jira.issue.issuetype.IssueType
import com.atlassian.jira.project.Project
import com.atlassian.jira.project.ProjectManager
import com.atlassian.jira.user.ApplicationUser

final String body = """This is a test body
Severity: 1 Critical
Description: sample description
"""

String severityMatcher = "Severity: .*"
String severityMatch = body.find(severityMatcher)
String severityValue = null

if (severityMatch) {
severityValue = severityMatch.substring(severityMatch.indexOf(' '))
}

if (severityValue != null) {
//this is just an example of proof of concept, not really a fully fledged working script
CustomFieldManager customFieldManager = ComponentAccessor.getCustomFieldManager()
CustomField severityField = customFieldManager.getCustomFieldObjectsByName("Severity")?.first() //careful about this if you have more than 1 field with that name
if (severityField != null) {
ProjectManager projectManager = ComponentAccessor.getProjectManager()
IssueTypeManager issueTypeManager = ComponentAccessor.getComponent(IssueTypeManager)

Project project = projectManager.getProjectByCurrentKey("ABC")
IssueType issueType = issueTypeManager.getIssueType("Task")
if (project != null && issueType != null) {
IssueContext issueContext = new IssueContextImpl(project, issueType)
FieldConfig fieldConfig = severityField.getRelevantConfig(issueContext)

OptionsManager optionsManager = ComponentAccessor.getOptionsManager()
Options options = optionsManager.getOptions(fieldConfig)
Option criticalOption = options.findByName(severityValue)

if (criticalOption != null) {
//Now we have the custom field and custom field value, so we can create the issue with it
ApplicationUser mailhandleruser = ComponentAccessor.getUserManager().getUserByName("mailhandler_actor")

IssueService issueService = ComponentAccessor.getIssueService()
IssueInputParameters issueInputParameters = issueService.newIssueInputParameters()
issueInputParameters.with {
it.setSummary("abc")
it.setDescription("def")
it.addCustomFieldValue(severityField.getId(), criticalOption.getOptionId().toString())
}

IssueService.CreateValidationResult createValidationResult = issueService.validateCreate(mailhandleruser, issueInputParameters)
if (createValidationResult.isValid())
issueService.create(mailhandleruser, createValidationResult)
}
}
}
}

 

The question is, you say you want to create a new issue - what is your current approach to it? I think there might be 2 ways to do so. Typically IssueInputParameters is what I use: https://library.adaptavist.com/entity/update-the-value-of-custom-fields-through-the-script-console

 

So then depending on your approach it should be possible to set the value (given that everything else works). Note that I did not fully test above snippet, it's just what I would start with. You may want to incorporate part of it into your own script.

 

Another part to improve is the severity matcher. This here looks anywhere in the body. I tried to limit it to '^$' as in start and end of line, but the groovy didn't want to work with it (tried also Pattern and Matcher java classes, no budge). It's definitely possible but just couldn't fix it quickly enough. Then of course you might want to play around the regex, what if there isn't space, is your format always the same, etc., but just a general idea for now.

 

Just to re-iterate, I don't really do mail handlers, just a quick look around and thinking process what I'd do. Could still be that there is a better approach to all of this.

Omprakash Thamsetty
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
December 16, 2021

@Radek Dostál

This script helps me to start working on the severity field. I am asking the sender to have the severity in one line with the format that I mentioned so If that format is not mentioned then I may go ahead and set the default value.. If the format is correct then I will set the severity with the value of the email body. 

But this script helps and think about how we can read the mail body and get the field values from it. 

 

Thank you so much for the help. 

Omprakash Thamsetty
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
December 23, 2021

Hi @Radek Dostál I tried to put constant value instead of reading from email body. I did the coding little different. It is working but I see the error in incoming mail reader console. 

 

Here is my script and error message. 

 

def project = projectManager.getProjectObjByKey("DFRHD")
IssueType issueType = issueTypeManager.getIssueType("Helpdesk")



def issueServiceobj = ComponentAccessor.getIssueService()
def issueInputParametersobj = issueServiceobj.newIssueInputParameters()

def subject = message.getSubject() as String
def body = MailUtils.getBody(message)
def fromAddr = MailUtils.getSenders(message)
def cfvalue = fromAddr as String
def EmailID = cfvalue?.replaceAll(/^\[([\s\S]*)]$/,'$1')
//Set up for project/users/inbox
UserManager userManager = ComponentAccessor.getUserManager()
//Change lines for the correct email inbox to test
ApplicationUser user = userManager.getUserByName("dfrmoserhelpdesk")
//If the subject line has an issue id, see if it exists
def issueMatcher = /DFRHD-[0-9]*/
def issueResult = subject =~ /$issueMatcher/

def issue = ServiceUtils.findIssueObjectInString(subject)
if (issue) {
return
}

def issueObject = issueFactory.getIssue()
def ContactEmailField = customFieldManager.getCustomFieldObjectsByName("Customer Email").first()

issueObject.setProjectObject(project)
issueObject.setSummary(subject)
issueObject.setDescription(body)
//issueObject.setPriority("Normal")
issueObject.setPriorityId(ComponentAccessor.getConstantsManager().getPriorities().find{it.getName().equals("4 Low")}.getId())
issueObject.setIssueTypeId(project.issueTypes.find { it.name == "Helpdesk" }.id)
issueObject.setReporter(user)
def projectComponentManager = ComponentAccessor.getProjectComponentManager()
def componentA = projectComponentManager.findByComponentNameCaseInSensitive('1st Level Support')
issueObject.setComponent(componentA)
issueObject.setCustomFieldValue(ContactEmailField, EmailID)

issue = messageHandlerContext.createIssue(user, issueObject)

def attachments = MailUtils.getAttachments(message)
attachments.each { MailUtils.Attachment attachment ->
def destination = new File(jiraHome.home, FileService.MAIL_DIR).getCanonicalFile()
def file = FileUtils.getFile(destination, attachment.filename) as File
FileUtils.writeByteArrayToFile(file, attachment.contents)
messageHandlerContext.createAttachment(file, attachment.filename, attachment.contentType, user, issue)
}

def cfConfig = sevFld.getRelevantConfig(issue)
def value = ComponentAccessor.optionsManager.getOptions(cfConfig)?.find {
it.toString() == '4-Low'
}

issue.setCustomFieldValue(sevFld, value)

def reqsrcfld = customFieldManager.getCustomFieldObjectsByName("Request Source Type").first()
def cfreqsrcConfig = reqsrcfld.getRelevantConfig(issue)
def reqsrcvalue = ComponentAccessor.optionsManager.getOptions(cfreqsrcConfig)?.find {
it.toString() == 'Email'
}
issue.setCustomFieldValue(reqsrcfld, reqsrcvalue)
issueManager.updateIssue(user, issue, EventDispatchOption.DO_NOT_DISPATCH, false)

}

Error Message

 

Mail-handler.pngany help much appreciated.  

Radek Dostál
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
December 23, 2021

On first look based on static type checking, you are trying to set a value on an "Issue" object. You can only do so on a "MutableIssue" object.

Issue is sort of.. say, read-only reference of an issue.

MutableIssue is an editable reference. When the MutableIssue has got all the changes and whatnot, then you can "publish" them via issueManager.updateIssue(...).

The easiest way out of this is to obtain a MutableIssue reference via issueManager.getIssueObject(issue.getId()) or via a cast, e.g. MutableIssue mutableIssue = (MutableIssue) issue; cast should work too I think.

 

So essentially

def issueObject = issueFactory.getIssue()

is giving you MutableIssue, you are modifying that, no problems, later on you are creating it with

issue = messageHandlerContext.createIssue(user, issueObject)

and this returns an Issue object, not a MutableIssue

 

So if you want to modify it then you need to get the MutableIssue reference first

mutableIssue = (MutableIssue) issue

and that's where you can set custom field values, and then do an update via issueManager.

Like Filip Torz likes this
Omprakash Thamsetty
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
December 23, 2021

@Radek Dostál Yes, You are correct. I did issue to mutable issue then the error message gone and script works fine. Thank you so much for your help. 

Omprakash Thamsetty
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
December 23, 2021

Hi @Radek Dostál I am sorry for asking another question on this thread. But it is related to mail handler only. 

 

I am getting the full name from directory but I need in format of LastName, FirstName but it is giving me Firstname Lastname. Example: Output Omprakash Thamsetty but I need Thamsetty, Omprakash. How can I get this? Do you have any idea?

 

def custNameField = customFieldManager.getCustomFieldObjectsByName("Customer Name").first()
def dirUsers = userSearchService.findUsersByEmail(EmailID)
if (dirUsers) { //If one exists
def cwdDirUserVal = dirUsers.first().displayName // grab the first one if there are more than one
log.info "fullname" + cwdDirUserVal
//Set Contact Name field here
issueObject.setCustomFieldValue(custNameField, cwdDirUserVal)

} else {
//Do nothing
log.debug "The Director Full Name was not found! ${EmailID}"
}

Radek Dostál
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
December 24, 2021

Jira only has "displayName", so there is no first/middle/last to use. If you need to use a different format then you would need to reformat the displayName string you get out of the user.

 

Something like this "might" work but that largely depends on the names, I'm not sure how many different name formats there are in the world but I've come across some really funky ones in my days. This is though getting more java/groovy topic-ey:

class Scratch {
public static void main(String[] args) {
String displayName = "Jon Doe";
String displayName2 = "Joanna A Doelina";

System.out.println(Scratch.reformatDisplayName(displayName));
System.out.println(Scratch.reformatDisplayName(displayName2));
}

public static String reformatDisplayName(String displayName) {
String[] displayNameSplit = displayName.split(" ");
int length = displayNameSplit.length;
switch (length) {
case 1:
return displayNameSplit[0]; //Just one name in here
case 2:
return displayNameSplit[1] + ", " + displayNameSplit[0]; //Lastname, Firstname
case 3:
return displayNameSplit[2] + " " + displayNameSplit[1] + ", " + displayNameSplit[0]; //Lastname Middlename, Firstname
case 4:
return "please change your name sir/ma'am";
default:
return "if we really get this far, refer to case 4";
}
}
}

//system.out
Doe, Jon
Doelina A, Joanna

 

Alternatively a more reliable way would be to use whatever directory has the correct name details, such as your AD which is more likely to hold first/last names. Jira doesn't split it in any case so it's never going to be a IOO% accurate way to do it.

 

Rodolfo So May 28, 2022

 

Hi  @Radek Dostál 

 

Can you help me on how to update multi select field based from the email body using scriptrunner email handler?

Vetrical field is multi select field

Email body

inal String body = """This is a test body

 

Vertical: [ "option1","option2"]

 

Description: sample description

 

"""

 

 

 

Appreciate your help on this

Suggest an answer

Log in or Sign up to answer
DEPLOYMENT TYPE
SERVER
VERSION
8.13.4
TAGS
AUG Leaders

Atlassian Community Events