mcpField
E
email-notifications

email-notifications

github.com/serac-labs开发7794 次安装9 周前更新
代码仓库

关于 email-notifications

面向 ServiceNow 管理者与开发者的通知配置技能,说明如何通过事件、条件、模板和脚本发送邮件等提醒。还涵盖收件人、摘要通知、权重及测试与排错。

主要功能

  1. 01配置通知条件与事件
  2. 02创建邮件模板和脚本
  3. 03设置动态收件人
  4. 04配置摘要通知与权重
  5. 05测试并排查发送问题

适用场景

  1. 01通知事件分配给用户
  2. 02发送升级或审批提醒
  3. 03制作每日事件摘要
  4. 04排查收件人或内容错误

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/serac-labs/serac --skill email-notifications

安装后在 Claude Code 中输入/email-notifications确认已加载。

详细介绍

ServiceNow 邮件通知

ServiceNow 通知由事件触发,并向用户发送邮件、短信或其他提醒。

通知组件

组件表用途
通知sysevent_email_action主要通知记录
邮件模板sysevent_email_template可复用的邮件布局
事件sysevent触发通知
事件注册sysevent_register定义自定义事件
邮件脚本sys_script_email动态内容脚本

创建通知

基本通知结构
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
通知条件
// 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';
})()

邮件模板

模板变量

${number}

${caller_id.name}

${opened_at.display_value}



${URI}

${URI_REF}

${mail_script:script_name}



${mailto:assigned_to}

模板示例
<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>

邮件脚本

基本邮件脚本
// 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)
带附件的邮件脚本
// 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)
动态收件人
// 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)

自定义事件

注册自定义事件
// 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)
自定义事件的通知
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}

收件人类型

接收对象
类型描述示例
用户指定用户${assigned_to}、${caller_id}
组用户组服务台、CAB
组管理员组管理员字段${assignment_group.manager}
事件参数 1/2来自事件参数${event.parm1}
其他收件人电子邮件地址外部邮件
收件人脚本
// 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)

通知权重

多个匹配通知的优先级系统:

权重用例
0默认优先级
1-99更高优先级(权重越低,优先级越高)
-1 to -99较低优先级
100+很少使用
// Only highest weight notification sends if "Exclude subscribers" checked
// Weight 0 notification beats Weight 10 notification

摘要通知

配置摘要
Notification: Daily Incident Summary
├── Digest: Checked
├── Digest Interval: Daily
├── Digest Time: 08:00
└── Content: Summary of all incidents
摘要邮件脚本
// 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)

出站邮件配置

邮件属性
// 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)
测试通知
// 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)

最佳实践

  1. 使用模板 - 在多个通知中复用布局
  2. 充分测试 - 开发期间使用测试用户属性
  3. 考虑摘要通知 - 适用于通知量较大的情况
  4. 谨慎设置权重 - 避免重复发送邮件
  5. 仅使用 ES5 - 所有脚本都必须符合 ES5 标准
  6. 限制收件人 - 不要向大型群组发送垃圾邮件
  7. 提供上下文 - 提供足够的信息,让用户无需登录即可采取行动
  8. 适配移动设备 - 保持 HTML 简洁,以适用于移动客户端

常见问题

问题原因解决方案
未发送邮件未触发事件检查业务规则是否触发事件
收件人错误脚本错误调试收件人脚本
内容缺失模板变量错误检查字段名称
重复邮件存在多个通知检查权重和条件
邮件延迟邮件作业计划检查 sysauto_script

评论

支持 Markdown