ykarpovich / msg.reader Goto Github PK
View Code? Open in Web Editor NEWOutlook Item File (.msg) reader in JavaScript
License: Apache License 2.0
Outlook Item File (.msg) reader in JavaScript
License: Apache License 2.0
When parsing an appointment from the calendar, start and end-time are not present within the resulting data. These should be present when saving the .msg file manually though. Is there any restriction that negates the possibility to do so?
Im not sure why, ive tried using the attachment blobs serveral different ways but the contents of the downloaded file are either empty, "undefined", or "[object Object]". The version below us the "[object Object]" Can anyone suggest where Im going wrong?
`// Function to check if logging is enabled
function isLoggingEnabled() {
return new Promise((resolve, reject) => {
chrome.storage.sync.get('loggingEnabled', function(result) {
resolve(result.loggingEnabled);
});
});
}
// Function to log messages if logging is enabled
async function logIfEnabled(...messages) {
const loggingEnabled = await isLoggingEnabled();
if (loggingEnabled) {
console.log(...messages);
}
}
// Function to parse headers
function parseHeaders(headers) {
logIfEnabled('Starting parseHeaders function...');
var parsedHeaders = {};
if (!headers) {
logIfEnabled('Headers are empty.');
return parsedHeaders;
}
var headerRegEx = /(.): (.)/g;
while (m = headerRegEx.exec(headers)) {
// todo: Pay attention! Header can be presented many times (e.g. Received). Handle it, if needed!
logIfEnabled(Parsing header: ${m[1]} with value: ${m[2]}
);
parsedHeaders[m[1]] = m[2];
}
logIfEnabled('Parsed headers:', parsedHeaders);
return parsedHeaders;
}
// Function to extract date from headers
function getMsgDate(rawHeaders) {
logIfEnabled('Starting getMsgDate function...');
var headers = parseHeaders(rawHeaders);
if (!headers['Date']) {
logIfEnabled('Date header not found.');
return 'Unknown';
}
var date = new Date(headers['Date']).toLocaleString();
logIfEnabled('Parsed date:', date);
return date;
}
// Function to fetch the raw data of the .msg file and populate overlay with parsed data
async function fetchMsgContent(msgUrl) {
logIfEnabled('Starting fetchMsgContent function...');
try {
const response = await fetch(msgUrl);
const buffer = await response.arrayBuffer();
logIfEnabled('Fetched .msg file data successfully.');
const msgReader = new MSGReader(new Uint8Array(buffer));
const fileData = msgReader.getFileData();
logIfEnabled('MSG file data:', fileData);
// Process attachments
await Promise.all(fileData.attachments.map(async (attachment, index) => {
logIfEnabled(`Processing attachment ${index + 1}...`);
const attachmentContent = await msgReader.getAttachment(index);
logIfEnabled('Attachment content:', attachmentContent);
attachment.content = attachmentContent;
}));
// Display content
displayMsgContent(fileData);
} catch (error) {
console.error('Error fetching or parsing .msg file:', error);
}
}
// Function to display the .msg content in an overlay
function displayMsgContent(msgContent) {
logIfEnabled('Starting displayMsgContent function...');
// Example code to populate overlay with parsed data
const recipients = msgContent.recipients.map(recipient => recipient.name).join(', ');
const attachments = msgContent.attachments.map(attachment => attachment.fileName).join(', ');
const headers = msgContent.headers;
const date = getMsgDate(headers);
// Wrap the message body in a <pre> tag to preserve formatting
const body = `<pre>${msgContent.body}</pre>`;
const msgHtml = `
<div>
<h2>From: ${msgContent.senderName}</h2>
<h2>To: ${recipients}</h2>
<h2>Date: ${date}</h2>
<h2>Subject: ${msgContent.subject}</h2>
${body}
<h2>Attachments: ${attachments}</h2>
</div>
`;
// Create overlay container
const overlay = document.createElement('div');
overlay.setAttribute('id', 'msgOverlay');
overlay.innerHTML = msgHtml;
// Style overlay
overlay.style.position = 'fixed';
overlay.style.top = '50%';
overlay.style.left = '50%';
overlay.style.transform = 'translate(-50%, -50%)';
overlay.style.width = '80%';
overlay.style.height = '80%'; // Set overlay height to 80% of the window height
overlay.style.backgroundColor = 'rgba(255, 255, 255, 0.9)'; // Semi-transparent white background
overlay.style.padding = '20px';
overlay.style.border = '2px solid black';
overlay.style.borderRadius = '10px';
overlay.style.overflowY = 'auto'; // Add vertical scroll bars if content overflows
overlay.style.zIndex = '9999';
// Append overlay to body
document.body.appendChild(overlay);
// Style dismiss button
const dismissButton = document.createElement('button');
dismissButton.setAttribute('id', 'dismissButton');
dismissButton.innerText = 'Dismiss';
dismissButton.style.position = 'absolute';
dismissButton.style.top = '10px';
dismissButton.style.right = '10px';
overlay.appendChild(dismissButton);
// Add event listener to dismiss button
dismissButton.addEventListener('click', () => {
// Remove overlay when dismiss button is clicked
overlay.remove();
});
// Loop through attachments to add download links
msgContent.attachments.forEach(attachment => {
const contentBlob = new Blob([attachment.content], { type: 'application/octet-stream' });
logIfEnabled('Attachment content:', attachment.content);
logIfEnabled('Attachment Blob:', contentBlob);
const downloadLink = document.createElement('a');
downloadLink.href = URL.createObjectURL(contentBlob);
logIfEnabled('Attachment href:', downloadLink.href);
downloadLink.download = attachment.fileName;
logIfEnabled('Attachment filename:', attachment.fileName);
downloadLink.innerText = `Download ${attachment.fileName}`;
logIfEnabled('Attachment inner text:', downloadLink.innerText);
overlay.appendChild(downloadLink);
});
}
// Function to replace .msg URLs with dynamic HTML content viewer
function replaceMsgUrls() {
logIfEnabled('Starting replaceMsgUrls function...');
const msgUrls = document.querySelectorAll('a[href$=".msg"]');
msgUrls.forEach(msgUrl => {
// Check if the URL is already processed
if (!msgUrl.getAttribute('data-msg-processed')) {
msgUrl.setAttribute('data-msg-processed', true);
msgUrl.addEventListener('click', function(event) {
event.preventDefault();
const msgFileUrl = msgUrl.href;
logIfEnabled('Processing .msg file:', msgFileUrl);
fetchMsgContent(msgFileUrl);
});
}
});
}
// Initial call to replace .msg URLs
replaceMsgUrls();
// Listen for DOM changes to detect new .msg URLs and rewrite them
const observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
mutation.addedNodes.forEach(addedNode => {
if (addedNode.nodeType === Node.ELEMENT_NODE) {
if (addedNode.tagName === 'A' && addedNode.href.endsWith('.msg')) {
// New .msg URL added to the DOM
logIfEnabled('New .msg URL added:', addedNode.href);
replaceMsgUrls();
}
}
});
});
});
// Start observing DOM changes
observer.observe(document.body, { childList: true, subtree: true });
`
Excellent work I would say. Supporting msg format from JS is a must!
Supporting html is very important. Since I could not reopen #1 and I do not know if closed issues are monitored I am opening a new issue now. The demo page fails to parse the msg in full when html is included. Is it difficult to enhance the library to support that? Perhaps the author can share some ideas?
In the meantime here is a workaround:
sudo apt install -y libemail-outlook-message-perl
cd /tmp
msgconvert test\ with\ html\ content.msg # creates test\ with\ html\ content.eml
git clone https://github.com/nodemailer/mailparser.git
npm install
cd mailparser/examples
node extractInfoFromEml.js /tmp/test\ with\ html\ content.eml
/* eslint no-console:0 */
'use strict';
const util = require('util');
const fs = require('fs');
const simpleParser = require('../lib/simple-parser.js');
const args = process.argv.slice(2);
const filePath = args[0];
let input = fs.createReadStream(filePath);
simpleParser(input)
.then(mail => {
console.log(util.inspect(mail, false, 22));
})
.catch(err => {
console.log(err);
});
Best regards, - Nestor
I am attempting to read in an external .msg file for display. Below is the code I am using to read in the file as a blob and then execute the example code. I have modified line 116 in the example code to set selectedFile to the blob.
This is encountering the following error:
msg.reader.js:420 Uncaught TypeError: Cannot read property 'name' of undefined
at getFieldType (msg.reader.js:420)
at MSGReader.getAttachment (msg.reader.js:553)
at DisplayOutlookMSG.aspx:722
at Function.map (jquery-1.12.0.min.js:2)
at FileReader.fileReader.onload (DisplayOutlookMSG.aspx:721)
var oReq = new XMLHttpRequest();
oReq.open("GET", "https://myDomain.com/myMessage.msg", true);
oReq.responseType = "blob";
oReq.onload = function(oEvent) {
var blob = oReq.response;
blob.name = "myMessage.msg";
//JS code from example.html with line 116 changed to
var selectedFile = blob;
}
I am not able to use FileReader at this time because the page must work with IE 11. Example code showing how to use FileReader may be appreciated by others.
When I load a msg file on the demo page: https://ykarpovich.github.io/msg.reader/examples/example.html
I get:
TypeError: fileData.body.substring is not a function[Learn More] example.html:141:33
Using FireFox 66.
I cannot parse this file:
msgFIle.msg.zip
When calculating sbatData
only the first startIndex has some value, at all other times it returns undefined and finally stops with stack overflow exception.
Great script ! Can you add a license so we can use it ?
It would be great to download the attachment with the specified extension.
Hi. This package is great although I notice I can't get the content of MSG attachments. It would be great if this was supported.
On certain msg files I am unable to read the body with this plugin.
When uploading the attached to the example site at https://ykarpovich.github.io/msg.reader/examples/example.html the body cannot be read.
When opening with outlook the msg file is in tact and perfectly readable. Is there some sort of difference in this file compared to others?
I'm trying convert html to msg.
Any way to create it easily?
Thanks
If we can convert it to a npm module I think will be useful
Hi @ykarpovich ,
Can we use this library with salesforce? As salesforce does not have native capacity to read .msg files?
Very good work for Javascript. but It does not display correctly HTML body in the MSG file.
Is it possible to separate the CC and BCC in the recipient array?
When I am copying the mail from sent folder, I am not able to get the sender email in the parsed data. Any help?
If I parse a .msg file from my send-folder, the header property is emty (undefined).
Hello,
I found you code very helpful, thank you.
But i need the attachments encoding because i need to create files on a remote server usinf the attachments so basically i will convert them to base64 strings.
But i cannot know the encoding of the file.content.
i am using reader. readAsDataURL but i cannot read it.
Appreciate the help.
Thanks.
How can I get email date from .msg file contents? In NAME_MAPPING, how to specify for date field, please.
Thanks.
I have incorporated this library into a google chrome extension. Looking for feedback and contributions.
https://github.com/nichols-eric/MSG-EML-Viewer
Thank you for the library, can mark as closed.
Thanks for great plugin! Is it possible to parse text breaks in message body?
Like over here: https://www.encryptomatic.com/viewer/
Hi,
we use this library and had good experience! Great Job!
But now the mails were sent as signed mails und the library can´t read the attachments. The file-object has only one file "smime.p7m".
Can anybody tell me to change the code that it will be work or is is impossible/complicated?
I´m glad to hear from you.
Best regards.
I see DataStream having write and save functionality. Is there a way I could read a .msg with placeholders as an XSTRING or Unit8Array, change placeholders as needed and then return to the same XSTRING / Unit8Array or just download directly? I did it with the plain array but can replace placeholders only with data of the same length. Maybe this msg.reader could help?
Thank you.
msg.reader/examples/example.html
Line 75 in c3bd6ee
Use https:// instead of file://
https://code.jquery.com/jquery-1.12.0.min.js
I want to read .msg files in my native iOS app, but I am not able to find a native Swift/objective-c solution for this. So I am thinking to use react native to achieve this. Can you please answer that we can use this with react native.
Many thanks.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.