Jaxer Mail Parser Class
by Steven Brown on Nov.22, 2008, under Jaxer
Here’s some more code that parses an incoming email. It’s only very basic and I am sure makes lots of mistakes, but it works enough to break up multipart emails, decode special characters in text parts and decode attachments in other parts.
Note that this requires the Base64 decoder class from http://www.webtoolkit.info/javascript-base64.html as I couldn’t be bothered making my own.
var mail = function mail(rawMessage) { var explodeMessage = function explodeMessage(inMessage) { var inHeaderPos = inMessage.indexOf("\r\n\r\n"); var inRawHeaders = inMessage.slice(0, inHeaderPos).replace(/\r\n\s+/g, " "); var inRawBody = inMessage.slice(inHeaderPos).replace(/(\r\n)+$/, "").replace(/^(\r\n)+/, ""); var inContentType = inRawHeaders.match(/Content-Type: (.*)/)[1]; var inContentTypeParts = inContentType.split(";"); var mimeType = inContentTypeParts[0].replace(/\s/g, ""); var mimeTypeParts = mimeType.split("/"); var inBodyParts; var inBodyParts; var inBoundary; var inBody; // If it's a multipart we need to split it up if (mimeTypeParts[0] === "multipart") { inBodyParts = []; inBoundary = inContentTypeParts[1].match(/boundary="?([^"]*)"?/)[1]; var regString = new RegExp("--" + inBoundary, "g"); inBodyParts = inRawBody.replace(new RegExp("--" + inBoundary, "g"), inBoundary).replace(new RegExp(inBoundary + "--", "g"), inBoundary).split(inBoundary); inBodyParts.shift(); inBodyParts.pop(); for (var i = 0; i < inBodyParts.length; i++) { inBodyParts[i] = inBodyParts[i].replace(/(\r\n)+$/, "").replace(/^(\r\n)+/, ""); inBodyParts[i] = explodeMessage(inBodyParts[i]); } } else { inBody = inRawBody; if (mimeTypeParts[0] === "text") { inBody = inBody.replace(/=\r\n/g, ""); var specialChars = inBody.match(/=[A-F0-9][A-F0-9]/g); if (specialChars) { for (var i = 0; i < specialChars.length; i++) { inBody = inBody.replace(specialChars[i], String.fromCharCode(parseInt(specialChars[i].replace(/=/, ""), 16))); } } } if (mimeTypeParts[0] === "application") { if (inRawHeaders.match(/Content-Transfer-Encoding: base64/)) { inBody = Base64.decode(inBody); } } } return { "rawHeaders": inRawHeaders, "rawBody": inRawBody, "body": inBody, "contentType": inContentType, "contentTypeParts": inContentTypeParts, "boundary": inBoundary, "bodyParts": inBodyParts, "mimeType": mimeType, "mimeTypeParts": mimeTypeParts, }; }; var messageParts = explodeMessage(rawMessage); var subject = (/\r\nSubject: (.*)\r\n/gi).exec(messageParts.rawHeaders)[1]; var to = (/\r\nTo: (.*)\r\n/gi).exec(messageParts.rawHeaders)[1]; var from = (/\r\nFrom: (.*)\r\n/gi).exec(messageParts.rawHeaders)[1]; var cascadeBody = function cascadeBody(inMessageParts) { var result = ""; result += inMessageParts.rawHeaders; result += "\r\n\r\n"; if (inMessageParts.bodyParts) { for (var i = 0; i < inMessageParts.bodyParts.length; i++) { result += "--" + inMessageParts.boundary + "\r\n"; result += cascadeBody(inMessageParts.bodyParts[i]); } result += "--" + inMessageParts.boundary + "--\r\n\r\n\r\n"; } else { result += inMessageParts.body + "\r\n"; } return result; }; return { "messageParts": messageParts, "recreateMessage": function recreateMessage() { return cascadeBody(messageParts); } }; };
Essentially you create the mail object like this:
var mailObj = mail(rawMail);
rawMail will be your entire email as you receive it from the server, including headers. You can then access the body or parts of the message if it is a multipart email. The recreateMessage() method of the returned object shows an example of recursively lopping through the multipart tree. This is necessary as emails often come as multipart/mixed with a multipart/alternative in the first “mixed” part.
I’ll be refining this so essentially you will get an object with a series of properties for headers (to/cc – array, from, subject, date) and then a few properties for the body (text, html, attachments – array).