Interested in a ServiceNow event built for developers? Registration for now[dev]26 is officially open!

Email script

tushar_ghadage
Tera Contributor

Hi all , 

I have to sent notification to a group when state on ritm is close complete or cancelled 

with the all the sla defination attached to the ritm as given below 

with has breached , start time , stop time , business left time , business elapsed time , pause duration fields in the notification..

 Screenshot (361).png

I don't have any experience with email script can any please guide here how shall go ahead ??
 
thankss 
3 REPLIES 3

CFrandsen
Kilo Sage

Hi @tushar_ghadage  
I would personally prefer doing this within FlowDesigner - but due to limitations, you can't directly initiate flows from create or updates on sc_req_item table. (In case you wanted to do this, you could trigger the flow from a seperate BR) So let's stick to the requested approach for a good old Email Script.

1) Create the Notification
Table: Requested Item [sc_req_item]
When to send: Record updated
Condition:
State changes is true
State is one of Closed Complete, Closed Incomplete, Closed Skipped

Who will receive: your target Group (add a specific group, or use a Scripted Recipient if you need logic).
What it will contain: put ${mail_script:ritm_sla_table} where you want the SLA table.

2) Let's create the Notification Email Script
Go to System Policy → Email → Notification Email Scripts and create ritm_sla_table with this script:

// Name: ritm_sla_table
// Applies to: Global (or your app scope)
// Usage: ${mail_script:ritm_sla_table}

(function() {
    // Guard: ensure we’re on a RITM
    if (!current || current.getTableName() !== 'sc_req_item') {
        template.print('<p><em>No RITM context available.</em></p>');
        return;
    }

    // Query all SLAs linked to this RITM
    var slaGR = new GlideRecord('task_sla');
    slaGR.addQuery('task', current.sys_id);
    slaGR.orderBy('start_time');
    slaGR.query();

    if (!slaGR.hasNext()) {
        template.print('<p><em>No SLAs found for this item.</em></p>');
        return;
    }

    // Helper to format durations safely
    function fmtDur(val) {
        if (!val) return '';
        try { return (new GlideDuration(val)).getDisplayValue(); } catch (e) { return val; }
    }

    // Build a simple HTML table
    var html = [];
    html.push('<table style="border-collapse:collapse;width:100%;">');
    html.push('<thead>');
    html.push('<tr>');
    html.push('<th style="text-align:left;border-bottom:1px solid #ddd;padding:6px;">SLA</th>');
    html.push('<th style="text-align:left;border-bottom:1px solid #ddd;padding:6px;">Has Breached</th>');
    html.push('<th style="text-align:left;border-bottom:1px solid #ddd;padding:6px;">Start Time</th>');
    html.push('<th style="text-align:left;border-bottom:1px solid #ddd;padding:6px;">Stop Time</th>');
    html.push('<th style="text-align:left;border-bottom:1px solid #ddd;padding:6px;">Business Time Left</th>');
    html.push('<th style="text-align:left;border-bottom:1px solid #ddd;padding:6px;">Business Elapsed</th>');
    html.push('<th style="text-align:left;border-bottom:1px solid #ddd;padding:6px;">Pause Duration</th>');
    html.push('</tr>');
    html.push('</thead><tbody>');

    while (slaGR.next()) {
        html.push('<tr>');
        html.push('<td style="padding:6px;border-bottom:1px solid #f0f0f0;">' +
                  slaGR.sla.getDisplayValue() + '</td>');
        html.push('<td style="padding:6px;border-bottom:1px solid #f0f0f0;">' +
                  (slaGR.has_breached ? 'Yes' : 'No') + '</td>');
        html.push('<td style="padding:6px;border-bottom:1px solid #f0f0f0;">' +
                  slaGR.getDisplayValue('start_time') + '</td>');
        html.push('<td style="padding:6px;border-bottom:1px solid #f0f0f0;">' +
                  slaGR.getDisplayValue('end_time') + '</td>'); // "end_time" is stop time
        html.push('<td style="padding:6px;border-bottom:1px solid #f0f0f0;">' +
                  fmtDur(slaGR.getValue('business_time_left')) + '</td>');
        html.push('<td style="padding:6px;border-bottom:1px solid #f0f0f0;">' +
                  fmtDur(slaGR.getValue('business_elapsed_time')) + '</td>');
        html.push('<td style="padding:6px;border-bottom:1px solid #f0f0f0;">' +
                  fmtDur(slaGR.getValue('pause_duration')) + '</td>');
        html.push('</tr>');
    }

    html.push('</tbody></table>');
    template.print(html.join(''));
})();


I've quickly tested - and received this 😉 

CRFN1_0-1755021540307.png


So I guess it would work for you as well.

 

 



 If this pointed you in the right direction, hit Helpful to spread the good vibes.
✅ If it cracked the case for you, mark it Correct so the next person doesn’t have to reinvent the wheel.

Bhimashankar H
Mega Sage

Hi @tushar_ghadage ,

 

So need to first create the email script, that will form like table structure format and use that in email notification like

 

${mail_script:nameOfYourMailScript}

ensure the notification is triggered when sc_req_item.state is Closed Complete or Closed Cancelled and is sent to the desired group.

 

below is mail script you can try

 

(function runMailScript(/* GlideRecord */ current, /* TemplatePrinter */ template,
          /* Optional EmailOutbound */ email, /* Optional GlideRecord */ email_action,
          /* Optional GlideRecord */ event) {

 function disp(gr, field) {
    if (!gr || !field) return '';
    try {
      return gr.getDisplayValue(field) || '';
    } catch (e) {
      return '';
    }
  }

  function boolToYesNo(v) {
    // task_sla.has_breached is a boolean; display Yes/No
    return ('' + v) === 'true' ? 'Yes' : (('' + v) === 'false' ? 'No' : (v ? 'Yes' : 'No'));
  }

  // Query task_sla where task is this RITM
  var slaGR = new GlideRecord('task_sla');
  slaGR.addQuery('task', current.sys_id);
  slaGR.orderBy('sla.name'); // stable order
  slaGR.query();

  // If no SLAs found, render a short note
  if (!slaGR.hasNext()) {
    template.print('<p>No SLAs are attached to this Requested Item.</p>');
    return;
  }

  // Table header
  template.print(
    '<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;">' +
      '<thead>' +
        '<tr style="background:#f2f2f2;">' +
          '<th align="left">SLA Definition</th>' +
          '<th align="left">Has Breached</th>' +
          '<th align="left">Start Time</th>' +
          '<th align="left">Stop Time</th>' +
          '<th align="left">Business Time Left</th>' +
          '<th align="left">Business Elapsed</th>' +
          '<th align="left">Pause Duration</th>' +
          '<th align="left">Stage</th>' +
        '</tr>' +
      '</thead><tbody>'
  );

  while (slaGR.next()) {
    // Fields: Add your fields
    // - sla.name (definition)
    // - has_breached (boolean)
    // - start_time, end_time (a.k.a. stop time)
    // - business_time_left, business_elapsed_time (durations)
    // - pause_duration (duration)
    // - stage (in_progress, paused, completed, cancelled, breached)
    var slaName = disp(slaGR, 'sla');
    var breached = boolToYesNo(slaGR.has_breached);
    var startTime = disp(slaGR, 'start_time');
    var stopTime = disp(slaGR, 'end_time'); // stop time stored in end_time
    var bizLeft = disp(slaGR, 'business_time_left');
    var bizElapsed = disp(slaGR, 'business_elapsed_time');
    var pauseDur = disp(slaGR, 'pause_duration');
    var stage = disp(slaGR, 'stage');

    template.print(
      '<tr>' +
        '<td>' + gs.escapeHTML(slaName) + '</td>' +
        '<td>' + gs.escapeHTML(breached) + '</td>' +
        '<td>' + gs.escapeHTML(startTime) + '</td>' +
        '<td>' + gs.escapeHTML(stopTime) + '</td>' +
        '<td>' + gs.escapeHTML(bizLeft) + '</td>' +
        '<td>' + gs.escapeHTML(bizElapsed) + '</td>' +
        '<td>' + gs.escapeHTML(pauseDur) + '</td>' +
        '<td>' + gs.escapeHTML(stage) + '</td>' +
      '</tr>'
    );
  }

  template.print('</tbody></table>');

})(current, template, email, email_action, event);

 

Once done then, try sending notification and check the final mail. You may not able view this when 'preview notication'.

Thanks,
Bhimashankar H

 

-------------------------------------------------------------------------------------------------
If my response points you in the right directions, please consider marking it as 'Helpful' & 'Correct'. Thanks!

Rafael Batistot
Kilo Patron

Hi @tushar_ghadage,

This is the complete guide for your solicitation:

1 - Create an event

You define event names in the Event Registry.

  • Go to System Policy > Events > Event Registry.

  • Click New.

  • Fill in:

    • Name: a unique event name (e.g., custom.task.completed)

    • Table (optional): the table related to the event (e.g., task)

    • Save it.

2 - Create a notification 

  • Create a new notification triggered when:

    • Table: sc_req_item

    • When to send: Record updated

    • Condition: state is Closed Complete OR Cancelled.

  • In the Who will receive section, choose your target group.

  • In the What it will contain section, add:

    • The normal message body.

    • Under Advanced view, add the above mail script.

  • In the body, reference it like:

${mail_script:sla_details}


3 - Create the mail script

// Mail script for notification
(function() {
    var result = [];
    var slaGR = new GlideRecord('task_sla');
    slaGR.addQuery('task', current.sys_id);
    slaGR.query();

    while (slaGR.next()) {
        result.push(
            'SLA Name: ' + slaGR.sla.name + '\n' +
            'Has Breached: ' + slaGR.has_breached + '\n' +
            'Start Time: ' + slaGR.start_time.getDisplayValue() + '\n' +
            'Stop Time: ' + slaGR.end_time.getDisplayValue() + '\n' +
            'Business Time Left: ' + slaGR.business_time_left + '\n' +
            'Business Elapsed Time: ' + slaGR.business_elapsed_time + '\n' +
            'Pause Duration: ' + slaGR.pause_duration + '\n' +
            '-------------------------\n'
        );
    }

    template.print(result.join('\n'));
})();
​

 

If this response was helpful, please mark it as Helpful and, if applicable, as Correct.
This helps other users find accurate and useful information more easily