Simple Client-Side JavaScript MIME Parser

Today, I have been working on JavaScript for the first time in a while. I have spent a lot of time lately in VSTO and specifically targeting Outlook. It was good to get back to the OfficeJS side of the house.

A customer of mine requested if there was a way to easily parse the MIME content from the easyEws library call: getMailItemMimeContent

I found a number of server-side JavaScript libraries but nothing that would help me with parsing the data on the client-side. Here is the class I created and I am contemplating incorporating it into it’s own library at some point and expanding on it. But for now, here it is:


/**
* Simple MIME Object for parsing basic MIME results:
* – Headers (parts)
* – HTML (full)
* – Attachments
* – Embedded Image Data
*/
function simpleMIMEClass() {
/** @type {string} */
var fullHeader = "";
/** @type {string} */
var html = "";
/** @type {MIMEImageData[]} */
var images = new Array();
/** @type {string} */
var text = "";
/** @type {string} */
var mimeData = "";
/**
* Internal MIME Image Class
*/
function MIMEImageData(){
this.ID = "";
this.Data = "";
}
/** @type {string} */
this.FullHeader = function() { return fullHeader };
/** @type {string} */
this.HTML = function() { return html; }
/** @type {string} */
this.Text = function() { return text; }
/** @type {string} */
this.GetImageData = function(id) {
for(var i=0;i<images.length;i++) {
if(images[i].ID == id) {
return images[i].Data;
}
}
// if here – nothing
return "";
}
/**
* Parses the MIME data into the object
* @param {@type {string} value} – MIME data from getMailItemMimeContent()
*/
this.Parse = function(value) {
mimeData = value;
text = atob(mimeData);
var parts = text.split("\r\n\r\n");
fullHeader = parts[0];
for(var partIndex=0;partIndex<parts.length;partIndex++) {
if(parts[partIndex].includes("Content-Type: text/html;", 0) > 0) {
html = parts[partIndex+1];
// must remove the =3D which is an incomplete escape code for "="
// which gets into Outlook MIME somehow – now sure
// also removing line breaks which are = at the very end
// followed by carriage return and new line
html = html.replace(/=3D/g,'=').replace(/=\r\n/g,"");
}
if(parts[partIndex].includes("Content-Type: image/", 0) > 0) {
var imgTag = parts[partIndex].split("\r\n");
var imgData = parts[partIndex+1];
var imgID = "";
for(var tagIndex=0;tagIndex<imgTag.length;tagIndex++) {
if(imgTag[tagIndex].includes("Content-ID: ") > 0) {
imgID = "cid:" + imgTag[tagIndex].split(": ")[1].replace("<","").replace(">","");
}
}
var img = new MIMEImageData();
img.Data = imgData;
img.ID = imgID;
images.push(img);
}
}
// done
return this;
};
};

To use this, I am demonstrating from an On Send event in OfficeJS. I grab the mail item being composed, save it to make sure it is in the Drafts folder, grab the ID of the message, then use that to grab the MIME data. Here is the sample code:


function sampleOfficeEvent(event){
/** @type {Office.Types.ItemCompose} */
var item = Office.cast.item.toItemCompose(Office.context.mailbox.item);
item.saveAsync(function(idResult) {
easyEws.getMailItemMimeContent(idResult.value,
function(mimeResult) {
/** {@type (simpleMIMEClass)} */
var oMime = new simpleMIMEClass();
oMime.Parse(mimeResult);
var doc = $(oMime.HTML()); // load into an HTML document
console.clear();
console.log("MIME: " + oMime.Text()); // get the raw MIME text
console.log("HEADER: " + oMime.FullHeader()); // get the full header info
console.log("HTML: " + oMime.HTML()); // return just the HTML
// here we are looking for the first image in the HTML document
var id = doc.find("img").attr("src");
// we display the SRC – which is a CID
console.log("TAG: " + id);
// Then we display the BASE64 string data for the image
// which can be converted to an image, replaced in the src tag
// to make it inline or store offline
console.log("DATA: " + oMime.GetImageData(id));
// done
event.completed();
});
});

Leave a Reply