Skip to main content
Version: 4.8.0

Email Notification Guide

Create ServiceNow Email Notifications (sysevent_email_action) to send automated emails based on database operations, custom events, or manual triggers. This guide covers trigger types, content formats, recipients, digest emails (batched notifications), templates, styles, scripts, access restrictions, and notification categories. Supported in SDK 4.3.0 or higher.

When to Use

  • Creating or modifying email notifications for database operations (insert/update)
  • Implementing event-based email notifications triggered by custom events
  • Setting up manual/on-demand notifications triggered by scripts
  • Configuring recipient lists based on users, groups, or record fields
  • Implementing calendar invitations (vCalendar notifications)
  • Implementing digest notifications or email templates (advanced features)

Instructions

  1. ONE Notification Rule: Create one notification per request unless explicitly asked for multiple. Use both onRecordInsert: true AND onRecordUpdate: true in one notification instead of separate notifications for create/insert and update.

  2. Simplicity First: Default to inline content with minimal HTML (<p> and <div> tags only). No templates, no digest, no styles unless explicitly requested.

  3. Template Order: If templates are requested, create the template first, then reference it. Never create inline content then retrofit.

  4. Field Validation: Only use actual table fields (e.g., ${field_name}). Email fields (replyTo, from) must be plain strings, never template variables.

  5. Business Rules Are Not Needed: For engine-based notifications (generationType: 'engine'), do not create business rules -- the notification engine handles triggering automatically.

  6. Instance URLs: Never Use \${URI_REF} for instance URLs link. Always use a mail script with gs.getProperty('glide.servlet.uri') to generate the instance URL dynamically.

Quick Decision Guide

How Many Notifications?

  • "send email on insert/update" -- ONE notification with both flags
  • "when created or updated" / "when created and updated" -- ONE notification with both flags
  • "multiple notifications" -- Ask: "How many and for what purposes?"

Should I Use Templates?

  • Default: NO (use inline content)
  • Only if explicitly requested: "template", "reusable content"

Should I Add Digest?

  • Default: NO
  • Only if explicitly requested: "daily digest", "group emails"

Should I Add Styles?

  • Default: NO (minimal HTML only)
  • Only if explicitly requested: "styled", "branded", "formatted"

Request Classification

  • SIMPLE ("send email when...") -- ONE notification, inline content, no advanced features
  • COMPREHENSIVE ("email system", "multiple notifications") -- Ask clarifying questions first
  • UNCLEAR -- Ask: "How many notifications?", "Need templates?", "Group into digests?"

Trigger Types

Engine-Based (generationType: 'engine')

Auto-triggers on insert/update. Do not create business rules to trigger the notification. Most common type for standard CRUD operations.

Choose when:

  • Notification should fire on record insert/update
  • No custom business logic needed
  • Standard CRUD operation monitoring

Event-Based (generationType: 'event')

Triggers on custom ServiceNow events. Requires the Event Registry to register the event first. Requires a Business Rule (or equivalent) to fire the event via gs.eventQueue().

Choose when:

  • Custom workflow events trigger notification
  • Complex business logic determines when to send
  • Event parameters contain recipient information

Important: Always query the instance for the event name (sysevent_register table) before using it in a notification. Do not assume an event name exists. If the event does not exist, create it first using the Event Registry (see registering-events-guide), then create a Business Rule to trigger it via gs.eventQueue().

Triggered (generationType: 'triggered')

Manual/script-triggered. Requires explicit triggering logic via scripts or business rules.

Choose when:

  • Manual/on-demand sending required
  • Script-controlled timing needed
  • Maximum control over when notification sends

Content Types

HTML ('text/html', default)

Rich emails with minimal HTML (<p>, <div>). Only create messageHtml field.

Plain Text ('text/plain')

Simple text-only for maximum compatibility or SMS. Only create messageText field.

Multipart ('multipart/mixed')

Both HTML and plain text versions for best compatibility. Must create both messageHtml AND messageText fields.

Variable Syntax

When writing TypeScript code, use a single backslash to escape variables in template literals:

// CORRECT - Single backslash in TypeScript code
messageHtml: `<p>Hello \${assigned_to.name}</p><p>Incident \${number}</p>`;

// WRONG - Double backslash
messageHtml: `<p>Hello \\${assigned_to.name}</p>`;

// WRONG - No backslash (JavaScript interpolates it)
messageHtml: `<p>Hello ${assigned_to.name}</p>`;

In TypeScript template literals (backticks), write \${field_name} with one backslash. This escapes the dollar sign so JavaScript does not try to interpolate it, producing the runtime string ${field_name} which ServiceNow then substitutes.

Recipients

Field Recipients (recipientFields): Dynamic recipients from record fields (e.g., assigned_to, caller). Most common and flexible pattern.

Group Recipients (recipientGroups): Array of group sys_ids for teams/departments. Preferred over individual users for scalability.

User Recipients (recipientUsers): Array of user sys_ids for fixed lists of specific individuals.

Special Recipients:

  • sendToCreator: true -- Send to record creator
  • eventParm1WithRecipient / eventParm2WithRecipient -- Event-based only
  • excludeDelegates: true -- Exclude out-of-office delegates
  • isSubscribableByAllUsers: true -- Allow user subscriptions

API Reference

For the full property reference (EmailNotification, trigger conditions, email content, digest), see the emailnotification-api topic.

Supporting Record Types

These are created using the Record API, not dedicated Fluent constructors.

Email Template (sysevent_email_template)

FieldTypeRequiredDescription
nameStringYesTemplate name.
subjectStringNoEmail subject (max 100).
message_htmlHTMLScriptNoHTML message (max 4000).
message_textEmailScriptNoPlain text message (max 4000).
messageEmailScriptNoMessage content, legacy field (max 4000).
sms_alternateEmailScriptNoSMS alternate message (max 8000).
collectionTableNameNoTarget table. Default: 'incident'.
sys_versionStringNoVersion. Default: '2'.
email_layoutReferenceNoReference to sys_email_layout (overall structure: header, footer, container).
message_listListNoPush messages, reference to sys_push_notif_msg.

On the template record use the snake_case field names (message_html, message_text), not the camelCase messageHtml/messageText names used in emailContent.

Email Layouts: Layouts define overall structure (header, footer, container) while templates define content. Use layouts only for consistent branding across multiple notifications.

Important: Always query the instance for existing email templates before creating new ones. Only create a new template if none of the existing templates satisfy your requirement or it is specifically asked to create one. Reusing existing templates promotes consistency and reduces maintenance overhead.

Email Style (sysevent_email_style)

FieldTypeRequiredDescription
nameStringYesStyle name.
styleHTMLNoCSS/HTML style content (max 65000).

Email Client Compatibility: Most clients support colors, fonts, spacing, borders, and text-align. Limited support for flexbox, grid, and pseudo-classes. Use inline styles for critical styling and tables for layout.

Email Script (sys_script_email)

FieldTypeRequiredDescription
nameStringYesScript name (max 100, unique).
scriptStringNoScript contents (max 4000).
new_lines_to_htmlBooleanNoConvert newlines to HTML. Default: false.

The script must maintain the structure (function runMailScript(current, template, email, email_action, event) {...})(current, template, email, email_action, event); and use template.print() to output content. Available variables: current (the target record), template (TemplatePrinter), and the optional email, email_action, and event.

To run a mail script, create the sys_script_email record and reference it by name inline in the message content using \${mail_script:Script Name}. See the Notification with Email Script example.

Email Access Restriction (email_access_restriction)

FieldTypeRequiredDescription
notificationReference, EmailNotificationYesReference to sysevent_email_action.
conditionsConditionsYesAccess conditions (max 8000).
descriptionStringNoDescription (max 1000).

Important: Only one restriction per notification. Query first to check if a restriction already exists before creating. Combine multiple conditions using ^ (AND) or ^OR (OR). Do not use Now.ID for the notification field -- use notificationVariable.$id or a queried sys_id.

Condition Format: Conditions must match the notification's table fields using format field_name=value^EQ or field_name!=value. Example: priority=1^ORpriority=2^state!=6^EQ for P1/P2 incidents that aren't resolved.

Behavior: When access is denied, recipients receive the email but content is replaced with a generic message. Subject lines remain visible.

Email Digest Interval (sys_email_digest_interval)

FieldTypeRequiredDescription
nameTranslatedTextYesInterval name.
intervalGlideDurationYesDuration (max 40) in format YYYY-MM-DD HH:MM:SS.

Common intervals: Hourly 1970-01-01 01:00:00, Daily 1970-01-02 00:00:00, Weekly 1970-01-08 00:00:00. Range: one hour to one week.

Choosing an Interval: Use hourly for high-volume operational monitoring, daily for moderate-volume end-of-day summaries, weekly for low-volume status reports.

Important: Always query the instance for existing digest intervals before creating new ones. Only create a new interval if none of the existing intervals satisfy your requirement. Reusing existing intervals helps maintain consistency across notifications.

Notification Category (sys_notification_category)

FieldTypeRequiredDescription
nameTranslatedTextYesCategory name (max 32, unique).
short_descriptionStringNoShort description (max 1000).

Default category sys_id: c97d83137f4432005f58108c3ffa917a.

Organization Patterns: Organize by application (Incident Management, Change Management), by priority (Critical Alerts, Standard Updates), or by event type (Assignments, Approvals, Status Changes).

GUID Validation

All reference fields must contain valid 32-character hexadecimal sys_ids:

  • category -- sys_notification_category
  • emailContent.template -- sysevent_email_template
  • emailContent.style -- sysevent_email_style
  • recipientDetails.recipientUsers -- sys_user
  • recipientDetails.recipientGroups -- sys_user_group
  • digest.defaultInterval -- sys_email_digest_interval

Common Mistakes to Avoid

  • Do not use incorrect $id syntax -- always use $id: Now.ID["value"]
  • Do not use double backslash in TypeScript template literals
  • Do not hallucinate fields -- only use actual table fields in message content
  • Do not assume or auto-populate replyTo and from fields
  • Do not create business rules for engine-based notifications
  • Do not create templates, digest, or styles unless explicitly requested
  • Do not use \${URI_REF} for record links -- use a mail script with gs.getProperty('glide.servlet.uri') to generate the URL dynamically
  • Always include import "@servicenow/sdk/global" at the top of your code

Examples

Simple Insert/Update Notification

import { EmailNotification } from "@servicenow/sdk/core";

EmailNotification({
$id: Now.ID["incident-update-notification"],
table: "incident",
name: "Incident Notification",
triggerConditions: {
generationType: "engine",
onRecordUpdate: true,
onRecordInsert: true
},
recipientDetails: {
recipientFields: ["assigned_to"]
},
emailContent: {
subject: "Incident \${number} Update",
messageHtml: `<p>Hello \${assigned_to.name}</p><p>Incident \${number} has been updated.</p><p>Priority: \${priority}</p>`
}
});

Include a clickable link to the record by dynamically generating the instance URL using a mail script.

import { EmailNotification, Record } from "@servicenow/sdk/core";

// Create email script to generate the record link dynamically
Record({
$id: Now.ID["generate_record_link_script"],
table: "sys_script_email",
data: {
name: "Generate Record Link",
new_lines_to_html: false,
script: `(function runMailScript(/* GlideRecord */ current, /* TemplatePrinter */ template,
/* Optional EmailOutbound */ email, /* Optional GlideRecord */ email_action,
/* Optional GlideRecord */ event) {
var instanceUrl = gs.getProperty('glide.servlet.uri');
var recordUrl = instanceUrl + '/' + current.getTableName() + '.do?sys_id=' + current.sys_id;
template.print(recordUrl);
})(current, template, email, email_action, event);`
}
});

EmailNotification({
$id: Now.ID["incident-with-link"],
table: "incident",
name: "Incident Notification with Link",
triggerConditions: {
generationType: "engine",
onRecordUpdate: true,
onRecordInsert: true
},
recipientDetails: {
recipientFields: ["assigned_to"]
},
emailContent: {
subject: "Incident \${number} Update",
messageHtml: `<p>Hello \${assigned_to.name},</p>
<p>Incident <strong>\${number}</strong> has been updated.</p>
<p><strong>Priority:</strong> \${priority}</p>
<p><strong>Short Description:</strong> \${short_description}</p>
<p>
<a href="\${mail_script:Generate Record Link}"
style="display: inline-block; padding: 10px 20px; background-color: #0066cc; color: white; text-decoration: none; border-radius: 4px;">
View Incident
</a>
</p>`
}
});

Dynamic URL Generation: The mail script uses gs.getProperty('glide.servlet.uri') to get the instance URL at runtime, then constructs the full record URL: <instance-url>/<table>.do?sys_id=<sys_id>. This ensures the link works across different instances (dev, test, prod) without hardcoding.

Notification with Template

import { EmailNotification, Record } from "@servicenow/sdk/core";

const incidentTemplate = Record({
$id: Now.ID["incident_update_template"],
table: "sysevent_email_template",
data: {
name: "Incident Update Template",
subject: "Incident \${number} has been updated",
message_html: `<h1>Incident Update</h1>
<p>Incident \${number} has been updated:</p>
<ul>
<li>State: \${state}</li>
<li>Priority: \${priority}</li>
<li>Assigned To: \${assigned_to}</li>
</ul>`,
collection: "incident",
sys_version: "2"
}
});

EmailNotification({
$id: Now.ID["incident-with-template"],
table: "incident",
name: "Incident Notification With Template",
active: true,
triggerConditions: {
generationType: "engine",
onRecordUpdate: true
},
recipientDetails: {
recipientFields: ["assigned_to"]
},
emailContent: {
template: incidentTemplate
}
});

Digest Notification

Digest batches multiple notifications into fewer emails. type controls how:

  • 'multiple' (Multiple Digest) -- Sends separate emails per record, but batched by interval. Each record becomes a separate entry rendered with emailContent.messageHtml and joined by digest.separatorHtml. Use for record-specific tracking where individual emails per record are needed.
  • 'single' (Single Digest) -- Sends one consolidated email per interval containing all records. Built from digest.html (or digest.template); the per-record emailContent.messageHtml is ignored. Use for high-volume notifications where maximum email reduction is desired.

Digest has built-in scheduling -- do not create business rules or schedulers to drive it. Digest is not available for vcalendar notifications.

import { EmailNotification } from "@servicenow/sdk/core";

EmailNotification({
$id: Now.ID["daily-incident-digest"],
table: "incident",
name: "Daily Incident Digest",
active: true,
triggerConditions: {
generationType: "engine",
onRecordInsert: true
},
recipientDetails: {
recipientFields: ["assignment_group"]
},
emailContent: {
subject: "Incident \${number} Created",
messageHtml: `<div style="border-bottom: 1px solid #ddd; padding: 10px;">
<h4>\${number}: \${short_description}</h4>
<p><strong>Priority:</strong> \${priority} | <strong>State:</strong> \${state}</p>
</div>`
},
digest: {
allow: true,
type: "multiple",
defaultInterval: "daily_digest_sys_id",
subject: "Daily New Incidents - \${digest_count} incidents",
html: "<h2>New Incidents (\${digest_count} total)</h2>",
separatorHtml: '<hr style="margin: 15px 0;">'
}
});

Event-Based Notification

import { EmailNotification } from "@servicenow/sdk/core";

EmailNotification({
$id: Now.ID["contract-expiring-notification"],
table: "sn_contract_e_2_contract",
name: "Contract Expiring - Account Owner Notification",
active: true,
triggerConditions: {
generationType: "event",
eventName: "sn_contract_e_2.contract.expiring"
},
recipientDetails: {
eventParm1WithRecipient: true
},
emailContent: {
subject: `Contract Expiring Soon: \${name}`,
messageHtml: `<p>Dear \${account_owner.name},</p>
<p>The following contract is approaching its expiration date:</p>`
}
});

Plain Text Notification

import { EmailNotification } from "@servicenow/sdk/core";

EmailNotification({
$id: Now.ID["system-alert-plain-text"],
table: "incident",
name: "System Alert Plain Text",
triggerConditions: {
generationType: "engine",
onRecordInsert: true,
condition: "priority=1^EQ"
},
recipientDetails: {
recipientFields: ["assigned_to"]
},
emailContent: {
contentType: "text/plain",
subject: "ALERT: Incident \${number}",
messageText: `Hello \${assigned_to.name},\n\nIncident \${number} requires attention.\nPriority: \${priority}\nDescription: \${short_description}`
}
});

VCalendar Meeting Invitation

import { EmailNotification } from "@servicenow/sdk/core";

EmailNotification({
$id: Now.ID["incident-review-meeting"],
table: "incident",
name: "Incident Review Meeting",
notificationType: "vcalendar",
triggerConditions: {
generationType: "event",
eventName: "incident.severity.1",
condition: "active=true^EQ"
},
recipientDetails: {
recipientFields: ["assignment_group", "assigned_to"]
},
emailContent: {
subject: "Incident \${number} Review Meeting",
messageHtml: `<div>You are invited to review incident \${number}</div>`
}
});

Triggered (Manual) Notification

Manually invoked notifications -- they are not fired automatically. You must trigger them from a script or business rule.

import { EmailNotification } from "@servicenow/sdk/core";

EmailNotification({
$id: Now.ID["manual-incident-notification"],
table: "incident",
name: "Manual Incident Notification",
triggerConditions: {
generationType: "triggered"
},
recipientDetails: {
recipientFields: ["assigned_to"],
sendToCreator: true
},
emailContent: {
subject: "Manual Notification - Incident \${number}",
messageHtml: `<p>This is a manually triggered notification.</p><p>Incident: \${number}</p><p>Status: \${state}</p>`
}
});

Multipart Notification (HTML + Text)

Set contentType: 'multipart/mixed' and provide BOTH messageHtml and messageText. Clients display HTML when supported and fall back to text otherwise.

import { EmailNotification } from "@servicenow/sdk/core";

EmailNotification({
$id: Now.ID["multipart-incident-notification"],
table: "incident",
name: "Multipart Incident Notification",
triggerConditions: {
generationType: "engine",
onRecordUpdate: true
},
recipientDetails: {
recipientFields: ["assigned_to"]
},
emailContent: {
contentType: "multipart/mixed",
subject: "Incident \${number} Update",
messageHtml: `<p>Hello \${assigned_to.name}</p><p>Incident \${number} has been updated.</p><p><strong>Priority:</strong> \${priority}</p>`,
messageText: `Hello \${assigned_to.name},\n\nIncident \${number} has been updated.\nPriority: \${priority}\n\nThank you.`
}
});

Notification with Email Script

Create the sys_script_email record with Record, then reference it inline in the message content with \${mail_script:Script Name}. There is no emailScript field on emailContent.

import { EmailNotification, Record } from "@servicenow/sdk/core";

Record({
$id: Now.ID["format_incident_details_script"],
table: "sys_script_email",
data: {
name: "Format Incident Details",
new_lines_to_html: false,
script: `(function runMailScript(/* GlideRecord */ current, /* TemplatePrinter */ template,
/* Optional EmailOutbound */ email, /* Optional GlideRecord */ email_action,
/* Optional GlideRecord */ event) {
template.print("Incident: " + current.number);
template.print("\\nPriority: " + current.getDisplayValue('priority'));
template.print("\\nStatus: " + current.getDisplayValue('state'));
})(current, template, email, email_action, event);`
}
});

EmailNotification({
$id: Now.ID["incident-with-script"],
table: "incident",
name: "Incident With Script",
triggerConditions: {
generationType: "engine",
onRecordUpdate: true
},
recipientDetails: {
recipientFields: ["assigned_to"]
},
emailContent: {
subject: "Incident \${number} Update",
messageHtml: `<p>Hello \${assigned_to.name}</p><p>Incident details:</p>\${mail_script:Format Incident Details}`
}
});

Styled Notification

Create a sysevent_email_style record and pass it to emailContent.style. Prefer inline styles in messageHtml for maximum email-client compatibility.

import { EmailNotification, Record } from "@servicenow/sdk/core";

const corporateStyle = Record({
$id: Now.ID["corporate_email_style"],
table: "sysevent_email_style",
data: {
name: "Corporate Email Style",
style: `.priority-high { color: #d32f2f; font-weight: bold; }`
}
});

EmailNotification({
$id: Now.ID["styled-incident-notification"],
table: "incident",
name: "Styled Incident Notification",
triggerConditions: {
generationType: "engine",
onRecordUpdate: true,
condition: "priority=1^EQ"
},
recipientDetails: {
recipientFields: ["assigned_to"]
},
emailContent: {
subject: "URGENT: Incident \${number}",
messageHtml: `<p><span class="priority-high">Priority: \${priority}</span></p><p>Incident: \${number}</p><p>\${short_description}</p>`,
style: corporateStyle
}
});

Advanced Email Options

Real emailContent fields for delivery control. from and replyTo must be plain static email strings (never template variables) -- only set them when explicitly provided.

import { EmailNotification } from "@servicenow/sdk/core";

EmailNotification({
$id: Now.ID["critical-incident-alert"],
table: "incident",
name: "Critical Incident Alert",
mandatory: true,
triggerConditions: {
generationType: "engine",
onRecordInsert: true,
onRecordUpdate: true,
condition: "priority=1^EQ"
},
recipientDetails: {
recipientFields: ["assigned_to", "caller_id"],
recipientGroups: ["incident_managers_group_sys_id"]
},
emailContent: {
subject: "CRITICAL: Incident \${number}",
messageHtml: `<p><strong>Incident:</strong> \${number}</p><p><strong>Description:</strong> \${short_description}</p>`,
importance: "high",
includeAttachments: true,
omitWatermark: true,
forceDelivery: true,
smsAlternate: "CRITICAL: Incident \${number} - \${short_description}",
from: "incident-management@company.com",
replyTo: "itsupport@company.com"
}
});

Notification with Access Restriction

Restrict which records' content recipients can see. Create an email_access_restriction record that references the notification. Use the notification variable's $id for the notification field -- not a fresh Now.ID. Only one restriction is allowed per notification; combine conditions with ^ (AND) or ^OR (OR).

import { EmailNotification, Record } from "@servicenow/sdk/core";

const restrictedNotification = EmailNotification({
$id: Now.ID["restricted-incident-notification"],
table: "incident",
name: "Restricted Incident Notification",
triggerConditions: {
generationType: "engine",
onRecordUpdate: true
},
recipientDetails: {
recipientFields: ["assigned_to"]
},
emailContent: {
subject: "Incident \${number} Update",
messageHtml: `<p>Incident \${number} has been updated.</p><p>Priority: \${priority}</p>`
}
});

Record({
$id: Now.ID["incident_access_restriction"],
table: "email_access_restriction",
data: {
notification: restrictedNotification,
conditions: "priority=1^ORpriority=2^state!=6^state!=7^EQ",
description: "Only show content for P1/P2 incidents that are not resolved or closed"
}
});

Notification with Category

Create categories to organize notifications by type or department. Query for existing categories first before creating new ones.

import { EmailNotification, Record } from "@servicenow/sdk/core";

const securityCategory = Record({
$id: Now.ID["security_notifications_category"],
table: "sys_notification_category",
data: {
name: "Security Notifications",
short_description: "All security-related incident notifications"
}
});

EmailNotification({
$id: Now.ID["security-incident-notification"],
table: "incident",
name: "Security Incident Notification",
category: securityCategory,
triggerConditions: {
generationType: "engine",
onRecordInsert: true,
condition: "category.name=Security^EQ"
},
recipientDetails: {
recipientFields: ["assignment_group"],
recipientGroups: ["security_team_sys_id"]
},
emailContent: {
subject: "Security Incident \${number} Created",
messageHtml: `<p>A new security incident has been created.</p><p>Incident: \${number}</p><p>Description: \${short_description}</p>`
}
});

Complete Notification with All Advanced Features

Comprehensive example combining category, style, script, and access restriction. Only create all components when explicitly requested for complex requirements.

import { EmailNotification, Record } from "@servicenow/sdk/core";

// 1. Create category
const criticalCategory = Record({
$id: Now.ID["critical_incidents_category"],
table: "sys_notification_category",
data: {
name: "Critical Incidents",
short_description: "Critical priority incident notifications"
}
});

// 2. Create email style
const criticalStyle = Record({
$id: Now.ID["critical_incident_style"],
table: "sysevent_email_style",
data: {
name: "Critical Incident Style",
style: `.critical-header { background: #dc3545; color: white; padding: 20px; }
.urgent-badge { background: #dc3545; color: white; padding: 8px 16px; border-radius: 20px; font-weight: bold; }`
}
});

// 3. Create email script
const criticalScript = Record({
$id: Now.ID["critical_incident_script"],
table: "sys_script_email",
data: {
name: "Critical Incident Details Script",
new_lines_to_html: true,
script: `(function runMailScript(/* GlideRecord */ current, /* TemplatePrinter */ template,
/* Optional EmailOutbound */ email, /* Optional GlideRecord */ email_action,
/* Optional GlideRecord */ event) {
var created = new GlideDateTime(current.sys_created_on);
var now = new GlideDateTime();
var duration = GlideDateTime.subtract(created, now);
template.print("Time since creation: " + duration.getDisplayValue());
template.print("\\nAssigned to: " + current.getDisplayValue('assigned_to'));
if (current.escalation > 0) {
template.print("\\n⚠️ ESCALATED " + current.escalation + " times");
}
})(current, template, email, email_action, event);`
}
});

// 4. Create notification
const criticalNotification = EmailNotification({
$id: Now.ID["critical_incident_notification"],
table: "incident",
name: "Critical Incident Notification",
category: criticalCategory,
mandatory: true,
triggerConditions: {
generationType: "engine",
onRecordInsert: true,
onRecordUpdate: true,
condition: "priority=1^EQ"
},
recipientDetails: {
recipientFields: ["assigned_to", "caller_id"],
recipientGroups: ["incident_managers_sys_id"]
},
emailContent: {
subject: "🚨 CRITICAL: Incident \${number}",
messageHtml: `<div class="critical-header">
<h1>🚨 CRITICAL INCIDENT ALERT</h1>
<span class="urgent-badge">IMMEDIATE ACTION REQUIRED</span>
</div>
<p><strong>Incident:</strong> \${number}</p>
<p><strong>Priority:</strong> \${priority}</p>
<p><strong>Description:</strong> \${short_description}</p>
<p><strong>Additional Details:</strong></p>
\${mail_script:Critical Incident Details Script}`,
style: criticalStyle,
importance: "high",
includeAttachments: true,
forceDelivery: true
}
});
  • emailnotification-api — For complete API reference of all EmailNotification properties and types
  • business-rule-guide — For understanding when to use business rules vs notification engine triggers
  • registering-events-guide — For creating custom events that can trigger event-based notifications
  • table-guide — For understanding table structures when configuring notification triggers
  • script-include-guide — For reusable logic in notification scripts (advanced conditions or content generation)