Learn how to Implement a NetSuite Email Plug-in to Automate Order Processing

This article is relevant if you are seeking to automate Netsuite driven by email processing.

Background

One of our senior NetSuite consultants is working with a client in the premiums business who has a complex order entry process. The client’s customers need to provide artwork and other materials to drive manufacturing and order fulfillment. Our consultant has done a great job enhancing the order entry process to collect all the specialized information. This work alone has driven down considerable time and mistakes previously in their pre-NetSuite implementation processes.

However, he wanted to go further.  When order entry appears all properly setup, and related artwork and materials have arrived (for a bit more background, the art work image assets are managed through a Box.com integration), the client would like the customer to approve the order. They call this a Proof Approval. Recognizing that NetSuite has now implemented an Email Plug-in Framework, our savvy senior consultant developed the idea that an email could be generated to the client with all the information about the order to produce the “proof”. If the client’s customer is satisfied with the proof, all they would need to do is reply with one word: “Approved”.

From this single email, the client gets confirmation that all is in good to go and production can begin.  The client’s customer will have the latest production configuration handy without needing an account login — this means that return times can be very fast because email is ubiquitous and withing reach. It also means that the process is low maintenance because no other setup is needed to produce customer coordination.

How to Implement the NetSuite Email Plug-In


The NetSuite email plug-in implementation is straight forward if you are comfortable in SuiteScript. In my mind, the Email Plug-in looks like a traditional NetSuite Script Definition and then a different method for Script Deployment. Here are key differences:

  1. Scripts are referenced via Customization, Plug-Ins, Plug-In Implementations. Select “Email Capture” for the type.
  2. Select your script file under the Scripts, Implementation. Notice there is no function reference. The script definition expects one “function process(email){}” as your entry point.  See code below.

  1. The deployment is handled under Customization, Plug-ins, Manage Plug-ins. Check the box to the name of your definition and use the provided email address to listen to requests to fire your script.

Sample Code to process “Approved” response from Customer

The script below has been simplified to remove error handling and other logic checking to help you see the basic code pattern. The trick here is to understand how the body of the email will contain content you expect. In our case, we have asked the customer to reply “Approved” or “Rejected” and nothing more. As such, we look in the first parts of the email and ignore the rest.

//set some constants for our custom status values
var CONST_ARTSTATUS_PROOF_REJECTED	= 9;
var CONST_ARTSTATUS_PROCESSED 		= 4;

// find order# in the email body before we do anything more; reference status field
var CONST_TEXT_LABEL_MATCH = "ABC Order#";
var CONST_ORDER_STATUS_FIELD = "custbody_abc_trans_artstatus";

// look in the first x characters of body for match and disposition status to change order to
var CONST_TEXT_CONDITIONAL_MATCH = [["approve", CONST_ARTSTATUS_PROCESSED], ["reject",CONST_ARTSTATUS_PROOF_REJECTED]];
var CONST_TEXT_MATCH_CHARACTERS  = 100;  // amount of email body text to inspect

// Email Plugin entry point
function process(email) {
	var subject  = email.getSubject();
	var textbody = email.getTextBody();

	// find the order number in the body
	// note: match_text is a custom function not shown here.  However, regex works great
	var order_num = match_text(textbody, CONST_TEXT_LABEL_MATCH);

	if (order_num.length == 0) return;  // do no work; not an email we can act on

	//okay, we found an order ID in the email body.  Proceed to see if it is approved
	nlapiLogExecution('DEBUG', 'found order_num', order_num);

	// only match the first x characters of the message body as this is where our instructions
	// are to reply.  Anything deeper is not right.
	var match_textbody = textbody.substring(0, CONST_TEXT_MATCH_CHARACTERS).toLowerCase();

	// look for the order number and watch the current status relative to new status
	var filters = new Array();
	filters[0] = new nlobjSearchFilter('tranid', null, 'is', order_num);
	filters[1] = new nlobjSearchFilter('mainline', null, 'is', 'T');

	var columns = new Array();
	columns[0] = new nlobjSearchColumn(CONST_ORDER_STATUS_FIELD);

	//look for a candidate salesorder
	var results = nlapiSearchRecord('salesorder', null, filters, columns);
	if (results != null && results.length> 0 ) {
		var tran_id = results[0].getId();
		var current_status = results[0].getValue(CONST_ORDER_STATUS_FIELD);

		var new_status = match_text(match_textbody, CONST_TEXT_CONDITIONAL_MATCH);
		//function returns an element of the array if matched

		if (new_status.length > 0) {
			//process if the value is different
			if (new_status[0] != current_status){
				//we found a new value.  Let's update the sales order

				var order_record = nlapiLoadRecord('salesorder', tran_id);
				order_record.setFieldValue(CONST_ORDER_STATUS_FIELD, new_status[0]);
				nlapiLogExecution('DEBUG', 'Set new status', new_status[0]);
				nlapiSubmitRecord(order_record);
			};
		};
	};
};

Conclusion

The NeSuite Platform continues to get more robust giving customers more capacity to invent solutions that increase revenue and lower costs. If you would like to develop a NetSuite Email Plug-in or you want to work with professionals that can innovate with NetSuite tools, let’s have a conversation.

Be Sociable, Share!

Marty Zigman

Holding all three official certifications, Marty is Southern California's NetSuite expert and leads a team of senior professionals at Prolecto Resources, Inc. He is a former Deloitte & Touche CPA and has held CTO roles. For over 25 years, Marty has produced leadership in ERP, CRM and eCommerce business systems. Contact Marty to setup a conversation.

More Posts - Website - Twitter - Facebook - LinkedIn - Google Plus - YouTube

| Tags: , , , , | Category: CRM, ERP, NetSuite, Technical | 8 Comments

8 Comments

  1. Quentin Pongrass
    Posted April 11, 2017 at 1:27 pm | Permalink

    Is it possible to generate a unique email capture on the fly like NetSuite does every time you email from a record?

  2. Posted April 12, 2017 at 4:46 am | Permalink

    Hello Quentin,

    Is is possible to generate email when ever a record is committed. That email then can be attached to the record in some manner. But I am not sure this answers what you are asking. Can you say more?

    Marty

  3. Quentin Pongrass
    Posted April 12, 2017 at 6:41 am | Permalink

    Thanks for replying, Marty.

    I actually would like to retract my initial question and replace it with this one:

    Is it possible to use nlapiSendEmail (or other equivalent if it exists) and have the author set as someone other than a NetSuite internalid reference?

    NetSuite does this. For example, if a PO is emailed from within NetSuite to an outside party and that person responds, the response email is captured on the PO record and author is shown as the person who responded.

  4. Posted April 13, 2017 at 5:06 am | Permalink

    We generally have not found this to be a problem in our client situations. I understand that the nlapSendEmail requires an author to be a NetSuite employee internal ID. Sometimes, our clients create fake employee records simply to help manage email. Once the outbound message goes out, NetSuite crafts special email addresses to have the email threading working. To get email working other ways, I suspect you may want to call an external service. Naturally, this will lack the built-in message tracking.

  5. Quentin Pongrass
    Posted April 13, 2017 at 6:34 am | Permalink

    Appreciate your time, Mr. Zigman.

    I figured I would be limited to creating fake employee records.

    How about an easier one: can I reference multiple custom records on the nlapiSendEmail like the following:

    var records = new Array();
    records[‘recordtype’] = ‘customrecord239’
    records[‘record’] = ‘1934’;
    records[‘recordtype’] = ‘customrecord240’
    records[‘record’] = ‘5348’;
    nlapiSendEmail(‘35302’, fromAddress, subject, body, null, null, records, null, null, null, null)

    This code doesn’t work but also doesn’t throw an error, so I figure I’m just making a very amateur oversight.

  6. Posted April 20, 2017 at 5:31 am | Permalink

    Quentin,

    Create your record array as follows:

    var records = new Array();
    records[‘customrecord239’] = ‘1934’;
    records[‘customrecord240’] =‘5348’;

    Marty

  7. Gabriel Lawrence
    Posted July 19, 2017 at 11:53 am | Permalink

    Hi Marty,

    I’m trying to get NetSuite to forward the initial customer message with attachment to the support staff that is auto assigned to a support case. (I’d like the support staff to receive the attachment in their email instead of having to login to NetSuite to see it)

    Do you know if that’s possible through workflow or script on the case, or would it be a better approach to use the email plugin to forward the message to the support staff and forward it the the inbound case capture address as well? (If that’s possible either)

    Thanks,

    Gabe

  8. Posted August 3, 2017 at 12:52 pm | Permalink

    Hi Gabriel,

    You likely need to get control over the email distribution. You would have to turn off NetSuite’s native one and then craft a trigger based on a UserEvent to email with attachments. We do this kind of thing frequently with script. You may be able to do it with Workflow if you can get to the attached file sublist of the support case.

    Marty

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>