Please use for the latest documentation.

This site is for reference purposes only and may not be accurate for the latest ServiceNow version

AttachmentCreator SOAP Web Service

From Wiki Archive
Jump to: navigation, search

Note: This article applies to Fuji. For more current information, see AttachmentCreator SOAP Web Service at

The Wiki page is no longer being updated. Please refer to for the latest product documentation.


Attaching documents to records in ServiceNow is achieved by sending a SOAP message targeting the ecc_queue table. For example, using the following URL or target end point:

The following fields in ecc_queue must be set to trigger the creation of the attachment.

Field Name Description Value
agent The name of the agent sending in the request, this can be any value since it is not used for processing. AttachmentCreator
topic The topic of the queue record, this value must be set to "AttachmentCreator" to trigger the attachment creation AttachmentCreator
name This field must contain a ":" delimited value of the file name, and its content-type file_name.xls:application/
source This field must contain a ":" delimited value of the target table and its sys_id incident:dd90c5d70a0a0b39000aac5aee704ae8
payload This field must contain the Base 64 encoded string representing the object to be attached the base 64 encoded string

Sending in the values described in the table above will attach an Excel file to the incident table for the record located by the sys_id "dd90c5d70a0a0b39000aac5aee704ae8"


Like all other HTTP based web services available on the platform, the AttachementCreator SOAP web service is required to authenticate using basic authentication by default. The user ID that is used for authentication will be subjected to access control in the same way as an interactive user.

To create attachments, the SOAP user must have any roles required to create Attachment [sys_attachment] records, as well as the soap_create role, and any roles required to read and write records on the target table, such as the itil role to add attachments to incident records. By default there is no single role allowing you to add attachments. You can create a role to explicitly allow adding attachments, then assign this role to the SOAP user.

File Type Security

You can control what file types users can attach by setting the glide.attachment.extensions and properties. These properties apply to the AttachmentCreator web service starting with Fuji Patch 10.

For these properties to apply to the AttachmentCreator web service, the property glide.attachment.enforce_security_validation must be set to true. This property is true by default.

Example SOAP Message

The following is an example of a SOAP message that would take a text file "john1.txt" of mime-type: text/plain and attach it to an Incident with a GUID of: e6eed6950a0a3c59006f32c8e3ff3cf9. Note the payload is the base64 encoding of the file itself.

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="" xmlns:ecc="">
    <soapenv:Header />

Example Node.js Script

The following example Node.js script adds an attachment to an incident record. Run this script from a client computer, not a ServiceNow instance.

<source lang="javascript"> /**

* Node.js to ServiceNow attachment upload via SOAP
* Andrew Venables [email protected]
* July 2014
* Version 1.0

var soap = require('soap'), // mime = require('mime'), // fs = require("fs");

var WSDL_FILENAME = 'ecc_queue.xml'; // Goto and save a copy of the WSDL locally for simplicity var DIRECTORY_CONTAINING_FILES = '/Users/andrew.venables/Documents/Uploads'; // Local path to the directory containing all the files we want to upload var USERNAME = 'andy.venables'; // An admin user account on the instance var PASSWORD = 'MY_PASSWORD'; // Password for above account var TARGET_TABLE = 'incident'; // Target table to attach the files to var TARGET_SYS_ID = '9d385017c611228701d22104cc95c371'; // Target record / sys_id to attach the files to. OOTB INC0000002

var files_to_upload; // Global that will contain our list of files to be uploaded var pos = 0; // Global pointer for our position in the files_to_upload list

// Create a SOAP client to use to post to the instance soap.createClient(WSDL_FILENAME, function(err, client) { // Node uses callbacks if (err) console.error(err);

// Set the username and password client.setSecurity(new soap.BasicAuthSecurity(USERNAME, PASSWORD));

// Read all the files in our source directory, will include . and .. files_to_upload = fs.readdirSync(DIRECTORY_CONTAINING_FILES);

console.log('Files to upload: ' + files_to_upload.length + '\n');

// Start iterating through the list of files to upload next(client);


// Process the next file in the files_to_upload array // This is a neat way of dealing with Node and its expectation of callbacks function next(client) {

// Check we haven't reached the end if (pos >= files_to_upload.length) return;

// Get the next file to upload var file_name = files_to_upload[pos];

// Increment the pointer to the next file pos++;

console.log(pos + '/'+ files_to_upload.length+ ' - Uploading file: ' + file_name);

// A blank file is the end of the list if (file_name == ) return;

// Skip to the next file as this one is invalid if (file_name == '.' || file_name == '..' || file_name.indexOf('.') == 0) next(client);

// Get the file type using an module called mime var file_type = mime.lookup(file_name); console.log(' of type: ' + file_type);

var file_payload; // Load the file into a buffer fs.readFile(DIRECTORY_CONTAINING_FILES + '/' + file_name, function(err, the_data) { if (err) console.error(err);

// Encode the buffer to base64 file_payload = new Buffer(the_data, 'binary').toString('base64');

// Set the parameters before we call the Web Service var parameters = { 'agent': 'AttachmentCreator', 'topic': 'AttachmentCreator', 'name': file_name+':'+file_type, 'source': TARGET_TABLE+':'+TARGET_SYS_ID, 'payload': file_payload };

console.log(' sending...') // Make the Web Service call, remember node likes callbacks client.insert(parameters, function(err, result) { if (err) console.error(err);


// This file is done, next! next(client); }); }); } </source>

Example Perl Script

The following example inserts multiple attachments into the ecc_queue table. You can specify the directory to upload using the file_path argument. All files in that directory and all subdirectories are uploaded.

This script requires a before business rule on inserts to the ecc_queue table to avoid having to make multiple calls for each attachment import.

<source lang="perl"> use warnings; use File::Basename; use File::Find qw(finddepth); use ServiceNow::SOAP; use MIME::Base64; use MIME::Types;

  1. Handle command line arguments to get the destination folder

$numArgs = $#ARGV + 1; if( $numArgs != 6) { print "ERROR: Insufficient Command Line Arguements.\n\n"; print_usage(); exit -1; }

$SNC_HOST = $ARGV[0]; $username = $ARGV[1]; $password = $ARGV[2]; $file_path = $ARGV[3]; $target_table = $ARGV[4]; $correlation_field = $ARGV[5];

my $base64; my $buf; my $mimetype;

  1. SOAP CONFIG stuff

my $CONFIG = ServiceNow($SNC_HOST, $username, $password); my $sn_table = $CONFIG->table('ecc_queue');

  1. traverse the specified file directory and stores files in the @files array

my @files; finddepth(sub {

    return if($_ eq '.' || $_ eq '..');
    push @files, $File::Find::name;

}, $file_path);

  1. process all the files in our array

foreach $file (@files) { $full_path = "$file"; print "\nFull Path: ". $file;

#Test the file type if( -d $file) { print "\nWe don't send directories only files: ". $full_path; next; }

open( FILE, $file) or die "$!"; binmode FILE; #preserves file formatting on Windows my $file_contents = ""; while ( read( FILE, $buf, 60 * 57 ) ) { $file_contents .= encode_base64($buf); }

my $filename = basename($full_path); my $mimetype = MIME::Types -> new;

 #Get Target Record by Correlation Field - $number should retrieve the matching correlation value from the filename
 #  In this case, the correlation value is the first 5 characters of the filename
 my $number = substr $filename, 0, 5;

	my $sysid = $sn_table->insert(

agent => 'AttachmentCreator', topic => 'AttachmentCreator', name => $filename.':'.$mimetype->mimeTypeOf($filename), source => $target_table.':ka'.$number.':'.$correlation_field, payload => $file_contents


 # print results or faults
 print " Created Attachment record: " . $sysid . "\n";


  1. subroutine to print out the USAGE of this script

sub print_usage { print "===============================\n"; print "\n"; print "===============================\n"; print "\nUSAGE:\n\n"; print " <SN instanceUrl> <SN username> <SN password> <root_data_path>\n"; print "\n...Where:\n"; print "\t<SN instance name>: The name of the target ServiceNow instance, i.e. instance (for instance.service-\n"; print "\t<username>: ServiceNow user name with rights to add records to the target table\n"; print "\t<password>: ServiceNow user password\n"; print "\t<root_data_path>: The full path and name of the directory that contains the attachment data.\n"; print "\t<target_table>: The ServiceNow table the attachment should be associated with.\n"; print "\t<correlation_field>: The ServiceNow field on the target table that matches the correlation value of the attachments\n"; print "\nEXAMPLE:\n\n"; print " myinstancename myusername mypassword ./attachment_root_folder sn_table_name correlation_field\n"; print "\n--------------------------------\n\n"; } </source>

Before Business Rule

Create the following before business rule to manage inserting multiple attachments.

Field Value
Table ecc_queue
When Before
Insert true
Condition current.source.indexOf(':ka') > -1

<source lang="javascript"> onBefore(current, previous) {

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

var log = []; log.push('Starting Attachment Correlation\nAgent: '+ current.agent); var correlation_field = current.source.split(':ka')[1].split(':')[1]+; var correlation_id = current.source.split(':ka')[1].split(':')[0]+; var target_table = current.source.split(':ka')[0]+; log.push('Field: '+ correlation_field +'\nID: '+ correlation_id +'\nTable: '+ target_table); var gr = new GlideRecord(target_table); if(correlation_field != && correlation_id != ){ gr.addQuery(correlation_field, correlation_id); gr.query();; current.source = target_table + ':' + gr.sys_id; log.push('Source: '+ current.source); } gs.log(log.join('\n')); } </source>


  • How many attachments can you send in one message
    • Only one attachment per message
  • Is there size limit on the attachment in the message
    • Attachments are limited to a maximum of 5MB.