
- Post History
- Subscribe to RSS Feed
- Mark as New
- Mark as Read
- Bookmark
- Subscribe
- Printer Friendly Page
- Report Inappropriate Content
on ‎04-27-2021 04:30 AM
My requirement was very specific to write a reusable/generic Notification Email Script that can print/return the MRVS in Tabular/Grid format so that when a Request Submitter or Approver receives an Email Notification, he/she can see what they submitted or what to approve. Also, this needs to be easily managed by my Production Support team for any existing or future Catalog Item where there is an MRVS, with the help of a Configuration Change.
So let start with, What is the Multi-Row Variable Set?
Multi-Row Variable Set (MRVS) is a Variable Set of Type Multi-Row. It captures the variable data in a grid/tabular layout.
The article by Brad Tilton describes MRVS pretty well [Multi-row variable set]. Also, you can check ServiceNow docs for details of MRVS.
Now, To get this done. I made the following changes—
Step 1: Add a new List Control in table: Catalog Item/Maintain Item (sc_cat_item)
Application Scope: Global Table: sc_cat_item Type: List Column Label: Multi-row variable set in Email
Column Name: u_multi_row_variable_set_in_email Reference: Variable Set Reference qual condition: Type - is - Multi Row
and bring this to the Catalog Item form for later Configuration Change. (Note: you can select the MRVS letter in this control)
Step 2: A script include. This will help in formatting the MRVS and return that in HTML tabular format.
Name: mrvsFormatter Application: Global Accessible from: All application scope
var mrvsFormatter = Class.create();
mrvsFormatter.prototype = Object.extendsObject(AbstractAjaxProcessor, {
/*
Call this function like this--
var objFncs = new mrvsFormatter();
gs.print(objFncs.getMRVSFormated('7b750d0b1b232814be65c955624bcb40')); //ritm --> sys_id
*/
getMRVSFormated: function(i_ritmSysId) {
var ritmSysId = i_ritmSysId,
mrvsSysIDes = '',
mrvsTable = '';
var grRITM = new GlideRecord("sc_req_item");
if (grRITM.get(ritmSysId)) {
mrvsSysIDes = grRITM.cat_item.u_multi_row_variable_set_in_email;
if (mrvsSysIDes != '') {
var grVarSet = new GlideRecord("item_option_new_set");
grVarSet.addQuery("sys_idIN" + mrvsSysIDes);
grVarSet.query();
while (grVarSet.next()) {
var mrvsSysId = grVarSet.sys_id;
var mrvsTitle = grVarSet.title;
var mrvsInternalName = grVarSet.internal_name;
mrvsTable = mrvsTable + "\n" + this.getFormatedTable(mrvsSysId, mrvsInternalName, mrvsTitle, i_ritmSysId);
}
}
}
return mrvsTable;
},
/*
Call this function like this--
var objFncs = new mrvsFormatter();
gs.print(objFncs.getFormatedTable('11e0039bdbc87700bc1a72fc0f9619bf', 'grp_owner_domain', '7b750d0b1b232814be65c955624bcb40'));
*/
getFormatedTable: function(i_mrvsSysId, i_mrvsName, i_mrvsTitle, i_ritmSysId) {
var mrvsSysId = i_mrvsSysId,
ritmSysId = i_ritmSysId,
mrvsName = i_mrvsName,
mrvsTitle = i_mrvsTitle,
col = '',
colHeader = '';
Table = '<table style="width: 100%; border-collapse: collapse; border: 0.0pt; float: left; font-family: arial, sans-serif; font-size: 12px; line-height: 25px; color: #55565A; padding-left: 4px; padding-right: 4px; padding-top: 2px; padding-bottom: 2px; text-align: justify; vertical-align: top;" cellspacing="0" cellpadding="2">',
TH = [],
TR = '',
rowCount = 0,
totalColumn = 0;
var grMultiRow = new GlideRecord('item_option_new');
grMultiRow.addQuery('variable_set=' + mrvsSysId + '^active=true');
grMultiRow.orderBy('order');
grMultiRow.query();
while (grMultiRow.next()) {
var variableName = grMultiRow.question_text.toString();
if (col == '')
col = variableName;
else
col = col + ',' + variableName;
}
TH = col.split(',');
totalColumn = TH.length;
colHeader = colHeader + '<tr style="height: 25px; text-align: left;">';
for (var h = 0; h < totalColumn; h++) {
colHeader = colHeader + '<td style="font-weight:bold; border-collapse: collapse; border-style: solid; border: solid #AEAAAA 1.0pt;">' + TH[h].toString() + '</td>';
}
colHeader = colHeader + '</tr>';
var now_GR = new GlideRecord('sc_req_item');
if (now_GR.get(ritmSysId)) {
var mrvs = now_GR.variables[mrvsName]; //.grp_owner_domain;
//gs.print(mrvs);
rowCount = mrvs.getRowCount();
for (var i = 0; i < rowCount; i++) {
TR = TR + '<tr style="text-align: left; height: 25px;">';
var row = mrvs.getRow(i);
var cells = row.getCells();
for (var k = 0; k < cells.length; k++) {
var cell = cells[k];
//gs.info(cell.getLabel() + ":" + cell.getCellDisplayValue())
var colVal = cell.getCellDisplayValue();
TR = TR + '<td style="border-collapse: collapse; border-style: solid; border: solid #AEAAAA 1.0pt;">' + colVal + '</td>';
}
TR = TR + '</tr>';
}
}
if (rowCount > 0) {
Table = Table + '<tr><td colspan=' + totalColumn + ' style="font-weight:bold; border: 0px; text-decoration: underline;">\n\n' + mrvsTitle + '\n</td></tr>';
Table = Table + colHeader;
Table = Table + TR;
Table = Table + '</table>';
} else
Table = ''; //If there is no data in mrvs don't print
return Table;
},
type: 'mrvsFormatter'
});
Step 3: A Notification Email Scripts. this can be inserted in the Notification and ensures that the MRVS is printed on the notification email.
Name: mrvsEmailScript
(function runMailScript( /* GlideRecord */ current, /* TemplatePrinter */ template,
/* Optional EmailOutbound */
email, /* Optional GlideRecord */ email_action,
/* Optional GlideRecord */
event) {
var scCatItemSysId = '', mrvsSysIDs = '', ritmSysId = '', mrvsTable = '';
scCatItemSysId = current.cat_item.sys_id;
mrvsSysIDs = current.cat_item.u_multi_row_variable_set_in_email;
ritmSysId = current.sys_id;
if (mrvsSysIDs != '') {
var objFncs = new global.mrvsFormatter();
mrvsTable = objFncs.getMRVSFormated(ritmSysId); //'7b750d0b1b232814be65c955624bcb40'));
if (mrvsTable != '') {
template.print(mrvsTable);
}
}
})(current, template, email, email_action, event);
Now we are all set to use this in the Notification.
Step 4: If you don't have a Catalog Item with MRVS. Create it and then select your MRVS (in my case Internal Name: please_link_laptop_or_computer_to_user) in the "Include in". My MRVS looks as below-
Step 5: A Notifications (System Notifications -> Email -> Notifications). (I create a custom but you can use any existing Notification).
Name: Request Item Status Change Table: sc_req_item Send When: Record inserted or updated Updated: Checked Condition: State – Changes Who will receive -> Users/Groups in fields -> Request.Opened by What it will contain -> Subject: Number: ${number} Message HTML: ${mail_script:mrvsEmailScript}
Step 6: Now let's go to the Catalog Item form and select the MRVS (please_link_laptop_or_computer_to_user) in the LIST (ref: Step 1).
Step 7: Submit a Request and copy the RITM number. Go to the Emails table and search your email and click on "Preview Email"
Here you go!!!
Note: If you don't want a reusable code, only the function getFormatedTable of script include should be suffecient.
- 10,916 Views
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Can you clarify the script include..
(objFncs.getMRVSFormated('7b750d0b1b232814be65c955624bcb40')); //ritm --> sys_id */
&
Call this function like this-- var objFncs = new mrvsFormatter(); gs.print(objFncs.getFormatedTable('11e0039bdbc87700bc1a72fc0f9619bf', 'grp_owner_domain', '7b750d0b1b232814be65c955624bcb40')); */
This seems confusing to me - but I am fairly new to scripting in ServiceNow- just wondering which sys_id would be inserted into each line?
Thank you
Melissa

- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Looks like this is working for me. Thanks for putting this together. Well written!!

- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Thank you, Chris! I am glad to hear this.

- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Thanks for this! This is such a life saver.
Would you have an idea how can we combine this with the other normal variables in the RITM so that we can get exactly what the user submitted? We currently get the normal variable value using GlideappVariablePoolQuestionSet but that will omit any MRVS. Now that you have this script for the MRVS, how can we incorporate them both so that whatever order of the normal variables/MRSV will be on the form, that's exactly how it will be printed out by the script.

- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Thank you, JC! I am glad, for your word - "Life Saver".
Certainly, we can print the variables in the same order. Let me write that for you and post it here.
With regards,
Satyendra Kumar
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
This was fantastic and helped me greatly. Any ideas on how you could CC the attendees name into the email notification?

- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
I am glad to know that this helped you!
You can specify copied and blind copied recipients by using the email object within a mail script.
email.addAddress("cc", 'er.satyendragupta@gmail.com', 'Satyendra Kumar');
email.addAddress("bcc", 'satyendrakgupta@outlook.com', 'Satyendra Gupta');
Reference: Example scripting for email notifications
Thanks and regards,
Satyendra Kumar
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi Sat,
Is this able to handle multiple MVRS tables in the one catalog item?

- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Thanks Sat,
Is this setup currently just set up to run for notifications off the sc_req_item table? or should it also work from the catalog task and/or approval table?
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Guessing would just need to change the mailscript to refer to the related RITM fields, will give that a go tomorrow

- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi Mike,
Request, Request Item, Task & Approvals have a very good relationship with each other and hence this solution can work for any one of these. In case you have any challenge implementing it, please share your exact requirement & if I get time, I'll write a solution for you.
With regards,
Satyendra Kumar
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Awesome work, thank you

- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
I have the same need. We have notifications that are sent from the sc_task table and the approval table.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi Chris, this email script should cater for emails that need to send from the request/request item/catalog task and sysapproval table.
(function runMailScript(current,template,email, email_action,event) {
var scCatItemSysId = '', mrvsSysIDs = '', ritmSysId = '', mrvsTable = '';
var curTaskType = current.getTableName();
if (curTaskType == 'sysapproval_approver'){
var relTaskType = current.sysapproval.sys_class_name;
if (relTaskType == 'sc_req_item'){
scCatItemSysId = current.sysapproval.ref_sc_req_item.cat_item.sys_id;
mrvsSysIDs = current.sysapproval.ref_sc_req_item.cat_item.u_multi_row_variable_set_in_email;
ritmSysId = current.sysapproval.ref_sc_req_item.sys_id;
}
else if (relTaskType == 'sc_request'){
var gr = new GlideRecord('sc_req_item');
gr.addQuery('request.sys_id', current.sysapproval.ref_sc_request.sys_id);
gr.query();
if (gr.next()){
scCatItemSysId = gr.cat_item.sys_id;
mrvsSysIDs = gr.cat_item.u_multi_row_variable_set_in_email;
ritmSysId = gr.sys_id;
}
}
}
else if (curTaskType == 'sc_task'){
scCatItemSysId = current.request_item.cat_item.sys_id;
mrvsSysIDs = current.request_item.cat_item.u_multi_row_variable_set_in_email;
ritmSysId = current.request_item.sys_id;
}
else if (curTaskType == 'sc_req_item'){
scCatItemSysId = current.cat_item.sys_id;
mrvsSysIDs = current.cat_item.u_multi_row_variable_set_in_email;
ritmSysId = current.sys_id;
}
else return;
if (mrvsSysIDs != '') {
var objFncs = new global.mrvsFormatter();
mrvsTable = objFncs.getMRVSFormated(ritmSysId);
if (mrvsTable != '') {
template.print(mrvsTable);
}
}
})(current, template, email, email_action, event);
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi Satyendra,
We have a similar requirement however on the approval table.
How can we implement this on approval notifications?
Any help would be really appreciated.
Regards,
Surabhi
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi Mike,
I tried using the above script for approval notification but doesnt seem to be working.
Can you suggest what else do we need to do for the table to be printed on the approval notification.
Regards,
Surabhi

- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi Surbhi,
The Request Item's approval also goes to Approval table and as far as Multi-row variable set is concern, it is only available as a Catalog Item's variable. So, this solution should work. May be I need a bit details about your requirement or may be the way you are trying to implement.
Thanks and regards,
Satyendra Kumar

- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi Mike,
Thanks for sharing this. We were able to get this to work for us.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi there @satyendrakgupta ,
We've been able to implement this for one of our business needs. Great work!
However, I'm using this for multiple MVRS tables, and even though they all show up, they don't end up showing up in the same order in the notification email than in the form.
Form example:
MVRS 1: A1 (order 100)
MVRS2: A2 (order 200)
MVRS3: A3 (order 300)
Notification received:
A3
A1
A2
Any ideas on this?
Thanks for your help!
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
In reply to my previous question, I found the answer if anyone had the same question regarding the order of multiple MVRS tables being all over the place.
Solution:
In the script include (here called mvrsFormatter) insert the following line : grVarSet.orderBy("order");
getMRVSFormated: function(i_ritmSysId,mrvsSysIDs) {
var ritmSysId = i_ritmSysId,
mrvsSysIDes = '',
mrvsTable = '';
var grRITM = new GlideRecord("sc_req_item");
if (grRITM.get(ritmSysId)) {
mrvsSysIDes = mrvsSysIDs;
if (mrvsSysIDes != '') {
var grVarSet = new GlideRecord("item_option_new_set");
grVarSet.addQuery("sys_idIN" + mrvsSysIDes);
grVarSet.orderBy("order");
grVarSet.query();
it's important to include this line in the script include and not the notification email script itself.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi Satyenragupta,
the script is helpful for me , i got one issue that it is populating the values of those variables set but it is not printing the variable labels , please find the screenshot.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Thanks for your clarification on this post. It solved my issue with NO Data in MRV's.
Thank YOu
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
My MRVS has several columns, can this be formatted for columns headers to be in the rows and individual set of data added in the columns for sake of readability?
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
HI @satyendrakgupta ,
I have tried the notification part of getting the multirow variable set in the notification. In my case, it's showing undefined.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hello,
I have made a simplified version of the script.
In this script you dont need to add a field and to list the variable sets you just need to call the getMRVSFormatted function passing the sys_id of the RITM and the script will look for MVRS and for regular variables and will put them into tables.
Example of calling the the script include from mailscript:
Script Include: