Restricting Outbound Email Recipients in Non‐Production Instances - ben-vargas/servicenow-wiki GitHub Wiki
This article describes how to implement a solution to restrict outbound emails in ServiceNow non-production instances (e.g., development, test) to a specific group of users. This is crucial for preventing accidental emails from being sent to real users during testing and development.
In non-production ServiceNow instances, it's crucial to prevent emails generated by the platform from reaching external users or production users. Sending test emails to a limited set of internal users or a specific group ensures proper testing of email functionality without disrupting real users. Without proper controls, these emails could cause confusion, expose sensitive data, or unintentionally trigger workflows in production environments.
This solution uses a system property and a Business Rule to intercept outgoing emails and reroute them to a designated test group. This will ensure only those in that group will receive any emails. This approach provides a centralized and flexible way to manage email recipients in your non-production environments.
-
System Property:
-
tp13.glide.email.test.group
: This system property stores thesys_id
or name of the user group whose members are allowed to receive emails. This property allows for an easy way to turn on or off this functionality, or to swap the group used.
-
-
Business Rule:
-
TP13 Filter SubProd / NonProd Emails
: This Business Rule runs before sending emails (on thesys_email
table). It intercepts outgoing emails based on a condition that checks for the above property, validates the group, and changes the recipients of the email.
-
To create the system property manually:
- Navigate to System Definition > Properties
- Click the New button.
- Fill out the following fields:
- Description: Send all mail only to the members of this group (by sys_id) (non-production testing) -- The above property overrides this setting.
-
Name:
tp13.glide.email.test.group
-
Table:
sys_properties
-
Type:
string
-
Value: Set this to the
sys_id
of the group that should receive the test emails, or the name of the group.
To create the Business Rule manually:
- Navigate to System Definition > Business Rules
- Click the New button.
- Fill out the following fields:
-
Name:
TP13 Filter SubProd / NonProd Emails
-
Table:
sys_email
-
When:
before
-
Advanced:
true
(Checked) -
Condition:
gs.getProperty('tp13.glide.email.test.group','') != ''
-
Filter Condition: Set the condition builder with the following values:
[type] [is] [send-ready]
AND[body] [does not contain] [glide.email.test]
. -
Script:
-
/**
* SubProd Email Filter
* This code handles checking all outgoing emails for who they're supposed to
* send to, and restricts it to only send to a specific group of people.
*
* This code is compatible with text notifications, and with calendar invites.
* This code is overridden by the glide.email.test.user property.
*
* Example Usage:
* On a Dev instance, to have only developers get emails.
*
* Specifically:
* This looks for the property "tp13.glide.email.test.group" and if it's populated
* it looks at all the recipients of the outbound emails, and checks to see
* if those email addresses or phone numbers belong to the members of the
* group referenced by sys_id in the property.
*
* If the user that created the record the email is about happens to be in the
* group, they will be added to the recipients list (to simplify testing).
*
* Note that in the code below:
* allowedEmails = people the email is slated to go to
* grpMembers = email addresses / phone numbers allowed to receive email.
*/
if (current.type != 'received') {
subprodEmailFilter();
}
function subprodEmailFilter() {
var table = current.target_table;
var record = current.instance;
var recips = current.recipients;
var bcc = current.blind_copied;
var cc = current.copied;
var body = current.body;
var body_text = current.body_text;
var grpMembers = [];
var allowedEmails = [];
var allowedBCC = [];
var allowedCC = [];
var email = '';
var phone = '';
var lastUpdate = '';
var groupName = '';
// Grab the sys_id of the email group, and verify it's a valid group.
var testGroup = gs.getProperty('tp13.glide.email.test.group', '');
// If the email is not turned on, then this should not run.
if (testGroup == '') {
return false;
}
// Validate that the group exists.
var grp = new GlideRecord('sys_user_group');
if (grp.get('sys_id', testGroup)) {
groupName = grp.name.toString();
} else if (grp.get('name', testGroup)) {
testGroup = grp.sys_id; // Sets the group sys_id
groupName = grp.name.toString();
} else {
// SubProd Email Group not found, don't send any emails.
current.type = 'send-ignored';
gs.log('Email Test Group "' + groupName + '" provided but does not match a valid group, so no email has been sent. Check property tp13.glide.email.test.group.');
return false;
}
// Look through all members of the test group, checking their email and phone.
var grpMember = new GlideRecord('sys_user_grmember');
grpMember.addQuery('group', testGroup);
grpMember.query();
var ndv;
while (grpMember.next()) {
// For each user, check their email
email = grpMember.user.email.toString();
if (recips.indexOf(email) >= 0) {
if (allowedEmails[0] == '') {
allowedEmails[0] = grpMember.user.email.toString();
} else {
allowedEmails.push(grpMember.user.email.toString());
}
}
if (bcc.indexOf(email) >= 0) {
if (allowedBCC[0] == '') {
allowedBCC[0] = grpMember.user.email.toString();
} else {
allowedBCC.push(grpMember.user.email.toString());
}
}
if (cc.indexOf(email) >= 0) {
if (allowedCC[0] == '') {
allowedCC[0] = grpMember.user.email.toString();
} else {
allowedCC.push(grpMember.user.email.toString());
}
}
grpMembers.push(grpMember.user.email.toString());
// Lookup that member's notification devices
ndv = new GlideRecord("cmn_notif_device");
ndv.addQuery("user", grpMember.user);
ndv.addQuery("email_address", "!=", email);
ndv.query();
while (ndv.next()) {
if (ndv.type == "SMS")
phone = String(ndv.phone_number) + "@" + String(ndv.service_provider.email_suffix);
else
phone = String(ndv.email_address);
if (recips.indexOf(phone) >= 0) {
allowedEmails.push(phone);
}
if (bcc.indexOf(phone) >= 0) {
allowedBCC.push(phone);
}
if (cc.indexOf(phone) >= 0) {
allowedCC.push(phone);
}
grpMembers.push(phone);
}
}
// Look to see who last updated the referenced record.
if (table) {
var gr = new GlideRecord(table);
if (gr.get(record)) {
lastUpdate = gr.sys_updated_by;
}
}
// Check if the last updated user is in the allowedEmails array and add them if not
// Only do this if there are no valid recipients.
if (lastUpdate && !allowedEmails) {
var usr = new GlideRecord('sys_user');
usr.addQuery('user_name', lastUpdate);
usr.addQuery('notification', 2); // Email notifications are set to 2
usr.query();
if (usr.next()) {
if (grpMembers.toString().indexOf(usr.email) >= 0) {
if (allowedEmails.toString().indexOf(usr.email) == -1) {
allowedEmails.push(usr.email.toString());
}
}
}
}
// If the current recipients field is blank then set the text to NONE.
if (recips == '')
recips = 'NONE';
// DO NOT APPEND anything if this is a calendar invite.
if (body.indexOf("END:VCALENDAR") < 0 && body != '' && body != null) {
current.body = body + '<div><br/><br/><hr/></div><div>Testing mode on via system property "tp13.glide.email.test.group". Intended recipients: ' + recips + '</div><br/>';
} else if (body.indexOf("END:VCALENDAR") < 0 && body_text != '' && body_text != null) {
current.body_text = body_text + '\n\nTesting mode on via system property "tp13.glide.email.test.group". Intended recipients: ' + recips;
}
// Set the recipients.
current.recipients = allowedEmails.toString();
current.blind_copied = allowedBCC.toString();
current.copied = allowedCC.toString();
return true;
}
Explanation:
- The Business Rule runs before emails are sent and only when a property value is present.
- The
subprodEmailFilter
function then:- Validates the test group, and if not valid, logs an error, ignores the email, and returns.
- Queries all members of the test group, including their notification devices (SMS email addresses).
- Checks if the original recipients (to, cc, bcc) exist in the test group's member list and if not, removes them from the original recipient list.
- If the last updated user is a member of the test group (to allow testing by those users), they will be added to the recipients list.
- It adds a line to the email body to identify that the email is from a test instance.
- It updates the email with only valid recipients, and sets the copied and blind copied fields as needed.
-
Create the System Property:
- Follow the instructions above to manually create the system property.
-
Create the Business Rule:
- Follow the instructions above to manually create the Business Rule.
- Copy the provided code into the Script field.
-
Ensure the Business Rule is Active:
- Navigate to
sys_script.list
and search forTP13 Filter SubProd / NonProd Emails
. - Ensure the
Active
checkbox is selected.
- Navigate to
-
Testing:
- Trigger emails from the instance, and confirm that only members of the configured group receive the messages. Verify that the last updated user for the record is also added if that user is a member of the test group.
-
Configuration: Ensure the
tp13.glide.email.test.group
property is configured correctly with thesys_id
or name of a valid group. - Active Property: Always double-check that the business rule is active.
- Group Management: Make sure the users in your test group are users who are appropriate for receiving email from the instance.
- Error Handling: If errors occur during the process, make sure to look at the logs for detailed information about how the Business Rule ran and if any issues were reported.
- Testing: Thoroughly test the solution to confirm that the correct users are getting emails, and all other users are not.
- Avoid Production: This logic should never be enabled on a production instance.
- Notification Devices: This script will get both email addresses, and phone numbers when looking for matching users. Ensure you have the proper mobile setup for this.
- Direct User Override: Consider adding a property where individual users can opt out of the test email functionality, as currently, it is controlled by the group property only.
- Script Includes: Consider moving some of the logic into a Script Include for better maintainability and reusability.
- System Properties: Restrict access to modify system properties to authorized users only.
- Business Rules: Limit write access to business rules, to ensure that no one can disable the logic.
This solution provides a robust mechanism for restricting outbound emails in non-production ServiceNow instances. By implementing a system property and Business Rule, you can ensure that emails are only sent to authorized personnel during testing and development. This helps to improve security, prevent user disruption, and maintain the integrity of your non-production environments. Always remember to test all code in a non-production environment before deploying to production.