Skip to content

Commit 02b9a72

Browse files
authored
Merge branch 'ServiceNowDevProgram:main' into main
2 parents 6579f1b + 7c55c08 commit 02b9a72

File tree

93 files changed

+3457
-1
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

93 files changed

+3457
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
function onChange(control, oldValue, newValue, isLoading) {
2+
if (isLoading) return;
3+
4+
if (newValue === 'hardware') {
5+
g_form.setMandatory('asset_tag', true);
6+
g_form.setDisplay('asset_tag', true);
7+
g_form.setValue('assignment_group', 'Hardware Support Group');
8+
} else if (newValue === 'software') {
9+
g_form.setMandatory('asset_tag', false);
10+
g_form.setDisplay('asset_tag', false);
11+
g_form.setValue('assignment_group', 'Software Support Group');
12+
} else {
13+
g_form.setMandatory('asset_tag', false);
14+
g_form.setDisplay('asset_tag', true);
15+
}
16+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
If an Incident Category = Hardware, make Asset Tag mandatory and automatically assign to Hardware Support Group.
2+
If Software, assign to Software Support Group and hide Asset Tag.
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
var GenericEmailUtility = Class.create();
2+
GenericEmailUtility.prototype = {
3+
initialize: function() {},
4+
5+
// Generate an Outlook (mailto) link with watermark tracking
6+
get_Outlook_link: function() {
7+
try {
8+
const email_payload = JSON.stringify({
9+
"REQUESTOR_ID": "",
10+
"TITLE": "",
11+
"BODY": "",
12+
"REQUEST_ID": "",
13+
"TABLE_ID": ""
14+
});
15+
16+
var mailtoLink = false;
17+
const raw_data = this.getParameter("sysparm_email_body") || email_payload;
18+
19+
if (global.JSUtil.notNil(raw_data)) {
20+
var email_data = JSON.parse(raw_data);
21+
22+
const to = this.getEmail(email_data.REQUESTOR_ID);
23+
const cc = gs.getProperty("instanceEmailAddress"); // instance default CC
24+
const subject = email_data.TITLE || '';
25+
const body = email_data.BODY || '';
26+
27+
const watermark = this.getWatermark(email_data.REQUEST_ID, email_data.TABLE_ID);
28+
29+
// Construct mailto link
30+
mailtoLink = 'mailto:' + to + '?cc=' + cc;
31+
32+
if (subject)
33+
mailtoLink += '&subject=' + encodeURIComponent(subject);
34+
35+
if (body)
36+
mailtoLink += '&body=' + encodeURIComponent(body);
37+
38+
if (watermark)
39+
mailtoLink += encodeURIComponent("\n\nRef: " + watermark);
40+
}
41+
42+
return mailtoLink;
43+
44+
} catch (ex) {
45+
gs.error("Error in get_Outlook_link(): " + ex.message);
46+
return false;
47+
}
48+
},
49+
50+
// Fetch watermark ID (creates one if missing)
51+
getWatermark: function(record_id, table_name) {
52+
var wm = new GlideRecord('sys_watermark');
53+
wm.addQuery('source_id', record_id);
54+
wm.orderByDesc('sys_created_on');
55+
wm.query();
56+
57+
if (wm.next()) {
58+
return wm.getValue('number');
59+
}
60+
61+
wm.initialize();
62+
wm.source_id = record_id;
63+
wm.source_table = table_name;
64+
wm.insert();
65+
66+
return wm.getValue('number');
67+
},
68+
69+
// Retrieve user’s email address
70+
getEmail: function(user_id) {
71+
if (global.JSUtil.notNil(user_id)) {
72+
var user = new GlideRecordSecure('sys_user');
73+
if (user.get(user_id))
74+
return user.email.toString();
75+
}
76+
return '';
77+
},
78+
79+
type: 'GenericEmailUtility'
80+
};
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Outlook Email Watermark Utility for ServiceNow
2+
3+
# Overview
4+
This reusable utility allows users to send emails **outside ServiceNow** (e.g., using Outlook or any default mail client) while still maintaining the conversation within ServiceNow.
5+
By embedding a unique watermark reference, any replies to the email will automatically append to the original record's activity feed.
6+
7+
This helps teams collaborate externally without losing internal record visibility — ideal for customers or vendors who communicate via Outlook.
8+
9+
---
10+
11+
# Objective
12+
- Enable ServiceNow users to send Outlook emails directly from a record.
13+
- Maintain conversation history in ServiceNow using watermark tracking.
14+
- Make the solution **generic**, reusable across tables (Incident, Change, Request, etc.).
15+
- Prevent dependency on outbound mail scripts or custom integrations.
16+
17+
# Components
18+
19+
## 1. Script Include: GenericEmailUtility
20+
Handles the logic for:
21+
- Constructing the mailto: link.
22+
- Fetching recipient and instance email addresses.
23+
- Generating or retrieving the watermark ID.
24+
- Returning a formatted Outlook link to the client script.
25+
26+
## Key Methods
27+
1. get_Outlook_link() - Builds the full Outlook mail link with subject, body, and watermark.
28+
2. getWatermark(record_id, table_name) - Ensures a watermark exists for the record.
29+
3. getEmail(user_id) - Fetches the email address for the target user.
30+
31+
## 2. UI Action (Client Script)
32+
Executes on the record form when the button/link is clicked.
33+
It gathers record data, constructs a payload, calls the Script Include using GlideAjax, and opens Outlook.
34+
35+
## Key Steps
36+
1. Collect field data like requestor, short description, and description.
37+
2. Pass record details to the Script Include (GenericEmailUtility).
38+
3. Receive a ready-to-use Outlook link.
39+
4. Open the mail client with prefilled details and watermark reference.
40+
41+
## How It Works
42+
1. User clicks "Send Outlook Email" UI Action on a record.
43+
2. Script gathers record data and passes it to GenericEmailUtility.
44+
3. The utility builds a 'mailto:' link including the watermark.
45+
4. Outlook (or default mail client) opens with pre-filled To, CC, Subject, and Body fields.
46+
5. When the recipient replies, ServiceNow uses the watermark to append comments to the correct record.
47+
48+
## Example Usage
49+
**User clicks “Send Outlook Email”** on a Request record:
50+
Outlook opens prefilled like this:
51+
52+
<img width="288" height="65" alt="image" src="https://github.com/user-attachments/assets/b58c5e0a-d80a-40ca-9ab5-f188a1203169" />
53+
54+
55+
<img width="710" height="496" alt="image" src="https://github.com/user-attachments/assets/5cbc7645-4233-4826-99f7-e2948bb5ab78" />
56+
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
function onClick(g_form) {
2+
var separator = "\n--------------------------------\n";
3+
var email_body = "Record URL:\n" + g_form.getDisplayValue('number') + separator;
4+
email_body += "Short Description:\n" + g_form.getValue('short_description') + separator;
5+
email_body += "Description:\n" + g_form.getValue('description') + separator;
6+
7+
var email_data = {};
8+
email_data.REQUESTOR_ID = g_form.getValue('caller_id') || g_form.getValue('opened_by') || g_form.getValue('requested_for');
9+
email_data.TITLE = g_form.getValue('short_description') || 'ServiceNow Communication';
10+
email_data.BODY = email_body;
11+
email_data.REQUEST_ID = g_form.getUniqueValue();
12+
email_data.TABLE_ID = g_form.getTableName();
13+
14+
var ga = new GlideAjax('GenericEmailUtility');
15+
ga.addParam('sysparm_name', 'get_Outlook_link');
16+
ga.addParam('sysparm_email_body', JSON.stringify(email_data));
17+
ga.getXMLAnswer(function(response) {
18+
var mailto_link = response;
19+
if (mailto_link && mailto_link != 'false') {
20+
window.open(mailto_link);
21+
} else {
22+
g_form.addErrorMessage('Unable to generate Outlook link.');
23+
}
24+
});
25+
}
80.1 KB
Loading
105 KB
Loading
67.7 KB
Loading
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
## Field Review of User Record when on form using action button
2+
3+
Displays informational messages suggesting improvements to field formatting on the User Table (**sys_user**) form when the **Fields Check** button is clicked.
4+
5+
- Helps maintain consistency in user data by checking capitalization of names and titles, validating email format, ensuring phone numbers contain only digits, and preventing duplicate phone entries.
6+
- Also suggests users not to leave the **user_name** field empty.
7+
- Shows Info messages below each field highlighting fields that may need attention.
8+
- Simple Prerequisite is that: when form loads give Info message to check **Field Check** button to bring user's attention
9+
- Uses a Client-side UI Action (**Fields Check**) that to review entered data and display friendly suggestions
10+
- Name: Fields Check
11+
- Table: User (sys_user)
12+
- Client: true
13+
- Form button: true
14+
- Onclick: onClickCheckDetails()
15+
16+
---
17+
18+
### Grab user's attention on Field Check Button using Info message at top
19+
20+
![Field Review on User Table_1](Field_Review_userTable_1.png)
21+
22+
---
23+
24+
### After clicking Field Check Button where suggestions are displayed below fields
25+
26+
![Field Review on User Table_2](Field_Review_userTable_2.png)
27+
28+
---
29+
30+
### When user fixes the suggested issues and click the **Fields Check** button again, a message confirms that all fields are correctly formatted
31+
32+
![Field Review on User Table_3](Field_Review_userTable_3.png)
33+
34+
---
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
function onClickCheckDetails() {
2+
// Friendly helper for field normalization guidance
3+
g_form.hideAllFieldMsgs();
4+
g_form.clearMessages();
5+
6+
// --- Get Field values ---
7+
var firstName = g_form.getValue('first_name');
8+
var lastName = g_form.getValue('last_name');
9+
var title = g_form.getValue('title');
10+
var userId = g_form.getValue('user_name');
11+
var email = g_form.getValue('email');
12+
var businessPhone = g_form.getValue('phone');
13+
var mobilePhone = g_form.getValue('mobile_phone');
14+
15+
// --- Regex patterns ---
16+
var capitalRegex = /^[A-Z][a-zA-Z\s]*$/; // Names & titles start with a capital
17+
var emailRegex = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/;
18+
var phoneRegex = /^\d+$/;
19+
20+
var suggestions = [];
21+
22+
if (firstName && !capitalRegex.test(firstName)) {
23+
g_form.showFieldMsg('first_name', 'Suggestion: Start the name with a capital letter.', 'info');
24+
suggestions.push('First Name');
25+
}
26+
27+
if (lastName && !capitalRegex.test(lastName)) {
28+
g_form.showFieldMsg('last_name', 'Suggestion: Start the name with a capital letter.', 'info');
29+
suggestions.push('Last Name');
30+
}
31+
32+
if (title && !capitalRegex.test(title)) {
33+
g_form.showFieldMsg('title', 'Suggestion: Titles usually start with a capital letter.', 'info');
34+
suggestions.push('Title');
35+
}
36+
37+
if (!userId) {
38+
g_form.showFieldMsg('user_name', 'Suggestion: Do not keep the User ID empty.', 'info');
39+
suggestions.push('User ID');
40+
}
41+
42+
if (email && !emailRegex.test(email)) {
43+
g_form.showFieldMsg('email', 'Suggestion: Please use a valid email format like name@example.com.', 'info');
44+
suggestions.push('Email');
45+
}
46+
47+
if (businessPhone && !phoneRegex.test(businessPhone)) {
48+
g_form.showFieldMsg('phone', 'Suggestion: Use digits only avoid letters.', 'info');
49+
suggestions.push('Business Phone');
50+
}
51+
52+
if (mobilePhone && !phoneRegex.test(mobilePhone)) {
53+
g_form.showFieldMsg('mobile_phone', 'Suggestion: Use digits only avoid letters.', 'info');
54+
suggestions.push('Mobile Phone');
55+
}
56+
57+
/
58+
if (businessPhone && mobilePhone && businessPhone === mobilePhone) {
59+
g_form.showFieldMsg('phone', 'Work and mobile numbers appear identical, use different Numbers!', 'info');
60+
suggestions.push('Phone Numbers');
61+
}
62+
63+
if (suggestions.length > 0) {
64+
g_form.addInfoMessage('Quick review complete! Please check: ' + suggestions.join(', ') + '.');
65+
} else {
66+
g_form.addInfoMessage('looks good! Nicely formatted data.');
67+
}
68+
}

0 commit comments

Comments
 (0)