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
(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.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);