Showing results for 
Search instead for 
Did you mean: 
Showing results for 
Search instead for 
Did you mean: 

Community Tip - Visit the PTCooler (the community lounge) to get to know your fellow community members and check out some of Dale's Friday Humor posts! X

Consolidate information into one email.


Consolidate information into one email.

I'm looking for the best way to consolidate information into one email for a scheduled (weekly or monthly) report. I have found using emailAdvanced.js will get me close to what I want, but it sends a user an email for each item. Instead, if the query returns multiple items for the same user, I would like the user to receive only one email. I have also looked at ReportLinkEmail.js, but this script is only allowed to be used as a rule based trigger, and not a scheduled trigger. Does anyone have any recommendations for modifying either of these scripts to do what I want? Are there alternatives that I'm not aware of?


Hi Christina,

This is definitely something that customizing a trigger script can deliver.

You can start with emailAdvanced.js and change how the bulk processing works (so that it clumps items for the same user instead of 1 email per item) or you can start from ReportLinkEmail.js and change it so that it allows bulk processing.

You could also start from scratch and write a new trigger script to do exactly what you want. At the end of that exercise you will probably have a greater understanding of how the trigger scripts work as well as a trigger script that exactly meets your needs, but it will take a while to do.

In any case, the key to understanding how to create or modify these triggers will start with how the various kinds of triggers differ.

The main difference between a rule based trigger and a scheduled trigger is how you get to the "issueDeltaBean". The issueDeltaBean is the mechanism for reading the values of fields from an item or writing new field values to an item, so it is used in pretty much every workflow and documents trigger.

In a rule based trigger, the issueDeltaBean represents the single item that the trigger is running against. If you set up a trigger to fire when the state changes from Active to Complete, and the state of item 1234 changes from Active to Complete, then your trigger will get an issueDeltaBean representing item 1234.

In most triggers, the way to get this issueDeltaBean is to use 'bsf.lookupBean("imIssueDeltaBean")'

In a scheduled trigger, the trigger is passed an array of issue IDs representing every item in the query run when the trigger executes. Most triggers handle this array by looping over each ID, loading the issueDeltaBean from that ID and processing it individually. Some example code which does this in our triggers is:

var beanServer = bsf.lookupBean("imServerBean");

var args = bsf.lookupBean("imScheduleTriggerArgumentsBean");

var issues = args.getIssues();

for ( var i = 0; i < issues.length; i++ ) {

beanDelta = beanServer.getIssueDeltaBean( issues[i] );

if (beanDelta != null) {




So, for changing the ReportLinkEmail.js to handle scheduled triggers, you would need to build something like the above.

At the same time, all this does is process the individual issueDeltaBeans separately (like emailAdvanced,js already does), but you want to process them together so that you can group the items and send out a single email per user.

To do this grouping, you will probably want to add some variables (maybe from Java collections) which keep track of the list of issueDeltaBeans applicable to each user as each issueDeltaBean is processed. After all the issueDeltaBeans have been handled, you will want to loop over those variables and use the data to construct the emails to send to each individual user.

A final word of caution is that storing all that data during a scheduled trigger to bulk process later on will cause the trigger to run slower and use more memory. The performance hit will scale up with the number of items returned in the scheduled trigger's query. I would not imagine that this would take down a well performing server, but it is something to keep in mind while designing, testing, and using the new trigger.

Hope that helps,


Thanks, this information was very helpful. Is there an easy way to sort the results of the query by the user I want to email the results to? That may reduce the amount of information I need to store.

Unfortunately I don't think its possible to sort the results in the query itself and have the trigger use that. I just tried with a test trigger and no matter what the sorting was on the query, the trigger still processed them in the order of their IDs.

The data structure you use to handle the data before your second processing loop could hold it in a sorted order, such as a java treemap or treeset, but that seems to be it.

Hi Matt and Christina,

Please contact our customer support department and file a request to have the scheduled trigger arguments bean .getIssues() method return items in the sort order specified by the query if you believe that would be useful. It certainly seems reasonable, and probably expected behaviour to me. However, it is beneficial for our Product Management to track input from our customers against requests in the system, so it would be better to have you file the request than me.

If you are strictly reporting on items in your trigger (make no modifications), then I would recommend you use the server bean's .getIssueBean method rather than .getIssueDeltaBean since you do not need/want to create an edit session for each item. The .getIssueBean also comes in flavours that accept the desired fields, as well as an array of item IDs. These can significantly enhance the performance of your trigger.

e.g. var items = serverBean.getIssueBeans(args.getIssues(), arrayOfFieldsIWant);

This is akin to running a single:

SELECT (fields I want) FROM items (WHERE ID in (array,of,items))

Rather than successively running:

SELECT * FROM items WHERE (ID = singleItem)




Great point, we do make use of getIssueBeans() for optimization where possible.

With that siad, I would recommend that anyone building a new trigger script first get the script working with issueDeltaBeans, even if it is more inefficient, and then refactor for optimizations like getIssueBeans after it is already working.

The reason for this is that while getIssueBeans() is very powerful, it is also easy to accidentally introduce subtle bugs while using it. For example, we recently had a bug where values copied from Issue A were not getting set properly on Issue B. The root cause ended up that a field was missing from the array in the getIssueBeans() call, so when we did the below code, it was reading null values from the missing field (because we did not request the field in the getIssueBeans call) instead of the values on the item itself.

issueDeltaBeanB.setFieldValue( destinationFieldName, issueBeanA.getFieldValue(sourceFieldName))

I will go ahead and open a support case for the query sorting in scheduled triggers, thanks for the heads up.


There are three forms of getIssueBean (at least in reasonably current releases):

getIssueBean(int i)

getIssueBean(int id, java.lang.Object[] fields)

getIssueBeans(int[] ids, java.lang.Object[] fields)

If you aren't intending to edit, I still recommend using the first form instead of getIssueDeltaBean(int ID). It will get you all the fields the same as the delta, but won't provide getNew/getOldFieldValue methods so you won't accidentally have those in your code prior to further optimizations with the other forms of getIssueBean. The methods are sort of analogous to "im viewissue <id>" versus "im issues --fields=... <id1> <id2> ...".

However you raise an excellent point that I should have highlighted -- getIssueBean methods that take an array of fields will give you a null value (rather than an error) if you try to retrieve a field that wasn't requested later on. This can be tricky to spot and confusing to debug. Feel free to open a support case and suggest throwing an exception instead of returning a null if you think that would be a more appropriate behaviour