Stripping attachments from inbound emails

poyntzj
Kilo Sage

A while ago I wrote a small Business Rule that stripped out image attachments from emails.

Works pretty well, but it was not restricted to working on embedded files, so a user attaching a genuinely small image may find it stripped.

I have revisited this and i have now come up with an updated version - running on Fuji.

this will only process images that are embedded and not attached.

This code strips all files that are below 7500 bytes - I would normally use less, but the company logo where I am now is just under this size.

I have tested with emails in from O365, outlook, gmail, vpop

Name:   Remove small embedded image attachments

Table:   sys_email

When:   After

Insert: Checked

function onAfter(current, previous) {

    //This function will be automatically called when this rule is processed.

   

  var strText = current.body;

  var regex = /sys_attachment\b[\W.]do\b[\W?]sys_id=\w{32}/igm;

  var arrMatches =[];

  // now try to find a match

  // the error is setting the value arrMatches to something as otherwise it breaks

  try

  {

  arrMatches = strText.match(regex);

  }

  catch(e)

  {

  arrMatches = 'something';

  }

  if (arrMatches != null)

  {

  for (i=0;i<arrMatches.length;i++)

  {

  // get the Sys Attachment Sys_id

  var strSASys_id = arrMatches[i].substr(arrMatches[i].length - 32);

  // now look for the record

  // needs to be the type contains image (as we are only removing those)

  // and size needs to be below 7500.

  // this figure has been chosen as an ARM logo comes in at 7079

  // normally I would suggest 5000

  var sagr = new GlideRecord('sys_attachment');

  sagr.addQuery('sys_id',strSASys_id);

  sagr.addQuery('content_type','CONTAINS','image');

  sagr.addQuery('size_bytes','<','7500');

  sagr.query();

  if (sagr.next())

  {

  sagr.deleteRecord();

  }

  }

  }

}

and a tweaked attachment mail script that we will use

the latest attachments are at the top

printattachments();

function printattachments() {

  // set defaults and intial settings

  var i=0;

  var strAtt = '';

  // query against the attachment table and see if there are any attachments

  var gr = new GlideRecord('sys_attachment');

  gr.addEncodedQuery('content_typeNOT LIKEmessage^content_typeNOT LIKEcalendar^table_sys_id='+current.sys_id);

  gr.orderByDesc('sys_updated_on');

  gr.query();

  while (gr.next())

  {

  // increase the count of attachments and then create a message with a HREF link to each attachment

  i++;

  strAtt += 'Attachment: <a href="http://'+gs.getProperty("instance_name")+'.service-now.com/sys_attachment.do?sys_id=' + gr.sys_id + '">' + gr.file_name + '</a><br>';

  }

  // Now check to see if there are any attachments and anything to add to the notification

  // if there are no attachments, add nothing to the ticket.

  if (i > 0)

  {

  // there are attachments, now lets get the ticket type

  if (current.sys_class_name == 'incident')

  strTicket = 'Incident';

  else if (current.sys_class_name == 'sc_request')

  strTicket = 'Request';

  else if (current.sys_class_name == 'sc_req_item')

  strTicket = 'Order';

  else if (current.sys_class_name == 'change_request')

  strTicket = 'Change Request';

  else if (current.sys_class_name == 'change_task')

  strTicket = 'Change Task';

  else if (current.sys_class_name == 'problem')

  strTicket = 'Problem';

  else if (current.sys_class_name == 'problem_task')

  strTicket = 'Problem Task';

  else

  strTicket = current.sys_class_name;

  // now lets see if we have 1 or more attachments

  if (i==1)

  strMsg = 'There is 1 attachment associated with this ' + strTicket + '.<br>Please click on the link to open / download the attachment :<p>';

  else

  strMsg = 'There are ' + i + ' attachments associated with this ' + strTicket + '.<br>Please click on the link to open / download the relevant attachment :<p>';

  // Lets combine our nice ticket count with all the links

  strMsg += strAtt;

  template.print(strMsg);

  }

}

7 REPLIES 7

dself
Tera Contributor

Thank you for sharing this Julian, I'm currently working on a solution that will strip alt=signature and this was a great starting point for my efforts.



Best,



David


Be nice to see what you come up with


So with the help of Rob Hayes on my team, we've figured out how to filter by that alt=".*"



We put a bus rule on the sys_email table just like yours, and made the image tag contain what we wanted to filter. In our case, we're looking for alt=".*_target_sn"



We also discovered that for some reason, the MAC version of outlook strips the first character off the alt= value in each image tag on every reply. So we made the tag start with 123456789_target_sn. You'll see in the script where we filter the regex accordingly. This gives our end users up to 10 replies before it starts stacking the images we're trying to filter.



Table: sys_emal


When: After


Condition: current.body.indexOf('<img') > 0


Script:


(function executeRule(current, previous /*null when async*/) {



  var attachsToDelete = current.body.match(/<img.*alt=".*target_sn".*>/g);



  var numToDelete = attachsToDelete.length;



  if (numToDelete > 0) {


  for (var x = 0; x < numToDelete; x++) {


  var sysIdStart = attachsToDelete[x].search(/src="cid:/) + 'src="cid:'.length;


  var fileName = attachsToDelete[x].substring(sysIdStart, attachsToDelete[x].search(/@/));


  var grSysAttach = new GlideRecord('sys_attachment');


  grSysAttach.addQuery('file_name','STARTSWITH', fileName);


  grSysAttach.addQuery('table_name', 'sys_email');


  grSysAttach.addQuery('table_sys_id', current.sys_id);


  grSysAttach.query();


  if (grSysAttach.next() && grSysAttach.getRowCount() < 2) {


  grSysAttach.deleteRecord();


  }


  }


// current.body = current.body.replace(/<img.*alt="sn_header_footer".*>/g,'');


  }


})(current, previous);


I'm assuming Image Tags can be set up in Exchange - would that be correct David?