Base64 conversion for any Attachment

PrakshalJain
Tera Contributor

Hi Friends,

I have a use case where I need to send an MMS message to a phone number. I learned that any attachment must be converted into Base64 format.

I am using an SMS service 'sndryt' endpoint that requires an API key along with mandatory parameters such as the message, phone number, business unique ID, and organization ID.(I have all with me)

To test the compatibility of the endpoint for handling MMS, I manually converted an image to Base64 using an online converter and passed it as a parameter in Postman. The recipient successfully received the message with the image.

Now, I am trying to achieve the same in ServiceNow via Flow Designer. I have attached an image to an incident record, retrieved its sys_id from the sys_attachment table, and am passing it as input.
I have created a custom action

PrakshalJain_0-1738935666030.png

passing attachment sys_id, phone, b_uid, org_id, message as an input

Below is the next script step I am using:
Script:

(function execute(inputs, outputs) {
    gs.info('Fetching attachment for Sys ID: ' + inputs.attachment_sys_id);

    // Validate inputs
    if (!inputs.attachment_sys_id || inputs.attachment_sys_id.trim() === "" ||
        !inputs.phone_number || inputs.phone_number.trim() === "" ||
        !inputs.message || inputs.message.trim() === "" ||
        !inputs.business_unit_id || inputs.business_unit_id.trim() === "" ||
        !inputs.org_id || inputs.org_id.trim() === "") {

        gs.error('Missing required inputs.');
        outputs.http_response_status = 400;
        outputs.http_response_body = "ERROR: Missing required inputs.";
        return;
    }

    // Retrieve the attachment record
    var attachmentGR = new GlideRecord('sys_attachment');
    if (!attachmentGR.get(inputs.attachment_sys_id)) {
        gs.error('Attachment not found for sys_id: ' + inputs.attachment_sys_id);
        outputs.http_response_status = 404;
        outputs.http_response_body = "ERROR: Attachment not found.";
        return;
    }

    // Retrieve metadata
    var fileName = attachmentGR.getValue('file_name');
    var mimeType = attachmentGR.getValue('content_type');
    var attachmentSize = attachmentGR.getValue('size_bytes');

    gs.info('Attachment Found: ' + fileName);
    gs.info('Size (Bytes): ' + attachmentSize);
    gs.info('MIME Type: ' + mimeType);

    // Ensure only valid image MIME types are sent
    var allowedMimeTypes = ["image/png", "image/jpeg", "image/gif"];
    if (!allowedMimeTypes.includes(mimeType)) {
        gs.error('Invalid attachment type. Only PNG, JPEG, and GIF are supported.');
        outputs.http_response_status = 415; // Unsupported Media Type
        outputs.http_response_body = "ERROR: Only PNG, JPEG, and GIF images are allowed.";
        return;
    }

    try {
        // Retrieve the attachment content as a byte array
        var attachmentUtil = new GlideSysAttachment();
        var attachmentData = attachmentUtil.getBytes('sys_attachment', inputs.attachment_sys_id);

        // Ensure attachment data is valid
        if (!attachmentData || attachmentData.length === 0) {
            gs.error('Error: Unable to retrieve attachment data.');
            outputs.http_response_status = 500;
            outputs.http_response_body = "ERROR: Unable to retrieve attachment data.";
            return;
        }

        gs.info('Successfully retrieved attachment bytes. Encoding to Base64...');

        // Convert byte array to a JavaScript-compatible string before encoding
        var binaryString = "";
        for (var i = 0; i < attachmentData.length; i++) {
            binaryString += String.fromCharCode(attachmentData[i] & 0xFF);
        }

        var base64Encoded = GlideStringUtil.base64Encode(binaryString);

        if (!base64Encoded || base64Encoded.length === 0) {
            gs.error('Error: Base64 encoding failed.');
            outputs.http_response_status = 500;
            outputs.http_response_body = "ERROR: Base64 encoding failed.";
            return;
        }

        gs.info('Base64 Encoding Successful! Length: ' + base64Encoded.length);

        // Construct the payload dynamically
        var payload = {
            org_id: inputs.org_id,
            business_unit_id: inputs.business_unit_id,
            api_key: "<API Key>", // Hardcoded API Key (have that with me)
            phone_number: inputs.phone_number,
            message: inputs.message,
            media: "data:" + mimeType + ";base64," + base64Encoded.trim() // Trim to avoid unnecessary spaces
        };

        gs.info('Payload Constructed: ' + JSON.stringify(payload));

        // REST API Request
        var request = new sn_ws.RESTMessageV2();
        request.setHttpMethod('POST');
        request.setEndpoint('https://ap.sndright.com/api/SndDirect/');
        request.setRequestHeader('Content-Type', 'application/json');
        request.setRequestHeader('Accept', 'application/json');
        request.setRequestBody(JSON.stringify(payload));

        // Execute the request
        var response = request.execute();
        var httpResponseStatus = response.getStatusCode();
        var responseBody = response.getBody();

        gs.info('HTTP Response Status Code: ' + httpResponseStatus);
        gs.info('HTTP Response Body: ' + responseBody);

        outputs.http_response_status = httpResponseStatus;
        outputs.http_response_body = responseBody;
    } catch (ex) {
        gs.error('Error processing attachment: ' + (ex.getMessage() || ex));
        outputs.http_response_status = 500;
        outputs.http_response_body = "ERROR: Exception while processing attachment.";
    }
})(inputs, outputs);

 

PrakshalJain_1-1738935822074.png

 

I place log info for debugging

PrakshalJain_2-1738935957454.png

 


Failing at this
"Error processing attachment: TypeError: Cannot find default value for object."
till then able to process everything getting meta data of the attachment
Facing issues with conversion.

Anyone Please Help




9 REPLIES 9

Ankur Bawiskar
Tera Patron
Tera Patron

@PrakshalJain 

which line is causing the error? did you debug that?

If my response helped please mark it correct and close the thread so that it benefits future readers.

Regards,
Ankur
✨ Certified Technical Architect  ||  ✨ 9x ServiceNow MVP  ||  ✨ ServiceNow Community Leader

it is always going to catch case not going to try

// Convert byte array to a JavaScript-compatible string before encoding
        var binaryString = "";
        for (var i = 0; i < attachmentData.length; i++) {
            binaryString += String.fromCharCode(attachmentData[i] & 0xFF);
        }

 

        var base64Encoded = GlideStringUtil.base64Encode(binaryString);

 

        if (!base64Encoded || base64Encoded.length === 0) {
            gs.error('Error: Base64 encoding failed.');
            outputs.http_response_status = 500;
            outputs.http_response_body = "ERROR: Base64 encoding failed.";
            return;
        }
Before that I am getting the bytes details as well
only conversion I am not able to achieve

@PrakshalJain 

so basically you want to get base64 encoded data of attachment

If you are running in global scope then this sample script will help you to get baase64 encoded string

Enhance your logic as per this

var gr = new GlideRecord('sys_attachment');
	gr.get('d7ff2c044f96cc90fc11fa218110c746');

	var StringUtil = new GlideStringUtil();
	var gsis = GlideSysAttachmentInputStream(gr.sys_id.toString());
	var ba = new Packages.java.io.ByteArrayOutputStream();
	gsis.writeTo(ba,0,0);
	ba.close();
	var base64EncodedData = StringUtil.base64Encode(ba.toByteArray());

If my response helped please mark it correct and close the thread so that it benefits future readers.

Regards,
Ankur
✨ Certified Technical Architect  ||  ✨ 9x ServiceNow MVP  ||  ✨ ServiceNow Community Leader

Hi Ankur,

Thankyou for the solution, But it didn't work, 
I am in my global scope, below is my code
Getting the same error as before:
*** Script: Error processing attachment: TypeError: Cannot find default value for object.

Below is the code:

(
function execute(inputs, outputs) {
    gs.info('Fetching attachment for Sys ID: ' + inputs.attachment_sys_id);

 

    // Validate inputs
    if (!inputs.attachment_sys_id || inputs.attachment_sys_id.trim() === "" ||
        !inputs.phone_number || inputs.phone_number.trim() === "" ||
        !inputs.message || inputs.message.trim() === "" ||
        !inputs.business_unit_id || inputs.business_unit_id.trim() === "" ||
        !inputs.org_id || inputs.org_id.trim() === "") {

 

        gs.error('Missing required inputs.');
        outputs.http_response_status = 400;
        outputs.http_response_body = "ERROR: Missing required inputs.";
        return;
    }

 

    // Retrieve the attachment record
    var attachmentGR = new GlideRecord('sys_attachment');
    if (!attachmentGR.get(inputs.attachment_sys_id)) {
        gs.error('Attachment not found for sys_id: ' + inputs.attachment_sys_id);
        outputs.http_response_status = 404;
        outputs.http_response_body = "ERROR: Attachment not found.";
        return;
    }

 

    // Retrieve metadata
    var fileName = attachmentGR.getValue('file_name');
    var mimeType = attachmentGR.getValue('content_type');

 

    gs.info('Attachment Found: ' + fileName);
    gs.info('MIME Type: ' + mimeType);

 

    try {
        // Convert attachment to Base64 using GlideSysAttachmentInputStream
        var base64Encoded = attachmentToBase64(inputs.attachment_sys_id);

 

        if (!base64Encoded || base64Encoded.length === 0) {
            gs.error('Error: Base64 encoding failed.');
            outputs.http_response_status = 500;
            outputs.http_response_body = "ERROR: Base64 encoding failed.";
            return;
        }

 

        gs.info('Base64 Encoding Successful! Length: ' + base64Encoded.length);

 

        // Construct the payload dynamically
        var payload = {
            org_id: inputs.org_id,
            business_unit_id: inputs.business_unit_id,
            api_key: "<apikey>", // Hardcoded API Key
            phone_number: inputs.phone_number,
            message: inputs.message,
            media: "data:" + mimeType + ";base64," + base64Encoded.trim() // Trim to avoid unnecessary spaces
        };

 

        gs.info('Payload Constructed: ' + JSON.stringify(payload));

 

        // REST API Request
        var request = new sn_ws.RESTMessageV2();
        request.setHttpMethod('POST');
        request.setEndpoint('end point name');
        request.setRequestHeader('Content-Type', 'application/json');
        request.setRequestHeader('Accept', 'application/json');
        request.setRequestBody(JSON.stringify(payload));

 

        // Execute the request
        var response = request.execute();
        var httpResponseStatus = response.getStatusCode();
        var responseBody = response.getBody();

 

        gs.info('HTTP Response Status Code: ' + httpResponseStatus);
        gs.info('HTTP Response Body: ' + responseBody);

 

        outputs.http_response_status = httpResponseStatus;
        outputs.http_response_body = responseBody;
    } catch (ex) {
        gs.error('Error processing attachment: ' + (ex.getMessage() || ex));
        outputs.http_response_status = 500;
        outputs.http_response_body = "ERROR: Exception while processing attachment.";
    }
})(inputs, outputs);

 

// Function to Convert Attachment to Base64 (Efficiently Reads Stream)
function attachmentToBase64(attachmentSysId) {
    var attachmentGR = new GlideRecord('sys_attachment');
    if (!attachmentGR.get(attachmentSysId)) {
        gs.error("Error: Attachment not found.");
        return "ERROR: Attachment not found.";
    }

 

    try {
        var gsis = new GlideSysAttachmentInputStream(attachmentSysId);
        var ba = new Packages.java.io.ByteArrayOutputStream();
        gsis.writeTo(ba, 0, 0);
        ba.close();

 

        var base64Encoded = GlideStringUtil.base64Encode(ba.toByteArray());
        return base64Encoded;
    } catch (e) {
        gs.error("Error encoding attachment to Base64: " + e);
        return "ERROR: Exception during Base64 encoding.";
    }
}