Notifications are the part of ServiceNow most people outside IT actually see. A caller gets an email when their incident is resolved; an approver gets a request; a group gets told about a new assignment. When notifications are designed well, nobody thinks about them. When they’re not, you get the Monday morning where a data fix touched 2,000 incidents and every caller and every group member got an “Incident updated” email for each one.
The interview questions here are practical: how do you trigger a notification, how do you stop duplicates, and what do you do before running a bulk change. Underneath all three is one idea: a notification should correspond to something a human cares about, not to a database write.
Three ways a notification gets triggered
An email notification record (on the sysevent_email_action table) has a “When to send” section with three options. ServiceNow’s documentation lists them as: when a record is inserted or updated, when a particular event is fired, or from a Notification step in Flow Designer.
Record inserted or updated is the simplest. You tick Inserted, Updated or both, and add conditions. The notification is evaluated whenever the record is saved, which is why loose conditions cause storms: every save is a candidate.
Event is fired decouples the “when” from the save. A business rule, script or workflow calls gs.eventQueue() with an event name registered in the event registry, and the notification listens for that name:
// After update business rule on incident (illustrative)
(function executeRule(current, previous) {
if (current.state.changesTo(6) && !current.close_notes.nil()) { // 6 = Resolved
gs.eventQueue('acme.incident.resolved', current, current.caller_id, current.assignment_group);
}
})(current, previous);The two extra arguments become event.parm1 and event.parm2, which the notification can use as recipients (“Event parm 1 contains recipient”). Because events are processed asynchronously from the event queue, the user’s save isn’t held up by email generation. The event is also a reusable signal: the same acme.incident.resolved event can drive the email, a survey trigger and a script action, and you can see every occurrence in the event log.
Flow Designer fits when the notification is one step in a larger process, such as an approval flow that emails the approver, waits, then escalates. The flow’s history then shows exactly when the email was sent and why.
A useful interview answer explains the choice: insert/update for simple, field-based rules; events when the trigger needs logic, when several things react to the same moment, or when you want to fire it from places other than a save; flows when the email belongs to a sequence.
Conditions that match a moment
“Send when an incident is updated” is almost never the requirement. The caller wants to know when someone replied, when the incident is resolved, or when it’s reopened. The assignment group wants to know when work lands in their queue. Write conditions that describe those changes: State changes to Resolved, Additional comments changes, Assignment group changes. The condition builder has “changes”, “changes to” and “changes from” operators for exactly this.
When the condition can’t be built visually, the advanced condition script can set answer (or return true) to allow the send. Keep it light: it runs for every candidate save.
To see how much the condition matters, I modelled a fix script that re-categorises 2,000 open incidents. Each incident has a caller and an assignment group of 12 people, spread across 900 callers and 15 groups. The only fields that change are category and subcategory:
const everyone = (inc) => [inc.caller, ...Array.from({ length: groupSize }, (_, k) => `${inc.group}-m${k}`)];
count({ recipients: everyone, fire: () => true });
count({ recipients: everyone, fire: (c) => c.fields.some((f) => ['state', 'comments'].includes(f)) });A "incident updated", any change : 26000 emails, 1080 people, worst inbox 134
B only when state or comments change: 0 emails, 0 people, worst inbox 0With an “any update” notification, 26,000 emails go out and one unlucky group member receives 134 of them. With a condition tied to the changes a person cares about, the recategorisation sends nothing, which is correct: nobody needs to know their incident’s subcategory was cleaned up.
Duplicates and the weight field
Even with good conditions, one save can satisfy two notifications. An agent adds a comment and resolves the incident in the same update, so both “Incident commented” and “Incident resolved” qualify for the caller. The Weight field handles this. ServiceNow treats notifications on the same table to the same recipients as duplicates, and sends only the one with the highest weight; the others are moved to the Skipped mailbox instead of being sent. The default weight is 0, which means “always send if conditions match”, so a notification you never gave a weight never takes part in this deduplication.
So for the caller-facing incident notifications, give the resolution email a higher weight than the comment email. The caller gets one message saying the incident is resolved, which already includes the latest comment if your template shows it.
Two other fields on the form matter for noise. “Send to event creator” controls whether the person who caused the notification also receives it; for “you commented on your own incident” emails, clearing it is usually right. And recipients can manage their own subscriptions and digests through notification preferences, which is worth mentioning when a stakeholder asks for “fewer emails” rather than a design change.
Gotcha
On a cloned sub-production instance, real user email addresses come across with the data. Before testing notifications there, make sure outbound email is disabled or redirected to a test address (the email properties include a setting for this), or your testing reaches real customers.
Before a bulk update or import
Notifications on insert/update evaluate for every row, whether the row came from a person, a transform map or a background script. Before any bulk operation, check which notifications listen to the table and whether your change can satisfy their conditions. You have a few options:
- Tighten the conditions permanently, as above. This is the real fix and protects you from the next bulk job too.
- In a background or fix script,
setWorkflow(false)on the GlideRecord stops business rules running for those updates, which also stops events that business rules would queue. It skips everything else those rules do, so use it only when you’ve checked what you’re skipping, and test the effect on notifications in sub-production first. - For imports, decide in the transform map whether to run business rules, and make sure “created by integration” changes don’t match human-facing conditions.
- Look at the outbox before email jobs pick messages up. In an emergency, setting the queued emails to a non-sending state is better than an apology email to 900 callers.
Interview exercise: the reassignment storm
A team lead runs a script to move 600 incidents from the dissolved “Desktop Support” group to “End User Services”. Within ten minutes the new group’s 20 members each have about 600 assignment emails, and callers are asking why their incident “was updated”. How would you have prevented it, and what do you change now?
Answer
Each update() triggered the “assigned to group” notification for 20 members and an “incident updated” notification for the caller, so roughly 12,000 group emails plus 600 caller emails. Prevention would have meant checking the notifications on incident before running the script. For a pure administrative reassignment, the script could have used setWorkflow(false), after confirming that skipping business rules didn’t break anything else (SLA recalculation, for instance), or the team could have sent one summary message to the new group instead. Going forward, I’d fix the caller notification so it fires on state changes and comments rather than any update, give overlapping caller notifications sensible weights, and add a checklist step for bulk scripts: list the notifications on the table, decide which should fire, and test on a sub-production clone with email redirected.