diff --git a/Client-Side Components/UI Actions/Email Watermark Utility/GenericEmailUtility.js b/Client-Side Components/UI Actions/Email Watermark Utility/GenericEmailUtility.js new file mode 100644 index 0000000000..1626209823 --- /dev/null +++ b/Client-Side Components/UI Actions/Email Watermark Utility/GenericEmailUtility.js @@ -0,0 +1,80 @@ +var GenericEmailUtility = Class.create(); +GenericEmailUtility.prototype = { + initialize: function() {}, + + // Generate an Outlook (mailto) link with watermark tracking + get_Outlook_link: function() { + try { + const email_payload = JSON.stringify({ + "REQUESTOR_ID": "", + "TITLE": "", + "BODY": "", + "REQUEST_ID": "", + "TABLE_ID": "" + }); + + var mailtoLink = false; + const raw_data = this.getParameter("sysparm_email_body") || email_payload; + + if (global.JSUtil.notNil(raw_data)) { + var email_data = JSON.parse(raw_data); + + const to = this.getEmail(email_data.REQUESTOR_ID); + const cc = gs.getProperty("instanceEmailAddress"); // instance default CC + const subject = email_data.TITLE || ''; + const body = email_data.BODY || ''; + + const watermark = this.getWatermark(email_data.REQUEST_ID, email_data.TABLE_ID); + + // Construct mailto link + mailtoLink = 'mailto:' + to + '?cc=' + cc; + + if (subject) + mailtoLink += '&subject=' + encodeURIComponent(subject); + + if (body) + mailtoLink += '&body=' + encodeURIComponent(body); + + if (watermark) + mailtoLink += encodeURIComponent("\n\nRef: " + watermark); + } + + return mailtoLink; + + } catch (ex) { + gs.error("Error in get_Outlook_link(): " + ex.message); + return false; + } + }, + + // Fetch watermark ID (creates one if missing) + getWatermark: function(record_id, table_name) { + var wm = new GlideRecord('sys_watermark'); + wm.addQuery('source_id', record_id); + wm.orderByDesc('sys_created_on'); + wm.query(); + + if (wm.next()) { + return wm.getValue('number'); + } + + wm.initialize(); + wm.source_id = record_id; + wm.source_table = table_name; + wm.insert(); + + return wm.getValue('number'); + }, + + // Retrieve user’s email address + getEmail: function(user_id) { + if (global.JSUtil.notNil(user_id)) { + var user = new GlideRecordSecure('sys_user'); + if (user.get(user_id)) + return user.email.toString(); + } + return ''; + }, + + type: 'GenericEmailUtility' +}; diff --git a/Client-Side Components/UI Actions/Email Watermark Utility/README.md b/Client-Side Components/UI Actions/Email Watermark Utility/README.md new file mode 100644 index 0000000000..29a7da7425 --- /dev/null +++ b/Client-Side Components/UI Actions/Email Watermark Utility/README.md @@ -0,0 +1,56 @@ +# Outlook Email Watermark Utility for ServiceNow + +# Overview +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. +By embedding a unique watermark reference, any replies to the email will automatically append to the original record's activity feed. + +This helps teams collaborate externally without losing internal record visibility — ideal for customers or vendors who communicate via Outlook. + +--- + +# Objective +- Enable ServiceNow users to send Outlook emails directly from a record. +- Maintain conversation history in ServiceNow using watermark tracking. +- Make the solution **generic**, reusable across tables (Incident, Change, Request, etc.). +- Prevent dependency on outbound mail scripts or custom integrations. + +# Components + +## 1. Script Include: GenericEmailUtility +Handles the logic for: +- Constructing the mailto: link. +- Fetching recipient and instance email addresses. +- Generating or retrieving the watermark ID. +- Returning a formatted Outlook link to the client script. + +## Key Methods +1. get_Outlook_link() - Builds the full Outlook mail link with subject, body, and watermark. +2. getWatermark(record_id, table_name) - Ensures a watermark exists for the record. +3. getEmail(user_id) - Fetches the email address for the target user. + +## 2. UI Action (Client Script) +Executes on the record form when the button/link is clicked. +It gathers record data, constructs a payload, calls the Script Include using GlideAjax, and opens Outlook. + +## Key Steps +1. Collect field data like requestor, short description, and description. +2. Pass record details to the Script Include (GenericEmailUtility). +3. Receive a ready-to-use Outlook link. +4. Open the mail client with prefilled details and watermark reference. + +## How It Works +1. User clicks "Send Outlook Email" UI Action on a record. +2. Script gathers record data and passes it to GenericEmailUtility. +3. The utility builds a 'mailto:' link including the watermark. +4. Outlook (or default mail client) opens with pre-filled To, CC, Subject, and Body fields. +5. When the recipient replies, ServiceNow uses the watermark to append comments to the correct record. + +## Example Usage +**User clicks “Send Outlook Email”** on a Request record: +Outlook opens prefilled like this: + +image + + +image + diff --git a/Client-Side Components/UI Actions/Email Watermark Utility/Send Email UI Action.js b/Client-Side Components/UI Actions/Email Watermark Utility/Send Email UI Action.js new file mode 100644 index 0000000000..000424a283 --- /dev/null +++ b/Client-Side Components/UI Actions/Email Watermark Utility/Send Email UI Action.js @@ -0,0 +1,25 @@ +function onClick(g_form) { + var separator = "\n--------------------------------\n"; + var email_body = "Record URL:\n" + g_form.getDisplayValue('number') + separator; + email_body += "Short Description:\n" + g_form.getValue('short_description') + separator; + email_body += "Description:\n" + g_form.getValue('description') + separator; + + var email_data = {}; + email_data.REQUESTOR_ID = g_form.getValue('caller_id') || g_form.getValue('opened_by') || g_form.getValue('requested_for'); + email_data.TITLE = g_form.getValue('short_description') || 'ServiceNow Communication'; + email_data.BODY = email_body; + email_data.REQUEST_ID = g_form.getUniqueValue(); + email_data.TABLE_ID = g_form.getTableName(); + + var ga = new GlideAjax('GenericEmailUtility'); + ga.addParam('sysparm_name', 'get_Outlook_link'); + ga.addParam('sysparm_email_body', JSON.stringify(email_data)); + ga.getXMLAnswer(function(response) { + var mailto_link = response; + if (mailto_link && mailto_link != 'false') { + window.open(mailto_link); + } else { + g_form.addErrorMessage('Unable to generate Outlook link.'); + } + }); +}