Forums

Articles
Create
cancel
Showing results for 
Search instead for 
Did you mean: 

Assets automation groovy multiple objects duplicates result - DC not Cloud

Amy Martin November 5, 2025

Hi Everyone, 

I've developed a Groovy script that will run on a schedule in Asset Automation. This script uses IQL to obtain a list of objects and obtain the relevant attributes of the objects. It then sends an email. 

The script runs without error.

If I run the script through the Asset Script Console, the script runs as expected and I have 1 email output per object. 

However, I'm finding when the same script is run through Asset Automation, the emails are sent multiple times for each object. Initially I encountered this when attempting to add a comment to the object after the email was sent. I've removed the comment command and the issue persists. It appears to be sending an email each object x the objects processed. So if 3 objects are found, 3 emails for each object. 

I'm sure it's something simple that is causing it to iterate over the list or something. Just odd that it works fine. So it's likely to do with the Asset Automation Criteria


Script
 //Script Expiry Date

import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.mail.server.MailServerManager;
import com.atlassian.mail.server.SMTPMailServer;
import com.atlassian.jira.mail.Email;
import com.atlassian.jira.mail.builder.EmailBuilder
import com.atlassian.mail.queue.MailQueue
import com.atlassian.mail.queue.MailQueueItem
import com.atlassian.mail.queue.SingleMailQueueItem;
import com.atlassian.jira.issue.CustomFieldManager;
import com.atlassian.jira.issue.fields.CustomField;
import com.atlassian.jira.issue.IssueManager;
import com.atlassian.jira.issue.Issue;
import com.atlassian.jira.issue.MutableIssue;
import com.atlassian.jira.event.type.EventDispatchOption;
import org.joda.time.DateTime;
import java.util.Locale;
import com.riadalabs.jira.plugins.insight.channel.external.api.facade.ObjectFacade
import com.riadalabs.jira.plugins.insight.channel.external.api.facade.ObjectTypeAttributeFacade
import com.riadalabs.jira.plugins.insight.services.model.ObjectAttributeBean
import com.riadalabs.jira.plugins.insight.services.model.ObjectBean
import com.atlassian.jira.user.ApplicationUser


MailServerManager mailServerManager = ComponentAccessor.getMailServerManager();
SMTPMailServer mailServer = mailServerManager.getDefaultSMTPMailServer();
def mailQueue = ComponentAccessor.getMailQueue()

if (mailServer == null) {
log.error("No email smtp server configured, abort");
return;
}

//Commercial Asset Schema
int insightSchemaId = 11
int registerSchemaId = 4

//Foreign Work Authorsiation asset object attributes
def summaryAttId = 2034
def effectiveDateAttId = 2037
def expirationDateAttId = 2038
def personAttId = 2042
def statusAttId = 2646
def projectAttId = 2039
def projectNameAttId = 945
def scopeAttId = 2041

 

Class objectFacadeClass = ComponentAccessor.getPluginAccessor().getClassLoader().findClass("com.riadalabs.jira.plugins.insight.channel.external.api.facade.ObjectFacade");
def objectFacade = ComponentAccessor.getOSGiComponentInstanceOfType(objectFacadeClass)

// Search query to determine assets with expiry in 60 days time, including only currently active assets.
String IQLSearch = "iql query"


/* Get Assets Object Attribute Facade from plugin accessor */
Class objectTypeAttributeFacadeClass = ComponentAccessor.getPluginAccessor().getClassLoader().findClass("com.riadalabs.jira.plugins.insight.channel.external.api.facade.ObjectTypeAttributeFacade");
def objectTypeAttributeFacade = ComponentAccessor.getOSGiComponentInstanceOfType(objectTypeAttributeFacadeClass);

//
Class iqlFacadeClass = ComponentAccessor.getPluginAccessor().getClassLoader().findClass("com.riadalabs.jira.plugins.insight.channel.external.api.facade.IQLFacade")
def iqlFacade = ComponentAccessor.getOSGiComponentInstanceOfType(iqlFacadeClass)


// Search Asset Schema based on IQL query
def fwaList = iqlFacade.findObjects(insightSchemaId,IQLSearch)
//log.info("IQL Search result " + fwaList.toString())

//Obtain the details of each entry found in search results
if (fwaList){
fwaList.each{fwaObj ->
def summary = fwaObj.label

def userObjId = objectFacade.loadObjectAttributeBean(fwaObj.getId(),personAttId)
def userobj = userObjId.getObjectAttributeValueBeans()[0].getValue()
//log.info("userObj " + userObjId.getObjectAttributeValueBeans()[0].getValue())

def userNameObj = objectFacade.loadObjectAttributeBean(userobj, 754)
def userEmailObj = objectFacade.loadObjectAttributeBean(userobj,908)
def userDisplayObj = objectFacade.loadObjectAttributeBean(userobj,958)
def userName = userNameObj.getObjectAttributeValueBeans()[0].getValue()
def userEmail = userEmailObj.getObjectAttributeValueBeans()[0].getValue()
def userDisplay = userDisplayObj.getObjectAttributeValueBeans()[0].getValue()
log.info("UserName " + userName)
log.info("User Email " + userEmail)

def expiryDateObj = objectFacade.loadObjectAttributeBean(fwaObj.getId(), expirationDateAttId)
def expiryDate = expiryDateObj.getObjectAttributeValueBeans()[0].getValue()
///log.info("Expiry Date : " + expiryDate)

def projectList = new ArrayList()

String fwaKey = "COM-"+ fwaObj.id
def outRef = iqlFacade.findObjects("iqlquery" + fwaKey + ")")
log.info("OUtRef: " + outRef)

outRef.each{refobj ->
def projectObj = objectFacade.loadObjectAttributeBean(refobj.getId(),projectNameAttId)
def projectName = projectObj.getObjectAttributeValueBeans()[0].getValue()
log.info("Project Name : " + projectName)
projectList.add(projectName)
}

log.info("Project List : " + projectList.toString())
def scopeObj = objectFacade.loadObjectAttributeBean(fwaObj.getId(),scopeAttId)
def scope = scopeObj.getObjectAttributeValueBeans()[0].getValue()
log.info("Scope : " + scope)

// Email body html code
def bodyContent = """
<!DOCTYPE html>

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
email body
</body>
</html>
"""

//Create email and details
def messEmail = new Email(userEmail.toString())
messEmail.setMimeType("text/html")
messEmail.setSubject("Reminder")
messEmail.setBody(bodyContent)
messEmail.setFrom("email@here.com")
//messEmail.setBody(templatefile)
mailServer.send(messEmail)
}
}

2025-11-06_14-01-49.png

1 answer

0 votes
Jeroen Poismans
Community Champion
November 7, 2025

Hi Amy,

I think I see what is wrong here. You have a scheduled automation which does a selection, then an IF condition to refine the result.

The way Automation works is that the ACTION (script in your case) is going to be executed for every Asset passed in by the Schedule IQL  and then filtered by the Condition. So the behavior you are seeing is as expected.

So what you really want is that the filter you are doing in the script to be taken out of the script and put in the Schedule Trigger IQL. Then your script should just take in one Asset at a time and send the mail for that one Asset.

You can access the object variable from your script to access the current Asset being processed. object.key or object.id will get you the value to get attribute values as you do in your script already.

Take a look at this, it describes what I am saying about the object variable:

https://confluence.atlassian.com/servicemanagementserver0503/configuring-assets-automation-rules-1167849954.html

Hope this fixes your issue.

Suggest an answer

Log in or Sign up to answer
DEPLOYMENT TYPE
CLOUD
PRODUCT PLAN
STANDARD
TAGS
AUG Leaders

Atlassian Community Events