Interested in a ServiceNow event built for developers? Registration for now[dev]26 is officially open!

Best practice for email correlation between ServiceNow CSM and customer's ticketing system

sn-ushi
Tera Contributor

Hi all,

we have a CSM email integration scenario where both ServiceNow and the customer use their own ticketing systems.

The customer sends emails from their ticketing system to our ServiceNow CSM mailbox. Their external ticket number is part of the subject, for example:

Ticket: EXT-123456 - "open tickets"

ServiceNow creates a Case, e.g. CS0012345, and sends an automatic notification back to the customer's service desk.

The ServiceNow notification subject is currently something like:

CS0012345 - A new case has been opened

ServiceNow also adds its normal Ref:MSG... watermark to the email.

The problem is that the customer's ticketing system requires its own ticket number (EXT-123456) in the subject to associate the incoming email with the existing ticket. If the external ticket number is no longer present, the customer system may create a new ticket, potentially resulting in an email/ticket ping-pong.

On the ServiceNow Case, correlation_id and correlation_display are currently empty.

What is the recommended ServiceNow approach for this kind of email-to-email ticket system communication?

In particular:

  • Is there an OOTB/recommended mechanism to retain an external ticket reference from an inbound email and reuse it in outbound notification subjects?
  • Should the external ticket number be stored in correlation_id, or is that field intended for a different correlation scenario?
  • Would you recommend storing the customer's ticket number in a dedicated Case field and using it in the notification subject?
  • How should this work together with ServiceNow's existing Ref:MSG... watermark?
  • Is there a standard approach to prevent autoresponse loops when both ServiceNow and the external ticketing system generate automatic notifications?
  • Ideally, this behavior should be configurable only for customers/service desk mailboxes that require external ticket correlation.
3 REPLIES 3

Vishal Jaswal
Tera Sage

Hello @sn-ushi 

#1: Customer sends an e-mail to their ticketing system (let's say TS).

#2: TS creates a ticket and send this ticket e-mail to ServiceNow (let's say SN). E-mail subject "Ticket: EXT-123456 - "open tickets""

#3: SN should have an inbound e-mail action to read such e-mail, extract the TS Ticket number, create the case and ensure case's correlation-id (out-of-the-box field in case form) is populated with extracted TS Ticket number as shown below in example background script:

NOTE: You must validate existing active case records for the same TS ticket number and if not found then create case (which means everything should be done in the if loop where I have used gs.print).

var emailSubject = 'Ticket: EXT-123456 - "open tickets"';
var extTicketRegex = /EXT-\d+/i;
var match = emailSubject.match(extTicketRegex);
if (match && match[0]) {  
	gs.print(match[0].toUpperCase());
}

 

VishalJaswal_0-1787771466630.png

 

 #4: SN e-mail notification(s): If you already have and don't want to use them, then you can have filter like correlation id is not empty and correlation display is not Name of the customer (you can hardcode it in your inbound e-mail action). Create new SN e-mail notification(s) by duplicating the existing ones and reverse the filter condition as shown above and in the subject field you can use the correlation id data pill / variable to append TS ticket number in the e-mail subject of SN Case.


Hope that helps!

Than you for your reply. So this is just for one client where they have the ticket number. And for others where we don’t have any Tickets number, will same code will work? We have many Templates being used as of now.

Hello  

If your use-case or requirement is "e-mail to case" where this client as well as others should be taken care of, then I would recommend to go with flow whose trigger condition will be "Inbound email".

As ServiceNow Flow Designer provides low-code or no-code capabilities along with debugging/audit/trace capabilities, hence my recommendation is to go with flow and adhere below steps:

Open Flow Designer and click Action tab and create new

Inputs - Click Create Input (top right)

 

Click + icon (purple) in left pane (Action Outline), search and select script, add input as shown below and paste below script:

 

(function execute(inputs, outputs) {
var emailSubject = inputs.email_subject;  // input variable name
var extTicketRegex = /EXT-\d+/i;
var match = emailSubject.match(extTicketRegex);
if (match && match[0]) {  
outputs.customer_ticket_number = match[0].toUpperCase(); //output variable name
}
})(inputs, outputs);


Scroll down to the bottom of the script and populate output variables:


Click Outputs in the left Action Outline and click Create Output in the middle

 

Enter Action Output Label and Name (automatically populated post Label entry) and click Exit Edit Mode

 

Use data pill picker icon to select Script step and it's only output

Click Test > Enter the subject and Hit Run Test and click View the execution details
Publish.

Now create a Flow in the Flow Designer and ensure it's Run as should be system user.
As this flow will only create new email received to Case, hence Flow Trigger = Inbound email with email conditions as body text does not contain Ref:MSG

Flow Action#1 - Flow Logic - If - Condition 1 as shown below Subject contains Ticket: EXT- and contains open tickets.

click + icon ion then and click Action and search the name of the action you just created

 

Click Add an Action under the action you just added and select look up records:

 

Click Flow Logic and add 

 

Click + on then and click create record

This entire if loop as Action#1 will ensure this client cases are created and duplicate are avoided.

You can have else loop for Action#1 where you just create Case which will work for other clients.

However if you want to use one email inbound action for all clients to create Case instead of flow then here is the script:

NOTE: Ensure the Action Type is New and validate the Receive type in the sys_email is New so that below only runs for new e-mail only:

 

(function executeAction(current, email) {
    
    var emailSubject = (email.subject || '') + '';
    var emailBody = (email.body_text || email.body || '') + '';
    var emailFrom = (email.from || '') + '';
    
    gs.info('Inbound Email Action - Processing email. Subject: ' + emailSubject); //NOTE: remove before prod
    
    // Extract external ticket number
    var extTicketRegex = /EXT-\d+/i;
    var match = emailSubject.match(extTicketRegex);
    var extTicketNumber = (match && match[0]) ? match[0].toUpperCase() : null;
    
    // Check for existing active case to avoid duplicates
    var grCase = new GlideRecord('sn_customerservice_case');
    var foundExisting = false;
    
    if (extTicketNumber) {
        gs.info('Inbound Email Action - EXT number found: ' + extTicketNumber); //NOTE: remove before prod
        grCase.addQuery('u_external_ticket_number', extTicketNumber);
        grCase.addQuery('state', 'NOT IN', '3,6,7'); //NOTE: validate state values
        grCase.query();
        if (grCase.next()) {
            foundExisting = true;
            gs.info('Inbound Email Action - Existing case found: ' + grCase.number); //NOTE: remove before prod
        }
    } 
    
    if (foundExisting) {
        // Append to existing case
        grCase.comments = 'Email received from ' + emailFrom + ':\n\n' + emailBody;
        grCase.update();
        gs.info('Inbound Email Action - Comment added to case: ' + grCase.number); //NOTE: remove before pr
    
	
	} else {
        // Create new case
        var newCase = new GlideRecord('sn_customerservice_case');
        newCase.initialize();
        newCase.short_description = emailSubject || '(no subject)';
        newCase.description = emailBody;
        newCase.contact_type = 'email';
        
        if (extTicketNumber) {
            newCase.u_external_ticket_number = extTicketNumber;
        }              
        
        var newSysId = newCase.insert();
        if (newSysId) {
            gs.info('Inbound Email Action - New case created: ' + newCase.number + ' (' + newSysId + ')'); //NOTE: remove before prod
        } else {
            gs.error('Inbound Email Action - Failed to create case from ' + emailFrom); //NOTE: remove before prod
        }
    }
    
})(current, email);

 


Hope that helps!