Need to Send just 1 Attachment or a Few?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎07-07-2017 09:37 AM
As many of you know, you can include attachments as part of notifications by simply checking the required box on the notification. However, whenever the notification goes out it will always send every attachment that exists on the record. If you are working a customer support case and going back and forth with a customer this could really get out of hand quickly, not to mention annoy the customer. The other risk is that your last attachment might not get added if you hit the data limit.
I have seen various posts online with workarounds and wanted to add my solution because I see that there are many people out there pulling their hair out trying to figure this out! I also want to point of some other solutions because depending on your needs they might just work for you.
1. Only send the last attachment. Only Last attachment to be sent in Email Notification I found this solution to work but it has a limitation. It will only send the "last" attachment added to the record so if you add 2 attachments...tough luck. Scroll down until you get to the section about adding 2 business rules. By the way, they should be added on the sys_email table.
2. This article was awesome, well worth the read just to understand how attachments in SN work. It's actually not at all what I thought! https://snprotips.com/blog/2016/2/25/understanding-and-using-glideattachment One thing to note with this code is that if you create a script include you will need to change all lines which have copyRecord() to this.copyRecord() in order for it to work.
On to my solution. Initially I thought I could simply turn on "include attachments" and write a business rule which would strip off the attachments I didn't want. What I did was look at all the attachments on the email and tried to remove attachments which were older than 5min. The thought was that agents working a case would add 1 or more attachments and then update the case. These attachments, along with any others, would get added to the notification email and I could strip out the attachments which had a sys_created_on date older than 5min ago. Seemed pretty genius to me but I was quickly let down. After investigating why this didn't work I eventually found out that when attachments are added to an email from a case, they are literally added as new attachments to the email object. Therefore you cannot reference the sys_created_on time for the attachments which are on the case record. Essentially all the attachments on the email are seconds old by the time my business rule fires and there they all get sent out. Booo!
What I then did was leverage the code from #2 above. The code in it's original format requires that you pass in the filename of the attachment you want to add. For my business case this wasn't much use. I really don't want to have to go query attachments, find all the latest attachments within the last 5 min, get the file names and then call this script recursively. To get around this I simply removed the filename from the function call and defined a GlideDateTime which essentially NOW - 5min. Then when I query the list of attachments I filter them by sys_created_on 5 min ago. The code then makes a copy of whatever attachments it finds and adds them to whatever record you supply.
var getAttachment = Class.create();
getAttachment.prototype = {
initialize: function() {
},
copySpecificAttachments : function (donorTable, donorID, recipientTable, recipientID) {
var donorAttSysID;
var newAttRecord;
var linkToNewRecord;
var attDataRecord;
var newDocRecord;
var dt = new GlideDateTime();
dt.addSeconds(-300); // subtract 5min from NOW
var attRecord = new GlideRecord('sys_attachment');
attRecord.addQuery('table_name', donorTable);
attRecord.addQuery('table_sys_id', donorID);
attRecord.addQuery('sys_created_on', '>=', dt);
attRecord.query();
while (attRecord.next()) {
donorAttSysID = attRecord.getValue('sys_id');
newAttRecord = this.copyRecord(attRecord);
newAttRecord.setValue('table_name', recipientTable);
newAttRecord.setValue('table_sys_id', recipientID);
newAttRecord.update();
linkToNewRecord = gs.getProperty('glide.servlet.uri') + newAttRecord.getLink();
attDataRecord = new GlideRecord('sys_attachment_doc');
attDataRecord.addQuery('sys_attachment', donorAttSysID);
attDataRecord.query();
while (attDataRecord.next()) {
newDocRecord = this.copyRecord(attDataRecord);
newDocRecord.setValue('sys_attachment', newAttRecord.getValue('sys_id'));
newDocRecord.update();
}
}
//gs.print(linkToNewRecord);
},
copyRecord :function(record) {
var recordElement;
var recordElementName;
var recordTable = record.getTableName();
var recordFields = record.getFields();
var newRecord = new GlideRecord(recordTable);
newRecord.initialize();
for (var i = 0; i < recordFields.size(); i++) {
recordElement = recordFields.get(i);
if(recordElement.getName() != 'sys_id' && recordElement.getName() != 'number')
{
recordElementName = recordElement.getName();
newRecord.setValue(recordElementName, record.getValue(recordElementName));
}
}
var newSysId = newRecord.insert();
return newRecord;
},
type: 'getAttachment'
};
So how does this all come together? I created a business rule on the sys_email table. This business rule is a "before" INSERT where TYPE is send-ready and the Target Table is "sn_customerservice_case". I only want this business rule to run on emails generated from Case (not Incident, etc). Then we check the "Advanced" box so we can add the code. In my case the code is just:
var x = new getAttachment();
x.copySpecificAttachments('sn_customerservice_case', current.instance, 'sys_email', current.sys_id);
Essentially we want to copy attachments from the given case which associated with this email and attach them to this email. It will only grab attachments which were added to the case within the last 5min.
Until ServiceNow comes up with a solution to only send the latest attachment(s) this is the best I could come up with. Hope this helps anyone else out there that has been looking for options.
- Labels:
-
Scripting and Coding
- 2,936 Views
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎12-19-2018 08:50 AM
Excelent article, I've adapted it to get only last attachment.
Thanks a lot!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎04-22-2019 04:57 AM
Where the above mentioned code needs to be added??!!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎04-22-2019 05:24 AM
"So how does this all come together? I created a business rule on the sys_email table. This business rule is a "before" INSERT where TYPE is send-ready and the Target Table is <the desired table>."
You can use the code directly on the Business rule (just remove Class related code) if you do not want to create a Script include.
Or do exactly as instructed by the author and create a Script Include (and call it from the BR).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎04-22-2019 06:21 AM
Please confirm!! The below code needs to added in script include??
var getAttachment = Class.create();
getAttachment.prototype = {
initialize: function() {
},
copySpecificAttachments : function (donorTable, donorID, recipientTable, recipientID) {
var donorAttSysID;
var newAttRecord;
var linkToNewRecord;
var attDataRecord;
var newDocRecord;
var dt = new GlideDateTime();
dt.addSeconds(-300); // subtract 5min from NOW
var attRecord = new GlideRecord('sys_attachment');
attRecord.addQuery('table_name', donorTable);
attRecord.addQuery('table_sys_id', donorID);
attRecord.addQuery('sys_created_on', '>=', dt);
attRecord.query();
while (attRecord.next()) {
donorAttSysID = attRecord.getValue('sys_id');
newAttRecord = this.copyRecord(attRecord);
newAttRecord.setValue('table_name', recipientTable);
newAttRecord.setValue('table_sys_id', recipientID);
newAttRecord.update();
linkToNewRecord = gs.getProperty('glide.servlet.uri') + newAttRecord.getLink();
attDataRecord = new GlideRecord('sys_attachment_doc');
attDataRecord.addQuery('sys_attachment', donorAttSysID);
attDataRecord.query();
while (attDataRecord.next()) {
newDocRecord = this.copyRecord(attDataRecord);
newDocRecord.setValue('sys_attachment', newAttRecord.getValue('sys_id'));
newDocRecord.update();
}
}
//gs.print(linkToNewRecord);
},
copyRecord :function(record) {
var recordElement;
var recordElementName;
var recordTable = record.getTableName();
var recordFields = record.getFields();
var newRecord = new GlideRecord(recordTable);
newRecord.initialize();
for (var i = 0; i < recordFields.size(); i++) {
recordElement = recordFields.get(i);
if(recordElement.getName() != 'sys_id' && recordElement.getName() != 'number')
{
recordElementName = recordElement.getName();
newRecord.setValue(recordElementName, record.getValue(recordElementName));
}
}
var newSysId = newRecord.insert();
return newRecord;
},
type: 'getAttachment'
};