Email notifications can be configured to distribute links to VividCharts assets using ServiceNow’s built in email functionality. Emails can be configured to send single or multiple links which can be dynamically generated at the time the email is distributed. Code examples are provided as boilerplate templates, but feel free to customize to your needs.
Prerequisite: VividCharts dashboard or summary should be created and shared with the appropriate users as we will need the URLs to add to the email notification. The permissions of the dashboard or summary should ideally encompass anyone who is a possible recipient of the email notifications.
For this example, we are creating a notification that contains a list of dynamically generated links based on ServiceNow records that meet certain criteria. More specifically, a list of Incidents.
Before starting we should already know these 3 items:
Who should receive the email notification
What the email notification should contain
When the email notification should be sent
This tutorial creates 5 records in ServiceNow so it is important that you have the applicable roles and permissions to create them. These are the record types we will be creating:
NOTE: While not required, we recommend building these items in the VividCharts Data Engagement application scope (x_vivid_vc_core)
Step 1: Register a new event
Navigate to the Event Registry list view. This can be found by typing ‘Event Registry’ in the filter navigator, or by typing “sysevent_register.LIST” in the filter navigator.
With the list open, click new to create a new record.
In the new record fill in all relevant fields. For this example:
Suffix: incident_email_example (The event name will then auto populate with the full event name by adding the application scope as a prefix)
Table: Incident as we are reading records from the incident table
Fired By: Scheduled Job - Generate Incident Email Example. This is free form so use what will help you keep track of the script firing the event.
Description: Event used to Generate an example of an Incident Email
Click submit.
Step 2 - Create a Scheduled Job
In the filter navigator, type ‘Scheduled Job’. Find the module called Scheduled Jobs under System Definition and click to open the list of Scheduled Jobs. Alternatively, you can type “sysauto_script.LIST” in the filter navigator.
Click new to create a new Scheduled Job record. (If asked what you would like to automate, click Automatically run a script of your choosing).
In the new record, populate relevant fields. For this example, we used the following:
Name: Generate Incident Email Example (Remember, this the same name we used in the event registry under the Fired By field)
Active: True (This can be toggled to False to pause the email distribution)
Run: Weekly
Day: Monday
Time Zone: Use System Time Zone
Time: 8:00am
NOTE: Of course, configure the frequency of the email distribution to your company’s needs.
Run This Script (This is Javascript code and we are calling the event we registered in Step 1. The event name between the quotes should match the event name you created)” gs.eventQueue('x_vivid_vc_core.incident_email_example');
Click Submit
Step 3 - Create the email Notification
In the filter navigator type in ‘Notifications’. Under System Notification locate the Email module and click on Notifications to open the list of Notifications. Alternatively, you can type “sysevent_email_action.LIST” in the navigator to open the list.
Click New to create a new record.
Add the name for the email notification. In this example, we are using the name “Weekly Incident Email Example”. Leave all the other options as-is.
Next, notice the 3 tabs When to send, Who will receive, and What it will contain. The next 3 steps will configure each of these tabs.
When to send - With the When to send tab selected. Change the “Send when” field to the “Event is fired” option. The event name field will not be shown. Choose the event we configured in Step 1. In the case of this example, we are using “x_vivid_vc_core.incident_email_example”. Leave the conditions as-is.
Who will receive - Select the Who will receive tab. This tab will allow you to define who receives the notification. We are able to select individual users, groups, and users/groups in field. For this example, we are sending the notification to a single user and the group VividCharts Builders. We can leave Subscribable unchecked.
What it will contain - Select the What it will contain tab. There are 3 main sections.
Email template: Leave as-is (Unsubscribe and Preferences)
Subject: This is the subject line of the email notification and will be visible to recipients. In this example, we used Major Incidents Opened This Week.
Message HTML (Body of the email): This is the body of the email and can contain text, html, images, and mail scripts.
Free typed text containing a salutation and text to give some context to the information that will be displayed by the mail_script below.
This is a mail_script which is used to dynamically display a list of incidents as an HTML table. It is denoted by ${mail_script:Name of the mail script}. In this case, it is called “GenerateIncidentLinksExample” and we will create this mail script in the next step. But the name should be descriptive of what information is being generated.
Click Submit to save and create the new record.
Step 4 - Create the Mail Script
Type ‘Notification Email Scripts’ in the filter navigator and select Notification Email Scripts under the Email module. Alternatively, you can type “sys_script_email.LIST” in the navigator to open the list of mail scripts.
Click New.
Using the name of the email script used in Step 3, populate the name field. In this case, we used “GenerateIncidentLinksExample”. The Javascript in the script field in the screenshot below is automatically generated. Leave all other fields as-is
Selecting EVERYTHING in the Script field, hit delete to completely clear the Script field.
Copy the script below and paste it into the Script field.
The script can be configured as needed but does require some basic knowledge of JavaScript. By line of the script that has been pasted into the Script field, here are some of the configurable items.
Around lines 34-36(search for ‘Script Step A’): Sets which field dictates the sorting order of the list. Please note, this field must be included in the email notification.
Around Line 51(search for ‘Script Step B’): baseQuery variable which can be set to an encoded query to determine which records will be returned on the email notification. This can be found by right-clicking filter breadcrumbs of a ServiceNow list view, or by clicking Preview Query on the pre-filter step of summary set-up.
Around Line 55(search for ‘Script Step C’): Sets the table to be queried
Around Line 66(search for ‘Script Step D’): The system property containing the sys_id of the portal connection ID (This will be created in Step 5 but you can name it now, just be aware that the property will be prefixed with the VividCharts app scope, x_vivid_vc_core). In this example, it is “x_vivid_vc_core.incident_example_portal_id”
Around Line 87(search for ‘Script Step E’): The text to be displayed with the link to the view. In this case, we are pulling the Incident number - “prjlinks.getDisplayValue("number")”
Around Line 91(search for ‘Script Step F’): Determines which fields are displayed in the email. The object key (The word in quotes, ex “Number”) is the Title used for the table column. The value (the stuff after the : to the right of the key), determines which field we will display in the columns. Generally we will use getValue from the Glide Record results but this can be manipulated to show any string.
Click Submit (or Save if you have previously submitted and are making edits.) Keep this browser tab open as it will be useful reference in the following steps.
Step 5 - Create the system property for the portal connection ID
Navigate to the Portal Connection table by typing “x_vivid_vc_core_view_portal_connection.LIST” in the filter navigator.
Find the record for the Summary you would like to use for the click through on the email notification. (It’s helpful to use the created date and the view used for the template to find the correct record.)
Right click on the appropriate record and choose copy sys_id and save it.
Go to System Properties by typing “sys_properties.LIST” in the filter navigator
Make sure you are still in the VividCharts scope and click new.
Referencing the name from the system property used in the Step 4, populate the Suffix field with the property name.
This is everything AFTER the dot. Notice the Name field will auto populate with the app scope-dot-suffix as the name.
Add a description.
Paste the sys_id copied from the portal connection table in the value field
Click submit.
To Test
Head back to the scheduled job created in Step 2.
Click execute now.
Type “Emails” in the filter navigator and click on Emails under the System Logs module.
Filter the list by subject line and created on date to find the Email(s) you just generated.
Right clicking on the email record will give you the option to Preview Email. Doing so should give you the final result of the notification.
Mail Script
(function runMailScript( /* GlideRecord */ current, /* TemplatePrinter */ template,
/* Optional EmailOutbound */
email, /* Optional GlideRecord */ email_action,
/* Optional GlideRecord */
event) {
//function to create an html table from a JSON object
function json2table(json, classes) {
// Everything goes in here
var cols = Object.keys(json[0]);
var headerRow = '';
var bodyRows = '';
var row = '';
classes = classes || '';
function capitalizeFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
cols.map(function(col) {
headerRow += '<th>' + capitalizeFirstLetter(col) + '</th>';
});
json.map(function(row) {
bodyRows += '<tr>';
cols.map(function(colName) {
bodyRows += '<td>' + row[colName] + '</td>';
});
bodyRows += '</tr>';
});
return '<style>table, th, td {border: 1px solid black;border-collapse: collapse; font-family: Arial;}th, td {padding: 5px;}div {margin-left: auto; margin-right: auto;}table {width:100%;}th {background-color: #394951; color: white;}</style><div><table class=' + classes + '><thead>' + headerRow + '</thead><tbody>' + bodyRows + '</tbody></table></div>';
}
//sort the JSON object by number
////////Script Step A
function compare(a, b) {
if (a.Number < b.Number) {
return -1;
}
if (a.Number > b.Number) {
return 1;
}
return 0;
}
var projectDetails = [];
//Base query to filter which Incident records will be shown in the notification and should match the Pre-filter of the summary used to generate the views we will be linking to
////////Script Step B
////////Base query to filter which records will be shown
var baseQuery = 'major_incident_state=accepted^promoted_onRELATIVEGT@dayofweek@ago@90^promoted_onRELATIVELT@dayofweek@ago@7';
var instance = gs.getProperty('instance_name');
////////Script Step C
////////Sets which table to be queried
var prjlinks = new GlideRecord('incident');
prjlinks.addEncodedQuery(baseQuery);
prjlinks.query();
while (prjlinks.next()) {
var incidentID = prjlinks.getValue('sys_id');
var link = '';
var linkBase = "https://" + instance + ".service-now.com/x/vivid/vividcharts/app/params/page/viewer-page/id/";
//Find the view ID
////////Script Step D
var portalConnectionID = gs.getProperty('x_vivid_vc_core.incident_example_portal_id'); // This is the ID of the view portal connection found here 'x_vivid_vc_core_view_portal_connection'
var deckID = false;
var viewID = false;
var portalConnection = new GlideRecord("x_vivid_vc_core_view_portal_connection");
if (portalConnection.get(portalConnectionID)) {
deckID = portalConnection.portal.card_deck;
}
// Now we need to find the portal card
var portalCard = new GlideRecord("x_vivid_vc_core_portal_card");
portalCard.addQuery("id", incidentID);
portalCard.addQuery("card_deck", deckID);
portalCard.query();
while (portalCard.next()) {
if (portalCard.getValue("view") != false) {
viewID = portalCard.getValue("view");
//return viewID;
}
}
////////Sets the link text
////////Script Step E
link = '<a style="text-align: center; text-decoration: none;" href="' + linkBase + viewID + '">' + prjlinks.getDisplayValue("number") + '</a><br>';
////////Sets which fields are displayed as columns
////////Script Step F
projectDetails.push({
"Number": link || '-',
"Incident": prjlinks.getDisplayValue('short_description') || '-'
});
var projectPrint = '';
projectDetails.sort(compare);
projectPrint += '<br><h3 style="font-size: 16pt; font-family: arial, helvetica, sans-serif">Major Incidents</h3>' + json2table(projectDetails);
}
projectDetails.sort(compare);
template.print(projectPrint);
})(current, template, email, email_action, event);