Marty Zigman Marty Zigman
Prolecto Labs Accelerator Templates

Learn How to Automatically Populate NetSuite’s Email Composer Additional Recipients Sublist

CRM NetSuite Technical



This article is relevant if you seek to automatically populate NetSuite’s email composer with a list of email addresses.

Background

As we assist our clients in automating their billing, a frequent request is the ability to add more email addresses to the invoice processing distribution list. This is largely focused on enabling hands-free mass processing and distribution of transactions.

However, there are occasions when manual message crafting is necessary. NetSuite provides a native email composer that allows users to create communications manually. The core content of these emails can be efficiently generated using NetSuite’s template system.

Despite this, other time-saving capabilities are needed. Building on my 2020 article, Get Control over NetSuite’s Email Reply-To Address, and my 2016 article, on how to automatically add attachments, we aim to automatically add additional recipients to the email sublist. This automation will save time and reduce the risk of errors.

Add Additional Email Addresses to the Transaction

The key to adding additional email addresses for transaction processing (e.g., Invoices) is determining how you will store them. There are several approaches you can take.

In 2015, I discussed a method to Extend NetSuite’s Transaction Email Address List to handle this. The main idea is to create a custom field at the customer level that holds a semicolon-separated list of email addresses. Then, during invoice processing, populate NetSuite’s native {email} field with these addresses. The great news is that NetSuite will automatically send emails to these addresses if the {tobeemailed} checkbox is selected when the transaction is saved.

Once we identify the source of the email addresses we need, we can enhance NetSuite’s native email composer (communications) feature accordingly.

Click images to see them full-size for clarity.

SuiteScript to Populate Additional Email Recipients

With the source of additional email addresses identified, you can use the following pattern to implement a solution. The NetSuite Message Composer provides access to the source transaction it originates from, allowing you to easily look up the {email} field on that transaction. You can then parse this field into a list to populate NetSuite’s native ‘additional recipients’ sublist.

Note that while the ‘additional recipients’ list (otherrecipientslist) is not documented in NetSuite’s Help, it follows standard approaches for driving data into forms.

/*
 * Description: add more capability to a message when clicking 
 * the Email button inside the message subtab
 */

/**
 * @NApiVersion 2.1
 * @NScriptType UserEventScript
 * @NModuleScope Public
 */


define(['N/record', 'N/search', 'N/runtime', 'N/error'],

    function(record, search, runtime, error) {

        var scriptName = "article_message_ue_21.";

        /* --------------------------------------------------- */
        function beforeLoad(context) {

            var funcName = scriptName + "beforeLoad " + context.type + " "
                + context.newRecord.type + " " + context.newRecord.getValue("id")
                + " via " + runtime.executionContext;

            try {

                var REC = context.newRecord;

                //run only if in create on the user interface
                if (context.type != context.UserEventType.CREATE)
                    return;
                if (runtime.executionContext != runtime.ContextType.USER_INTERFACE)
                    return;

                //get the values on the url parametes to help see the composer source 
                var str ="";
                var params = context.request.parameters;
                log.debug(funcName,'params: '+JSON.stringify(params));

                var rootRecType = '';
                var recid = '';

                //use the following source pattern the help drive the value lookups
                if(!isEmpty(params.transaction)) {
                    recid = params.transaction;
                    rootRecType= 'TRANSACTION';
                }
                else if(!isEmpty(params.record)) {
                    recid = params.record;
                    rootRecType = 'CUSTOMRECORD';
                }
                else {
                    recid = params.entity;
                    rootRecType = 'ENTITY';
                }
                log.debug(funcName,'recid: '+recid);

                if(isEmpty(recid)){
                    log.debug(funcName, 'No record or transaction found');
                    return;
                }
                
                //now do the lookup work which will vary based on your solution
                var rectype = '';
                var email = '';
                if(rootRecType == 'TRANSACTION') {
                    lookupResults = search.lookupFields({
                        type: search.Type.TRANSACTION,
                        id: recid,
                        columns: ['recordtype', 'email']
                    })
                    rectype = lookupResults.recordtype
                    email = lookupResults.email

                }
                else if(rootRecType == 'CUSTOMRECORD'){
                    rectype = params.recordtype;
                }
                else if(rootRecType == 'ENTITY'){
                    rectype = params.entitytype;
                }
                log.debug(funcName,'rectype: '+ rectype);
                log.debug(funcName,'email: '+ email);

                if(isEmpty(rectype)){
                    log.debug(funcName, 'No record type found');
                    return;
                }

                //in this solution, we know the email list is semicolon separated
                var emaillist = email.split(';')
                log.debug(funcName,'emaillist: '+ JSON.stringify(emaillist));
               
                //add to the email sublist the emails that were selected               
                var line = 0 
                emaillist.forEach((element) => {
                    log.debug(funcName,'emaillist: '+ line + ':' + element);
                    if (element){
                        REC.insertLine({
                            sublistId: 'otherrecipientslist',
                            line: line
                        });
                        REC.setSublistValue({
                            sublistId: 'otherrecipientslist',
                            fieldId: 'email',
                            line: line,
                            value: element
                        });
                        // use 'cc' or 'bcc' for other fields 
                        REC.setSublistValue({
                            sublistId: 'otherrecipientslist',
                            fieldId: 'toRecipients',
                            line: line,
                            value: 'T'
                        });
                    }
                    line++
                }); 
            } 
            catch (e) {
                log.error(funcName, e);
            }
        }
        /* --------------------------------------------------- */
        function isEmpty(val) {
            if(typeof(val) == 'object'){
                for(var key in val) {
                    if(val.hasOwnProperty(key))
                        return false;
                }
                return true;
            }
            else{
                return (val == null || val == '' || val == undefined);
            }
        }
        
        return {
            beforeLoad:	beforeLoad,
        }
    });

If you prefer to download this code, click here.

Drive Enhanced NetSuite Email Processing

This solution aims to inspire NetSuite Administrators with SuiteScript experience. It leverages the capabilities of the NetSuite extensibility platform to create better user experiences. It’s important to remember that NetSuite is designed to be enhanced, meaning we’re never truly stuck. With innovation, we can always find a way to get the job done.

If you found this article relevant, feel free to sign up for notifications to new articles as I post them. If you are the type of professional who would enjoy being part of a team that gets to produce these solutions every day, let’s have a conversation.

Marty Zigman

Holding all three official certifications, Marty is regarded as the top 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 30 years, Marty has produced leadership in ERP, CRM and eCommerce business systems. Contact Marty to set up a conversation.

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

About Marty Zigman

Marty Zigman

Holding all three official certifications, Marty is regarded as the top 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 30 years, Marty has produced leadership in ERP, CRM and eCommerce business systems. Contact Marty to set up a conversation.

Biography • Website • X (Twitter) • Facebook • LinkedIn • YouTube

2 thoughts on “Learn How to Automatically Populate NetSuite’s Email Composer Additional Recipients Sublist

  1. Víctor García says:

    Good morning,

    First of all, thank you for all the great content, I feel like you have been helping us all out through our NetSuite career.

    Second of all, I’m having an issue trying to implement a solution that is similar to this.
    I have tried deploying a UserEvent script on the message record. I’m receiving an invalid sublist operation error. I have tried deploying a CS on the message record but to no avail. Tried also to deploy it in an entity userevent, but also did not work. I am sure there must be something I’m missing.

    I would be very grateful if you could shed some light into this issue.

    Best regards!

  2. Marty Zigman says:

    Hello Victor. Please send over the code snippet (or screenshot) so that we can have a review.

    Marty

Leave a Reply

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