Anyone have a good way to deal with Undelivered Em...
# general
r
Anyone have a good way to deal with Undelivered Emails to make them more visible? I know I could create a Dashboard portlet for people to look up or have the contents of that search for the day send to a group of people. That said, those seem like poor ways to deal with it. Is there seriously no way other than the Undelivered Emails search to know if an email you send from a case or invoice or whatever bounces? I'm hoping I'm missing something simple because it seems really odd there isn't some sort of automated notification to say "hey your email bounced, you should go deal with it." Granted, there should be a low number of emails in Undelivered, but it doesn't seem efficient for CS people to have to look at that a couple times a day to ensure the emails they're sending go through.
j
Could create a search on the 'Sent email List' with failure reason as a filter. Add this as a reminder on their home page / create an email notification from the results
j
I wrote a scheduled script that runs every <n> minutes and sends us notifications on things that failed to send
Copy code
function undeliveredEmailNotifications(context) {
    	        	
    	// Number of seconds' worth of time to check for undelivered emails.        	
    	var seconds = 14400; // Four hours
    	//seconds = 604800; // one week
    	//seconds = 1296000; // two weeks

    	// Start by getting the names & email addresses of all current employees 
    	// so we can check for emails sent by them that were undelivered.
    	var employee_search = search.create({
			type: 'employee',
			filters: [
				['isinactive', 'is', 'F'], 
				'AND', 
				['hiredate', 'onorbefore', 'today'], 
				'AND', 
				[['releasedate', 'isempty', ''], 'OR', ['releasedate', 'after', 'today']]
			],
			columns: [
				search.createColumn({name: 'internalid', label: 'ID'}),
				search.createColumn({name: 'entityid', label: 'Name'}),
				search.createColumn({name: 'email', label: 'Email'})
			]
		});
    	
    	var employees = [];
    	
    	employee_search.run().each(function(result) {
    		
    		employees[result.getValue('entityid')] = {internalid: result.getValue('internalid'), email: result.getValue('email'), undelivereds: []};
    		return true;
    		
    	});
    			    			
    	if(log_level == 1) log.debug({title: 'undeliveredEmailNotifications', details: 'employees: ' + JSON.stringify(employees)});    
    	
    	// Add a catch-all for any emails "sent from" something that doesn't look like
    	// the name of an employee.
    	employees['catchall'] = {email: 'catchall', undelivereds: []};
    	
    	// Search undelivered emails.
    	var undelivered_email_search = search.create({
			type: 'undeliveredemail',
			filters: [['formulanumeric: (CAST(current_date AS DATE) - CAST({sentdate} AS DATE)) * 86400', 'lessthanorequalto', seconds]],
			columns: [
				search.createColumn({name: 'sentdate', label: 'Sent Date'}),
				search.createColumn({name: 'reason', label: 'Reason'}),
				search.createColumn({name: 'subject', label: 'Subject'}),
				search.createColumn({name: 'from', label: 'From'}),
				search.createColumn({name: 'recipients', label: 'Recipients'})
			]
		});
    	
    	// For each undelivered email, add it to the list for the employee who sent it.
    	// Also add it to mt list if not already there...
    	undelivered_email_search.run().each(function(result) {
    		
    		var from_string = result.getValue('from');
    		    		
    		var from_name = '';
    		var from_email = '';
    		
    		// Remove quote marks (in case there are some).
    		from_string = from_string.replace(/"/g,"");
    		
    		// Separate out the NAME from the EMAIL (e.g. Bob Smith <bob@smith.com>)
    		if(from_string.indexOf('<') !== -1) {
    			
    			var from_string_parts = from_string.split('<');    			
    			from_name = from_string_parts[0].trim();    			
    			from_string_parts = from_string_parts[1].split('>');
    			from_email = from_string_parts[0].trim();
    			
    		} else {
    			
    			from_name = from_string;
    			from_email = from_string;
    			
    		}
    		
    		if(log_level == 1) log.debug({title: 'undeliveredEmailNotifications', details: 'Found an undelivered email from ' + from_name});
    		
    		// Check to see if this is an identified employee name.
    		if(employees[from_name] != null) {
    			
    			employees[from_name].undelivereds.push({
    				from: from_string,
    				sentdate: result.getValue('sentdate'),
    				reason: result.getValue('reason'),
    				subject: result.getValue('subject'),
    				recipients: result.getValue('recipients')
    			});
    			
    		} else {
    			
    			// Add to the catch-all.        			
    			employees['catchall'].undelivereds.push({
    				from: from_string,
    				sentdate: result.getValue('sentdate'),
    				reason: result.getValue('reason'),
    				subject: result.getValue('subject'),
    				recipients: result.getValue('recipients')
    			});
    			
    		
    		}
    		
    		return true;
    		
    	});
    			
    	// Send notifications to employees that their emails bounced.
    	for(var employee_name in employees) {
    			    			
    		if(log_level == 1) log.debug({title: 'undeliveredEmailNotifications', details: 'employee_name is ' + employee_name});    	
    		
    		// What is their ID?
    		var internalid = <my_id>; // catchall email goes to me.
    		
    		if(employee_name != 'catchall')
    			internalid = employees[employee_name].internalid;
    		    		
    		// Did they get any bounces?
    		if(employees[employee_name].undelivereds.length > 0) {
    			    			
    			if(log_level == 1) log.debug({title: 'undeliveredEmailNotifications', details: employee_name + ' has undelivereds'});
    			
    			// Build the message.
    			var subject = 'Undelivered Email: ' + employee_name;    			
    			var body = 'The following recent email sent through NetSuite was undelivered:<br/><br/>';
    			
    			if(employees[employee_name].undelivereds.length > 1) {
    				
    				subject = 'Undelivered Emails: ' + employee_name;
    				body = 'The following recent emails sent through NetSuite were undelivered:<br/><br/>';
    				
    			}
    			    			
    			for(var i = 0; i < employees[employee_name].undelivereds.length; i++) {
    				
    				body += 'Date: ' + employees[employee_name].undelivereds[i].sentdate + '<br/>';
    				body += 'From: ' + employees[employee_name].undelivereds[i].from + '<br/>';
    				body += 'Subject: ' + employees[employee_name].undelivereds[i].subject + '<br/>';
    				body += 'Recipients: ' + employees[employee_name].undelivereds[i].recipients + '<br/>';
    				body += 'Reason: ' + employees[employee_name].undelivereds[i].reason + '<br/><br/>';
    				
    			}
    			    			
    			if(log_level == 1) log.debug({title: 'undeliveredEmailNotifications', details: 'sending an email from Jen to ' + internalid + ' with body ' + body});
    			              
    			email.send({
    				author: netsuite_notifications,
    				recipients: internalid,
    				subject: subject,
    				body: body
    			});
    			
    		}
    		
    	}
    	
    }
r
@Jono I'm not seeing that as an available field on the Sent Email List. Are you thinking of the Undelivered Email search?
@jen that is an interesting idea, thanks. The thing I forgot to mention is that our emails generally have a "from" being a generic email (orders@abccompany.com) and if I'm reading the code right, the notifications would go into this generic email right? Or is there somewhere in the back end where the person who really sent it is exposed? Not a coder so I don't know how to check. There's not anything like that in the Saved Search node.
j
Yeah so the notifications would have to get sent someplace sensible. Mine go to the author.
you can override that tho
I may have flipped out a bit when I discovered we weren't notified in any way whatsoever when something bounces.
it's a HUGE oversight as far as I'm concerned
#justnetsuitethings
😬 1
r
I agree it seems like a pretty big gap.
Appreciate the insight.
j
@RJMNS I mocked one up with the 'Sent Email List'
t
It is possible to check for undelivered email using SuiteQL, and there's a query for doing so in this post: https://timdietrich.me/blog/netsuite-suiteql-email/ You could use that in a work it into a scheduled script, similar to what @jen is doing.
d
@jen Thanks for that tid-bit. Similarly, I've got a piece of code that removes an employee from an being flagged as Hard Bounced, if anyone is interested. Requires a scheduled script and a Page Init on the employee record. It's a little bit of a hack, but it's a lifesaver for our accounting department, since they go on that list every now and then. I'm wondering now if I can turn this into a RESTlet, so that I don't have to click the link to "un-hard-bounce" them.
r
Thanks @Jono. I had just checked in the results list and not criteria. Odd they let you use that field as a criterion, but not as a Result.