Marty Zigman

Conversations with Marty Zigman

Certified Administrator • ERP • SuiteCloud

Learn how to Automatically add an Attachment to a NetSuite Message Object

NetSuite Technical

Tags: , , ,

This article is relevant if you want to automatically add an attachment to a NetSuite email message object.

Background

We are solving a number of client challenges with our Content Renderer Engine (CRE) which allows you to get much more data to a NetSuite Advanced PDF or HTML template. In many cases, because of the power of this tool, we are replacing the conventional Advanced PDF invoice and other standard transactional objects. Our CRE tool allows you to flexibly create file and email output. A client recently wanted to preserve the native NetSuite message object but they wanted all the goodness of CRE. In this case, they wanted a simple way to ensure that a file attachment was added to the native NetSuite message object so that users could have freedom to craft their own email yet ensure they have branded content as a file attachment.

SuiteScript 1.0 Pattern to Add Attachment to NetSuite Message

The following code pattern can be used as inspiration for any message object that needs a file attachment. At the same time, it illustrates how, with just a few lines of code , you can generate CRE profile based content. In addition, see the code pattern to turn off and hide NetSuite’s default message behavior which will add a transaction attachment.

//------------------------------------------------------------------------------
//Function:		cre_EmailTemplate_BeforeLoad
//Record:		message
//Type:			BeforeLoad
//Description:			On the related transaction, generate the cre attachment and
//				add as attachments to current message
//------------------------------------------------------------------------------
function cre_EmailTemplate_MsgBeforeLoad(type, form, request) {
    //check proper context
	if (type != 'create') return;
    var context = nlapiGetContext();
    if (context.getExecutionContext() != 'userinterface') return;
    if (!request) return;

    // get the query string parameters; this message example only works with transactions
	// ne is a custom function to return back a value if an expression returns back empty
    var recid = ne(request.getParameter("transaction"),'');
    if (recid.length == 0) return;

	//here, we have a custom script parameter holding a JSON structure binding transactions
	//to specific types of CRE profile templates.
    var rectype = nlapiLookupField('transaction', recid, 'type', false);

    var cre_trx_binding = JSON.parse(ne(context.getSetting('SCRIPT', 'custscript_cre_transaction_binding'),'{}'));
    var cre_profileid = cre_trx_binding[rectype];

    //only act on transactions that have a specific binding to CRE
	if (cre_profileid.length == 0) return;

	var error_list = [];

    //produce CRE output (effectively a PDF file)
    try
    {
        var creProfile = new CREProfile(cre_profileid);
        creProfile.Translate(recid);
        creProfile.Execute();
    }
    catch(e)
    {
		var str = "There was trouble generating the CRE file: " + recid + '-->' + cre_profileid; + '; error: ' + e.getCode();
		nlapiLogExecution("ERROR", 'could not create cre ouput', str);
		error_list.push("There was an error creating the CRE file. " + str);
    }

	if (error_list.length > 0){
		return;
	}

	//we should have file output
    var file_obj = null;
    var attachment_list = [];
    var foldername = cre_getFolderName(TEMPLATE_FOLDER_ID);

    if (creProfile.fields.DocumentName.translatedValue) {
        try
         {
          file_obj = nlapiLoadFile(foldername +'/' + creProfile.fields.DocumentName.translatedValue);
         }
         catch(e)
         {
             var str = "There was trouble looking up CRE output file: " + creProfile.fields.DocumentName.Value + '-->' + creProfile.fields.DocumentName.translatedValue; + '; error: ' + e.getCode();
             nlapiLogExecution("ERROR", 'could not create document', str);
             //syntax template does not exist. Return this one.
             error_list.push("There was an error creating the CRE attachment. " + str);
         }
    }

	//get the file object and add it to the attachment list array
    if (file_obj){
        nlapiLogExecution('DEBUG', 'fetched file' + file_obj.getName() + '; id:' +  file_obj.getId() + '; type:' + file_obj.getType() );
        attachment_list.push(file_obj.getId());
    } else {
        nlapiLogExecution('DEBUG', 'Missing fetchd file; return');
        error_list.push("There was an error attaching the CRE file.");
    }

	//add the attachment to the oject
    if (attachment_list.length > 0){
        for (var m=0; m<attachment_list.length; m++){
            nlapiSelectNewLineItem('mediaitem');
            nlapiSetCurrentLineItemValue('mediaitem', 'mediaitem', attachment_list[m]);
            nlapiCommitLineItem('mediaitem');
        }
    } else {
        nlapiLogExecution('DEBUG', 'attachment_list is empty');
        error_list.push("Expected an attachment and found none.");
    }

    // now enhance the default CRE message system to remove the default transaction checkbox so they don't send
    // netsuite's default message.
    var html = "";
    html += '<SCRIPT language="JavaScript" type="text/javascript">\r\n';
    html += "function bindEvent(element, type, handler) {if(element.addEventListener) {element.addEventListener(type, handler, false);} else {element.attachEvent('on'+type, handler);}} \r\n";
    html += "</SCRIPT>\r\n";
    html += '<SCRIPT language="JavaScript" type="text/javascript">\r\n';
    html += "function wload() \r\n{\r\n";
    html += "nlapiSetFieldValue('includetransaction', 'F');\r\n";
    html += "var fld = nlapiGetField('includetransaction');\r\n";
    html += "if (fld){fld.setDisplayType('hidden');};\r\n";
    html += "var fld = nlapiGetField('emailpreference');\r\n";
    html += "if (fld){fld.setDisplayType('hidden');};\r\n";
    if (error_list.length > 0){
        html += "alert('Warning: there appears to be an error fetching attachments. Please review the attachment list before sending.\\n\\n"+error_list.join('\\n')+"');\r\n";
        nlapiLogExecution('ERROR', 'Error fetching attachments', JSON.stringify(error_list));
    }
    html += "}\r\n";
    html += "</SCRIPT>\r\n";
    html += '<SCRIPT language="JavaScript" type="text/javascript">\r\n';
    html += 'bindEvent(window, "load", wload);\r\n';
    html += "</SCRIPT>\r\n";
    var field0 = form.addField('custpage_client_html', 'inlinehtml', '',null, null);
    field0.setDefaultValue(html);
}

Drive NetSuite To Fit Your Specific Requirements

NetSuite’s platform affords us many opportunities to streamline our day-to-day operational usage while increase our capacity to act quickly — this spells into lower cost and higher profits. If you have a unique requirement and wish to get more out the NetSuite platform, let’s have a conversation.

Marty Zigman LinkedIn

Marty Zigman

Holding three official certifications, Marty is widely recognized as a top NetSuite expert and leads a team of senior professionals at Prolecto Resources, Inc. A former Deloitte & Touche CPA and technology executive with CTO roles, he brings over 35 years of leadership in ERP, CRM, and eCommerce business systems. Contact Marty to engage directly.

BiographyYouTubeLinkedInX (Twitter)

5 thoughts on “Learn how to Automatically add an Attachment to a NetSuite Message Object

  1. how can I attach a file in the file sublist of any transaction in 2.0. I have tried the below code but its giving error as :”SSS_INVALID_SUBLIST_OPERATION”,”message”:”You have attempted an invalid sublist or line item operation. You are either trying to access a field on a non-existent line or you are trying to add or remove lines from a static sublist.

    Code:
    var attachment_list = new Array();
    attachment_list.push(fileObj.id);
    var nsRecord = record.load({
    type : record.Type.INVOICE,
    id : i_INV_InternalID,
    isDynamic: true
    });
    var lineCount = nsRecord.getLineCount({
    sublistId: ‘mediaitem’
    });
    log.debug(‘lineCount:’,lineCount);
    //return;
    nsRecord.selectNewLine({
    sublistId: ‘mediaitem’
    });

    nsRecord.setCurrentSublistValue({
    sublistId: ‘mediaitem’,
    fieldId: ‘mediaitem’,
    value: attachment_list[0]
    });

    nsRecord.commitLine({
    sublistId: ‘mediaitem’
    });

    var success = nsRecord.save({
    enableSourcing: true,
    ignoreMandatoryFields: true
    });

    Reply
  2. Hello Marty.

    Thanks for this. Is there a way to automatically include several email addresses in the email window?

    Thanks a lot.

    Reply
  3. For anyone working on attaching additional email and file to the message object, the easiest way I found is to use the search module to get additional emails and file ids to attach to message:
    Code:
    Part I for the additional emails
    First get the emails form a custom field, in my case I have a custom filed in the customer record to save the emails delimited by commas

    *******************************
    function addCCRecipients(REC, rootRecType, recid) {
    var customerId = null;

    // Get the customer ID from the transaction itself
    if (rootRecType == ‘TRANSACTION’) {
    try {
    var lookupResults = search.lookupFields({
    type: search.Type.TRANSACTION,
    id: recid,
    columns: [‘entity’]
    });

    if (!isEmpty(lookupResults.entity)) {
    customerId = lookupResults.entity[0].value;
    }
    } catch (lookupError) {
    return; // Exit this function
    }
    } else if (rootRecType == ‘ENTITY’) {
    customerId = recid;
    }

    if (!isEmpty(customerId)) {
    try {
    // Look up the additional emails from the customer record
    var additionalEmails = search.lookupFields({
    type: search.Type.CUSTOMER,
    id: customerId,
    columns: [‘custentity_add_emails’]
    });

    var emailsString = additionalEmails.custentity_add_emails;

    if (!isEmpty(emailsString)) {
    // Split the email string by multiple possible separators[ people struggle with simple instructions:-(]
    var regex = /\s*[,;]\s*/;
    var emailList = emailsString.split(regex);

    // Add each email to the CC list like you would for a line item
    var line = 0;
    emailList.forEach((email) => {
    email = email.trim();
    if (email) {
    try {
    REC.insertLine({ sublistId: ‘otherrecipientslist’, line: line });
    REC.setSublistValue({ sublistId: ‘otherrecipientslist’, fieldId: ’email’, line: line, value: email });
    REC.setSublistValue({ sublistId: ‘otherrecipientslist’, fieldId: ‘cc’, line: line, value: true });
    line++;
    } catch (emailError) {
    // Continue with the next email
    }
    }
    });
    }
    } catch (emailsError) {
    // Error processing additional emails – continue
    }
    *******************************
    Part II for the file attachment

    function attachFilesToEmail(REC, rootRecType, recid) {
    if (rootRecType != ‘TRANSACTION’ || isEmpty(recid)) return;

    try {
    /* Search for files attached to a transaction and get the file id,
    in my case its the same transaction the message object is on
    can be modified for any record really q*/
    var fileSearch = search.create({
    type: ‘transaction’,
    filters: [
    [‘mainline’, ‘is’, ‘T’],
    ‘AND’,
    [‘internalid’, ‘anyof’, recid]
    ],
    columns: [
    search.createColumn({ name: ‘formulanumeric’, formula: “{file.internalid}” }),
    search.createColumn({ name: ‘formulatext’, formula: “{file.name}” })
    ]
    });

    var searchResults = fileSearch.run().getRange({ start: 0, end: 100 }); // you’re not attaching 100 files, right?

    if (searchResults && searchResults.length > 0) {
    var attachmentLine = 0;

    // Add each file as an attachment to the email
    searchResults.forEach(function(result) {
    try {
    var fileId = result.getValue({ name: ‘formulanumeric’, formula: “{file.internalid}” });
    var fileName = result.getValue({ name: ‘formulatext’, formula: “{file.name}” });

    if (fileId) {
    REC.insertLine({ sublistId: ‘mediaitem’, line: attachmentLine }); // attach to mediaitem sublist just like any other line item
    REC.setSublistValue({ sublistId: ‘mediaitem’, fieldId: ‘mediaitem’, line: attachmentLine, value: fileId });
    attachmentLine++;
    }
    } catch (fileErr) {
    // Continue with next file
    }
    });
    }
    } catch (searchError) {
    // Error searching for attached files – continue
    }
    }

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *