Built something you're proud of? Tell the story. A quick G2 review of App Engine or Build Agent helps other developers see what's possible on ServiceNow. Share your experience.

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




10 REPLIES 10

HaizalJ
Tera Contributor

This is always a bit tricky in ServiceNow, especially when dealing with different file types. Usually, the GlideSysAttachment.getContentStream approach is the most reliable way to avoid memory issues with larger attachments.

One thing that helps me when I'm troubleshooting my script is to run a quick manual conversion on the same file using a site like this one and then compare the first few strings of the output. If the manual one works but the SN one doesn't, it’s usually an encoding issue in the script.

Quick tip: Make sure you're handling the character limit if you're trying to push that string into a standard string field, as they can get cut off!