email-notifications

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Email Notifications for ServiceNow

ServiceNow邮件通知

ServiceNow notifications are triggered by events and send emails, SMS, or other alerts to users.
ServiceNow通知由事件触发,可向用户发送邮件、短信或其他告警信息。

Notification Components

通知组件

ComponentTablePurpose
Notificationsysevent_email_actionMain notification record
Email Templatesysevent_email_templateReusable email layouts
EventsyseventTriggers notifications
Event Registrationsysevent_registerDefines custom events
Email Scriptsys_script_emailDynamic content scripts
组件表名用途
Notificationsysevent_email_action主要通知记录
Email Templatesysevent_email_template可复用邮件布局
Eventsysevent触发通知
Event Registrationsysevent_register定义自定义事件
Email Scriptsys_script_email动态内容脚本

Creating Notifications

创建通知

Basic Notification Structure

基础通知结构

Notification: Incident Assigned
├── When to send
│   ├── Table: incident
│   ├── When: Record inserted or updated
│   └── Conditions: assigned_to changes AND is not empty
├── Who will receive
│   ├── Users: ${assigned_to}
│   └── Groups: (optional)
├── What it will contain
│   ├── Subject: Incident ${number} assigned to you
│   ├── Message: HTML body with ${field} references
│   └── Email Template: (optional)
└── Advanced
    ├── Weight: 0 (priority)
    └── Send to event creator: false
Notification: Incident Assigned
├── 发送时机
│   ├── 表:incident
│   ├── 触发条件:记录插入或更新
│   └── 筛选条件:assigned_to字段变更且不为空
├── 收件人
│   ├── 用户:${assigned_to}
│   └── 用户组:(可选)
├── 通知内容
│   ├── 主题:事件${number}已分配给您
│   ├── 消息:包含${field}引用的HTML正文
│   └── 邮件模板:(可选)
└── 高级设置
    ├── 权重:0(优先级)
    └── 是否发送给事件创建者:false

Notification Conditions

通知条件

javascript
// Simple field conditions
assigned_to CHANGES
priority = 1
state = 6  // Resolved

// Script condition (ES5 only!)
// Returns true to send, false to skip
(function() {
    // Only notify for VIP callers
    var caller = current.caller_id.getRefRecord();
    return caller.vip == true;
})()

// Advanced condition with multiple checks
(function() {
    // Don't notify on bulk updates
    if (current.sys_mod_count > 100) return false;

    // Only for production CIs
    var ci = current.cmdb_ci.getRefRecord();
    return ci.used_for == 'Production';
})()
javascript
// 简单字段条件
assigned_to CHANGES
priority = 1
state = 6  // 已解决

// 脚本条件(仅支持ES5!)
// 返回true则发送,false则跳过
(function() {
    // 仅通知VIP呼叫者
    var caller = current.caller_id.getRefRecord();
    return caller.vip == true;
})()

// 多条件高级判断
(function() {
    // 批量更新时不发送通知
    if (current.sys_mod_count > 100) return false;

    // 仅针对生产环境配置项
    var ci = current.cmdb_ci.getRefRecord();
    return ci.used_for == 'Production';
})()

Email Templates

邮件模板

Template Variables

模板变量

html
<!-- Field references -->
${number}                    <!-- Direct field value -->
${caller_id.name}            <!-- Dot-walked reference -->
${opened_at.display_value}   <!-- Display value -->

<!-- Special variables -->
${URI}                       <!-- Link to record -->
${URI_REF}                   <!-- Reference link -->
${mail_script:script_name}   <!-- Include email script -->

<!-- Conditional content -->
${mailto:assigned_to}        <!-- Mailto link -->
html
<!-- 字段引用 -->
${number}                    <!-- 直接字段值 -->
${caller_id.name}            <!-- 关联字段取值 -->
${opened_at.display_value}   <!-- 显示值 -->

<!-- 特殊变量 -->
${URI}                       <!-- 记录链接 -->
${URI_REF}                   <!-- 引用链接 -->
${mail_script:script_name}   <!-- 引入邮件脚本 -->

<!-- 条件内容 -->
${mailto:assigned_to}        <!-- 邮件链接 -->

Template Example

模板示例

html
<html>
<body style="font-family: Arial, sans-serif;">
  <h2>Incident ${number} - ${short_description}</h2>

  <table border="0" cellpadding="5">
    <tr>
      <td><strong>Priority:</strong></td>
      <td>${priority}</td>
    </tr>
    <tr>
      <td><strong>Caller:</strong></td>
      <td>${caller_id.name}</td>
    </tr>
    <tr>
      <td><strong>Assigned to:</strong></td>
      <td>${assigned_to.name}</td>
    </tr>
    <tr>
      <td><strong>Description:</strong></td>
      <td>${description}</td>
    </tr>
  </table>

  <p>
    <a href="${URI}">View Incident</a>
  </p>

  ${mail_script:incident_history}
</body>
</html>
html
<html>
<body style="font-family: Arial, sans-serif;">
  <h2>事件${number} - ${short_description}</h2>

  <table border="0" cellpadding="5">
    <tr>
      <td><strong>优先级:</strong></td>
      <td>${priority}</td>
    </tr>
    <tr>
      <td><strong>呼叫者:</strong></td>
      <td>${caller_id.name}</td>
    </tr>
    <tr>
      <td><strong>负责人:</strong></td>
      <td>${assigned_to.name}</td>
    </tr>
    <tr>
      <td><strong>描述:</strong></td>
      <td>${description}</td>
    </tr>
  </table>

  <p>
    <a href="${URI}">查看事件</a>
  </p>

  ${mail_script:incident_history}
</body>
</html>

Email Scripts

邮件脚本

Basic Email Script

基础邮件脚本

javascript
// Email Script: incident_history
// Table: incident
// Script (ES5 only!):

(function runMailScript(current, template, email, email_action, event) {

    // Build activity history
    var html = '<h3>Recent Activity</h3><ul>';

    var history = new GlideRecord('sys_journal_field');
    history.addQuery('element_id', current.sys_id);
    history.addQuery('name', 'incident');
    history.orderByDesc('sys_created_on');
    history.setLimit(5);
    history.query();

    while (history.next()) {
        html += '<li><strong>' + history.sys_created_on.getDisplayValue() + '</strong>: ';
        html += history.value.substring(0, 200) + '</li>';
    }
    html += '</ul>';

    template.print(html);

})(current, template, email, email_action, event);
javascript
// 邮件脚本:incident_history
// 表:incident
// 脚本(仅支持ES5!):

(function runMailScript(current, template, email, email_action, event) {

    // 构建活动历史
    var html = '<h3>近期活动</h3><ul>';

    var history = new GlideRecord('sys_journal_field');
    history.addQuery('element_id', current.sys_id);
    history.addQuery('name', 'incident');
    history.orderByDesc('sys_created_on');
    history.setLimit(5);
    history.query();

    while (history.next()) {
        html += '<li><strong>' + history.sys_created_on.getDisplayValue() + '</strong>: ';
        html += history.value.substring(0, 200) + '</li>';
    }
    html += '</ul>';

    template.print(html);

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

Email Script with Attachments

带附件的邮件脚本

javascript
// Add attachments from the record to the email
(function runMailScript(current, template, email, email_action, event) {

    var gr = new GlideRecord('sys_attachment');
    gr.addQuery('table_sys_id', current.sys_id);
    gr.addQuery('table_name', 'incident');
    gr.query();

    while (gr.next()) {
        email.addAttachment(gr);
    }

})(current, template, email, email_action, event);
javascript
// 将记录中的附件添加到邮件
(function runMailScript(current, template, email, email_action, event) {

    var gr = new GlideRecord('sys_attachment');
    gr.addQuery('table_sys_id', current.sys_id);
    gr.addQuery('table_name', 'incident');
    gr.query();

    while (gr.next()) {
        email.addAttachment(gr);
    }

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

Dynamic Recipients

动态收件人

javascript
// Email Script to add CC recipients dynamically
(function runMailScript(current, template, email, email_action, event) {

    // Add all group members as CC
    var group = current.assignment_group;
    if (!group.nil()) {
        var members = new GlideRecord('sys_user_grmember');
        members.addQuery('group', group);
        members.query();

        while (members.next()) {
            var user = members.user.getRefRecord();
            if (user.email) {
                email.addAddress('cc', user.email, user.name);
            }
        }
    }

})(current, template, email, email_action, event);
javascript
// 动态添加抄送人邮件脚本
(function runMailScript(current, template, email, email_action, event) {

    // 将所有组成员添加为抄送人
    var group = current.assignment_group;
    if (!group.nil()) {
        var members = new GlideRecord('sys_user_grmember');
        members.addQuery('group', group);
        members.query();

        while (members.next()) {
            var user = members.user.getRefRecord();
            if (user.email) {
                email.addAddress('cc', user.email, user.name);
            }
        }
    }

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

Custom Events

自定义事件

Registering a Custom Event

注册自定义事件

javascript
// Event Registration
// Name: x_myapp.incident.escalated
// Table: incident
// Description: Fired when incident is escalated to management
// Fired by: Business Rule

// In Business Rule (ES5 only!)
(function executeRule(current, previous) {

    // Check if escalation occurred
    if (current.escalation > previous.escalation) {
        // Fire custom event
        gs.eventQueue('x_myapp.incident.escalated', current,
            current.escalation.getDisplayValue(),  // parm1
            current.assigned_to.name               // parm2
        );
    }

})(current, previous);
javascript
// 事件注册
// 名称:x_myapp.incident.escalated
// 表:incident
// 描述:事件升级到管理层时触发
// 触发方式:业务规则

// 业务规则中(仅支持ES5!)
(function executeRule(current, previous) {

    // 检查是否发生升级
    if (current.escalation > previous.escalation) {
        // 触发自定义事件
        gs.eventQueue('x_myapp.incident.escalated', current,
            current.escalation.getDisplayValue(),  // 参数1
            current.assigned_to.name               // 参数2
        );
    }

})(current, previous);

Notification on Custom Event

基于自定义事件的通知

Notification: Escalation Alert
├── When to send
│   ├── Send when: Event is fired
│   └── Event name: x_myapp.incident.escalated
├── Who will receive
│   └── Users/Groups: Escalation Managers
└── What it will contain
    ├── Subject: Escalation: ${number} - ${event.parm1}
    └── Message: Incident escalated. Assigned to: ${event.parm2}
Notification: 升级告警
├── 发送时机
│   ├── 触发条件:事件触发时
│   └── 事件名称:x_myapp.incident.escalated
├── 收件人
│   └── 用户/用户组:升级管理人员
└── 通知内容
    ├── 主题:升级通知:${number} - ${event.parm1}
    └── 消息:事件已升级,负责人:${event.parm2}

Recipient Types

收件人类型

Who Will Receive

收件人范围

TypeDescriptionExample
UsersSpecific users${assigned_to}, ${caller_id}
GroupsUser groupsService Desk, CAB
Group ManagersGroup manager field${assignment_group.manager}
Event Parm 1/2From event parameters${event.parm1}
Additional RecipientsEmail addressesExternal emails
类型描述示例
Users指定用户${assigned_to}, ${caller_id}
Groups用户组Service Desk, CAB
Group Managers组管理员字段${assignment_group.manager}
Event Parm 1/2事件参数取值${event.parm1}
Additional Recipients外部邮箱地址外部联系人邮箱

Recipient Script

收件人脚本

javascript
// Recipient Script (ES5 only!)
// Returns comma-separated list of emails or sys_ids

(function getRecipients(current, event) {
    var recipients = [];

    // Add the caller
    if (!current.caller_id.nil()) {
        recipients.push(current.caller_id.email.toString());
    }

    // Add VIP's manager
    var caller = current.caller_id.getRefRecord();
    if (caller.vip == true && !caller.manager.nil()) {
        recipients.push(caller.manager.email.toString());
    }

    return recipients.join(',');

})(current, event);
javascript
// 收件人脚本(仅支持ES5!)
// 返回逗号分隔的邮箱地址或用户sys_id列表

(function getRecipients(current, event) {
    var recipients = [];

    // 添加呼叫者
    if (!current.caller_id.nil()) {
        recipients.push(current.caller_id.email.toString());
    }

    // 添加VIP用户的经理
    var caller = current.caller_id.getRefRecord();
    if (caller.vip == true && !caller.manager.nil()) {
        recipients.push(caller.manager.email.toString());
    }

    return recipients.join(',');

})(current, event);

Notification Weight

通知权重

Priority system for multiple matching notifications:
WeightUse Case
0Default priority
1-99Higher priority (lower weight = higher priority)
-1 to -99Lower priority
100+Rarely used
javascript
// Only highest weight notification sends if "Exclude subscribers" checked
// Weight 0 notification beats Weight 10 notification
多通知匹配时的优先级机制:
权重使用场景
0默认优先级
1-99高优先级(权重值越小,优先级越高)
-1至-99低优先级
100+极少使用
javascript
// 若勾选“排除订阅者”,仅最高优先级通知会发送
// 权重0的通知优先级高于权重10的通知

Digest Notifications

摘要通知

Configuring Digest

配置摘要通知

Notification: Daily Incident Summary
├── Digest: Checked
├── Digest Interval: Daily
├── Digest Time: 08:00
└── Content: Summary of all incidents
Notification: 每日事件汇总
├── 摘要:已勾选
├── 摘要间隔:每日
├── 发送时间:08:00
└── 内容:所有事件汇总

Digest Email Script

摘要邮件脚本

javascript
// Summarize digest records
(function runMailScript(current, template, email, email_action, event) {

    var count = 0;
    var html = '<table border="1" cellpadding="5">';
    html += '<tr><th>Number</th><th>Description</th><th>Priority</th></tr>';

    // 'current' is a GlideRecord with all digest records
    while (current.next()) {
        count++;
        html += '<tr>';
        html += '<td>' + current.number + '</td>';
        html += '<td>' + current.short_description + '</td>';
        html += '<td>' + current.priority.getDisplayValue() + '</td>';
        html += '</tr>';
    }
    html += '</table>';
    html += '<p>Total: ' + count + ' incidents</p>';

    template.print(html);

})(current, template, email, email_action, event);
javascript
// 汇总摘要记录
(function runMailScript(current, template, email, email_action, event) {

    var count = 0;
    var html = '<table border="1" cellpadding="5">';
    html += '<tr><th>编号</th><th>描述</th><th>优先级</th></tr>';

    // 'current' 为包含所有摘要记录的GlideRecord对象
    while (current.next()) {
        count++;
        html += '<tr>';
        html += '<td>' + current.number + '</td>';
        html += '<td>' + current.short_description + '</td>';
        html += '<td>' + current.priority.getDisplayValue() + '</td>';
        html += '</tr>';
    }
    html += '</table>';
    html += '<p>总计:' + count + ' 个事件</p>';

    template.print(html);

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

Outbound Email Configuration

outbound邮件配置

Email Properties

邮件属性

javascript
// System Properties for email
glide.email.smtp.active          // Enable/disable outbound email
glide.email.smtp.host            // SMTP server
glide.email.smtp.port            // SMTP port (usually 25 or 587)
glide.email.default.sender       // Default from address
glide.email.test.user            // Test recipient (all emails go here)
javascript
// 系统邮件属性
glide.email.smtp.active          // 启用/禁用 outbound邮件
glide.email.smtp.host            // SMTP服务器
glide.email.smtp.port            // SMTP端口(通常为25或587)
glide.email.default.sender       // 默认发件人地址
glide.email.test.user            // 测试收件人(所有邮件将发送至此)

Testing Notifications

测试通知

javascript
// Background Script to test notification (ES5 only!)
var gr = new GlideRecord('incident');
gr.get('sys_id_here');

// Fire event to trigger notification
gs.eventQueue('incident.assigned', gr,
    gr.assigned_to.getDisplayValue(),
    gs.getUserDisplayName());

gs.info('Event queued for incident: ' + gr.number);
javascript
// 测试通知的后台脚本(仅支持ES5!)
var gr = new GlideRecord('incident');
gr.get('sys_id_here');

// 触发事件以启动通知
gs.eventQueue('incident.assigned', gr,
    gr.assigned_to.getDisplayValue(),
    gs.getUserDisplayName());

gs.info('已为事件触发队列:' + gr.number);

Best Practices

最佳实践

  1. Use Templates - Reuse layouts across notifications
  2. Test Thoroughly - Use test user property during development
  3. Consider Digests - For high-volume notifications
  4. Weight Carefully - Prevent duplicate emails
  5. ES5 Only - All scripts must be ES5 compliant
  6. Limit Recipients - Don't spam large groups
  7. Include Context - Provide enough info to act without login
  8. Mobile-Friendly - Keep HTML simple for mobile clients
  1. 使用模板 - 在多个通知中复用布局
  2. 充分测试 - 开发期间使用测试用户属性
  3. 考虑摘要通知 - 针对高频率通知场景
  4. 合理设置权重 - 避免重复邮件
  5. 仅用ES5 - 所有脚本必须兼容ES5标准
  6. 限制收件人范围 - 不要向大型用户组发送垃圾邮件
  7. 包含上下文信息 - 提供足够信息,无需登录即可操作
  8. 适配移动端 - 简化HTML以适配移动客户端

Common Issues

常见问题

IssueCauseSolution
Email not sentEvent not firedCheck business rule fires event
Wrong recipientsScript errorDebug recipient script
Missing contentTemplate variable wrongCheck field names
Duplicate emailsMultiple notificationsCheck weights and conditions
Delayed emailsEmail job scheduleCheck sysauto_script
问题原因解决方案
邮件未发送事件未触发检查业务规则是否触发事件
收件人错误脚本错误调试收件人脚本
内容缺失模板变量错误检查字段名称
重复邮件多个通知匹配检查权重和条件
邮件延迟邮件任务调度问题检查sysauto_script