Uncle Rob
Kilo Patron

But... but... #KillEmail

Yes, kill email when you can. In reality, Some systems and processes may still have components depending on an email initiation.   Here are some examples from my own history.

- support@company.com, service@company.com, contactus@company.com etc addresses that are externally facing need workflow driven responses.   (this is common in the hospitality space)

- legacy system is a starting point and has no rest/soap integration capabilities

- highly specialized staff that, for cultural or practical reasons, only uses email + 1 or 2 specialized tools (traders, field service staff, doctors, lawyers, etc)

Sometimes we have no choice in our inputs, and its better to win small than not win.

Before We Begin

  • Understand Inbound Email Actions, especially Section 6, which outlines how to handle email variables.
  • Understand Service Catalog Script API.   For further research, you can look at the Script Include "Cart" on your dev instance.
  • It is advised that you create your own email address in your environment to handle the intake.   In my example I created "term@company.com".   We ended up creating this such that anyone emailing the address was also sending to company@servicenow.com without realizing it.   In this fashion both the original sender & term@company.com are retained.   A further benefit is you can make separate addresses per workflow you wish to trigger.  
  • Text analysis is your enemy.   As much as possible ensure that your sender automated, not a person.   If that's not possible, resist attempts to make programatic decisions based on user entered email text.

Example:   Email initiated Termination

I've already created a Catalog Item with 3variables: terminee, subject, emailbody (HTML)

I'm assuming that whatever person / system sending will include in the body "priority:high" if priority needs adjustment.

Its also important to note that I don't generally use the request layer, so I will *also* want to modify the sc_req_item

Inbound Action

Name:   Email Based Term

Target Table:   Requested Item [sc_req_item]

Type: New

Order:   Anything lower (numerically) than your existing Incident items

Condition: email.recipients.toLowerCase().indexOf("term@company.com") > -1   (checks to ensure its coming to the controlling email address)

createRequest();

function createRequest() {

  var cart = new Cart();   //calling the cart API

  var item = cart.addItem('eb89a3b937e7d200a2982863b3990eab');   //sys_id of the catalog item I want to fire

  cart.setVariable(item, 'subject', email.subject) //sets catalog variable to the email's subject

  cart.setVariable(item, 'emailbody', email.body_html);   //sets catalog variable to email's body

    var rc = cart.placeOrder();   //this launches the catalog item, and creates a request object.   rc = the request object

  updateRITM(rc.sys_id);   //call a function immediately to update the ritm.   This must be a nested function, otherwise inbound actions get weird.

          //also, we're passing the sys_id of the request so we know what RITM to grab.

}

function updateRITM(req){

  var ritm = new GlideRecord('sc_req_item');

  ritm.addQuery('request', req);   //req is what we passed from the previous function. the sys_id of the request.

  ritm.query();

  while (ritm.next()){

      ritm.u_customer = gs.getUserID();   //my ritm table separately tracks its own customer, since I don't use Request

      ritm.description = email.body_text;   //we're still in the inbound action so why not exploit?

      ritm.priority = email.body.priority;     //good example of how to exploit email body variables

      ritm.update();

  }

}

event.state="stop_processing";   //stop evaluating inbound actions. This is why I keep this record's order lower than my incident from email rules.

Key Take-Aways

  • It is possible, and even handy to trigger workflow from email
  • if you want to modify RITM post insert, use a nested function where-ever you're calling the Cart API
  • Make sure inbound action(s) evaluate before your Incident creation inbound actions
  • Use stop processing once the script is complete.
  • Don't be afraid to exploit email.body.variables... especially if the email source is automated.
25 Comments
kjain
Giga Expert
I have achieved this using workflow.
User186043
Tera Guru

Coming very late to this party, but managed to get these records to link after I found the workaround was creating empty RITMs.

var requestedItem;
function updateRITM(req){
   var ritm = new GlideRecord('sc_req_item');
   ritm.addQuery('request', req);   //req is what we passed from the previous function. the sys_id of the request.
   ritm.query();

   while (ritm.next()){
       ritm.u_customer = gs.getUserID();   //my ritm table separately tracks its own customer, since I don't use Request
       ritm.description = email.body_text;   //we're still in the inbound action so why not exploit?
       ritm.priority = email.body.priority;     //good example of how to exploit email body variables
       ritm.update();
       requestedItem = ritm.sys_id;
   }
}
current.sys_id = requestedItem;
current.content_type = 'email';
current.update();

Passing the RITM sys_id into the current.sys_id manages to correctly link the sys_email record and the sc_req_item. The only issue I have noticed is the sc_req_item numbers are skipping a number for some reason.

Randall Arnold
Giga Expert

The update() causes the skipped numbers.  I moved everything but the email-specific code to a workflow (where no update is necessary) and that solved the problem (it also allows me to use the same catalog item for email or portal data entry).  I also set "Assign a task number only upon insert (prevents unused numbers)" to True in system properties to prevent skipped numbers or orphan tickets.

Here's my IA code:

createRequest();

function createRequest() {
    var cart = new Cart(); //calling the cart API   
    var item = cart.addItem('375e7b56dbd033407137ab8b4b961923'); //Hyperion Report Requests
    cart.setVariable(item, 'request_summary', email.subject.toString());
    cart.setVariable(item, 'request_details', email.body_text.trim());
    var rc = cart.placeOrder(); //this launches the catalog item, and creates a request object.   rc = the request object
    updateRITM(rc.sys_id); //call a function immediately to update the ritm.   This must be a nested function, otherwise inbound actions get weird.     
}

function updateRITM(req) {
    //original code relocated to workflow   
    //copy email attachment to ticket
    GlideSysAttachment.copy('sys_email', sys_email.sys_id, 'sc_request', req);
}
Jaspal Singh
Mega Patron

@Robert Fedoruk 4 years now but still helped to get something tested in no time.

Just a suggestion seems a semi-colon is missed for line

cart.setVariable(item, 'subject', email.subject)

Harish Mulpuri
Kilo Contributor

Hi Friends,

 

It is not working as expected for me. It is always skipping one RITM number while creating. (Instead of RITM002, it is creating RITM003). I think as a result I am unable to get values of the current record in the workflow using current. Rest of all is working fine like attaching workflow and stuff.

Please help me with this.

Poorva Bhawsar2
Tera Contributor

I have written my email specific code in workflow, but still it is skipping RITM nos, and can you please tell me the exact name of this system property?

Nathan Okh
Mega Sage

Hello I found this helpful. 

I implemented this just as you wrote and a Request and Requested Item is created!

However I have a problem. I hope someone can help here.

Even though it creates the request, in inbox shows Target "(empty)"

find_real_file.png

find_real_file.png

 

I'm thinking its because there is no Insert command anywhere would that fix this?

createRequest();
function createRequest() {
	var cart = new Cart();   //calling the cart API
	var item = cart.addItem('7d525710dbf80b002809534e5e9619d5');   //sys_id of the catalog item I want to fire
	cart.setVariable(item, 'subject', email.subject); //sets catalog variable to the email's subject
	cart.setVariable(item, 'emailbody', email.body_html);   //sets catalog variable to email's body
	var rc = cart.placeOrder();   //this launches the catalog item, and creates a request object.   rc = the request object
	
	updateRITM(rc.sys_id);   //call a function immediately to update the ritm.   This must be a nested function, otherwise inbound actions get weird.

           //also, we're passing the sys_id of the request so we know what RITM to grab.

}

function updateRITM(req){
var ritm = new GlideRecord('sc_req_item');
	ritm.addQuery('request', req);   //req is what we passed from the previous function. the sys_id of the request.
	ritm.query();
while (ritm.next()){
	ritm.u_customer = gs.getUserID();   //my ritm table separately tracks its own customer, since I don't use Request
	ritm.description = email.body_text;   //we're still in the inbound action so why not exploit?
	ritm.priority = email.body.priority;     //good example of how to exploit email body variables
	ritm.update();

   }

}

event.state="stop_processing";   //stop evaluating inbound actions. This is why I keep this record's order lower than my incident from email rules.

 

Sree21
Tera Guru

Hello Harish, I have the same issue where RITM numbers are skipped. Were you able to find a solution to avoid skipping the numbers? 

Thank you

EdH994884433077
Tera Guru

same for me

Uncle Rob
Kilo Patron

5 years and 10,000+ views later, its time to revisit this topic.  But THIS time, with far more digestible email content.  This time, everything is contained within Flow Designer.

Love you all, and thanks for keeping this thread alive for so long.

IF this concept is still valuable to you, I ask that you like & share this content with your ServiceNow network.