mailparser
Advanced tools
Comparing version 0.5.1 to 0.5.2
@@ -46,71 +46,71 @@ "use strict"; | ||
// Make MailParser a Stream object | ||
Stream.call(this); | ||
this.writable = true; | ||
// Make MailParser a Stream object | ||
Stream.call(this); | ||
this.writable = true; | ||
/** | ||
* Options object | ||
* @public */ | ||
this.options = options || {}; | ||
/** | ||
* Options object | ||
* @public */ | ||
this.options = options || {}; | ||
/** | ||
* Indicates current state the parser is in | ||
* @private */ | ||
this._state = STATES.header; | ||
/** | ||
* Indicates current state the parser is in | ||
* @private */ | ||
this._state = STATES.header; | ||
/** | ||
* The remaining data from the previos chunk which is waiting to be processed | ||
* @private */ | ||
this._remainder = ""; | ||
/** | ||
* The remaining data from the previos chunk which is waiting to be processed | ||
* @private */ | ||
this._remainder = ""; | ||
/** | ||
* The complete tree structure of the e-mail | ||
* @public */ | ||
this.mimeTree = this._createMimeNode(); | ||
/** | ||
* The complete tree structure of the e-mail | ||
* @public */ | ||
this.mimeTree = this._createMimeNode(); | ||
/** | ||
* Current node of the multipart mime tree that is being processed | ||
* @private */ | ||
this._currentNode = this.mimeTree; | ||
/** | ||
* Current node of the multipart mime tree that is being processed | ||
* @private */ | ||
this._currentNode = this.mimeTree; | ||
// default values for the root node | ||
this._currentNode.priority = "normal"; | ||
// default values for the root node | ||
this._currentNode.priority = "normal"; | ||
/** | ||
* An object of already used attachment filenames | ||
* @private */ | ||
this._fileNames = {}; | ||
/** | ||
* An object of already used attachment filenames | ||
* @private */ | ||
this._fileNames = {}; | ||
/** | ||
* An array of multipart nodes | ||
* @private */ | ||
this._multipartTree = []; | ||
/** | ||
* An array of multipart nodes | ||
* @private */ | ||
this._multipartTree = []; | ||
/** | ||
* This is the final mail structure object that is returned to the client | ||
* @public */ | ||
this.mailData = {}; | ||
/** | ||
* This is the final mail structure object that is returned to the client | ||
* @public */ | ||
this.mailData = {}; | ||
/** | ||
* Line counter for debugging | ||
* @private */ | ||
this._lineCounter = 0; | ||
/** | ||
* Line counter for debugging | ||
* @private */ | ||
this._lineCounter = 0; | ||
/** | ||
* Did the last chunk end with \r | ||
* @private */ | ||
this._lineFeed = false; | ||
/** | ||
* Did the last chunk end with \r | ||
* @private */ | ||
this._lineFeed = false; | ||
/** | ||
* Is the "headers" event already emitted | ||
* @private */ | ||
this._headersSent = false; | ||
/** | ||
* Is the "headers" event already emitted | ||
* @private */ | ||
this._headersSent = false; | ||
/** | ||
* If the e-mail is in mbox format, unescape ">From " to "From " in body | ||
* @private */ | ||
this._isMbox = -1; | ||
} | ||
// inherit methods and properties of Stream | ||
/** | ||
* If the e-mail is in mbox format, unescape ">From " to "From " in body | ||
* @private */ | ||
this._isMbox = -1; | ||
} | ||
// inherit methods and properties of Stream | ||
utillib.inherits(MailParser, Stream); | ||
@@ -623,10 +623,10 @@ | ||
if (Object.prototype.toString.call(date) != "[object Date]" || date.toString() == "Invalid Date") { | ||
try{ | ||
date = datetime.strtotime(value); | ||
}catch(E){ | ||
return false; | ||
try { | ||
date = datetime.strtotime(value); | ||
} catch (E) { | ||
return false; | ||
} | ||
if (date) { | ||
date = new Date(date * 1000); | ||
}else{ | ||
} else { | ||
return false; | ||
@@ -766,3 +766,3 @@ } | ||
i = 0, | ||
parts, encoding, name; | ||
parts, encoding, name, part; | ||
@@ -782,9 +782,11 @@ if (value.name) { | ||
fileName = value["filename*"]; | ||
} else if (value["name*0*"]) { | ||
while (value["name*" + (i) + "*"]) { | ||
fileName += value["name*" + (i++) + "*"]; | ||
} else if (value["name*0*"] || value["name*0"]) { | ||
while ((part = (value["name*" + (i) + "*"] || value["name*" + (i)]))) { | ||
fileName += part; | ||
i++; | ||
} | ||
} else if (value["filename*0*"]) { | ||
while (value["filename*" + (i) + "*"]) { | ||
fileName += value["filename*" + (i++) + "*"]; | ||
} else if (value["filename*0*"] || value["filename*0"]) { | ||
while ((part = (value["filename*" + (i) + "*"] || value["filename*" + (i)]))) { | ||
fileName += part; | ||
i++; | ||
} | ||
@@ -1428,3 +1430,3 @@ } | ||
if (fileRootName in this._fileNames) { | ||
this._fileNames[fileRootName] ++; | ||
this._fileNames[fileRootName]++; | ||
ext = fileName.substr((fileName.lastIndexOf(".") || 0) + 1); | ||
@@ -1431,0 +1433,0 @@ if (ext == fileName) { |
@@ -198,3 +198,4 @@ "use strict"; | ||
filename = buffer.slice(0, Math.min(buffer.length, 1024)).toString().split(/\s/)[2] || ''; | ||
var re = /^begin [0-7]{3} (.*)/; | ||
filename = buffer.slice(0, Math.min(buffer.length, 1024)).toString().match(re)[1] || ''; | ||
if (!filename) { | ||
@@ -213,2 +214,2 @@ return new Buffer(0); | ||
return buffer; | ||
}; | ||
}; |
{ | ||
"name": "mailparser", | ||
"description": "Asynchronous and non-blocking parser for mime encoded e-mail messages", | ||
"version": "0.5.1", | ||
"version": "0.5.2", | ||
"author": "Andris Reinman", | ||
@@ -18,6 +18,3 @@ "maintainers": [{ | ||
"main": "./lib/mailparser", | ||
"licenses": [{ | ||
"type": "MIT", | ||
"url": "http://github.com/andris9/mailparser/blob/master/LICENSE" | ||
}], | ||
"license": "MIT", | ||
"dependencies": { | ||
@@ -27,3 +24,3 @@ "mimelib": "^0.2.19", | ||
"mime": "^1.3.4", | ||
"uue": "^2.1.0" | ||
"uue": "^2.1.1" | ||
}, | ||
@@ -38,2 +35,2 @@ "devDependencies": { | ||
] | ||
} | ||
} |
130
README.md
@@ -39,9 +39,9 @@ MailParser | ||
Require MailParser module | ||
var MailParser = require("mailparser").MailParser; | ||
```javascript | ||
var MailParser = require("mailparser").MailParser; | ||
``` | ||
Create a new MailParser object | ||
var mailparser = new MailParser([options]); | ||
```javascript | ||
var mailparser = new MailParser([options]); | ||
``` | ||
Options parameter is an object with the following properties: | ||
@@ -60,13 +60,15 @@ | ||
mailparser.on("headers", function(headers){ | ||
console.log(headers.received); | ||
}); | ||
```javascript | ||
mailparser.on("headers", function(headers){ | ||
console.log(headers.received); | ||
}); | ||
``` | ||
When the parsing ends an `'end'` event is emitted which has an | ||
object with parsed e-mail structure as a parameter. | ||
```javascript | ||
mailparser.on("end", function(mail){ | ||
mail; // object structure for parsed e-mail | ||
}); | ||
``` | ||
### Parsed mail object | ||
@@ -92,36 +94,34 @@ | ||
var MailParser = require("mailparser").MailParser, | ||
mailparser = new MailParser(); | ||
```javascript | ||
var MailParser = require("mailparser").MailParser, | ||
mailparser = new MailParser(); | ||
var email = "From: 'Sender Name' <sender@example.com>\r\n"+ | ||
"To: 'Receiver Name' <receiver@example.com>\r\n"+ | ||
"Subject: Hello world!\r\n"+ | ||
"\r\n"+ | ||
"How are you today?"; | ||
var email = "From: 'Sender Name' <sender@example.com>\r\n"+ | ||
"To: 'Receiver Name' <receiver@example.com>\r\n"+ | ||
"Subject: Hello world!\r\n"+ | ||
"\r\n"+ | ||
"How are you today?"; | ||
// setup an event listener when the parsing finishes | ||
mailparser.on("end", function(mail_object){ | ||
console.log("From:", mail_object.from); //[{address:'sender@example.com',name:'Sender Name'}] | ||
console.log("Subject:", mail_object.subject); // Hello world! | ||
console.log("Text body:", mail_object.text); // How are you today? | ||
}); | ||
mailparser.on("end", function(mail_object){ | ||
console.log("From:", mail_object.from); //[{address:'sender@example.com',name:'Sender Name'}] | ||
console.log("Subject:", mail_object.subject); // Hello world! | ||
console.log("Text body:", mail_object.text); // How are you today? | ||
}); | ||
// send the email source to the parser | ||
mailparser.write(email); | ||
mailparser.end(); | ||
mailparser.write(email); | ||
mailparser.end(); | ||
``` | ||
### Pipe file to MailParser | ||
This example pipes a `readableStream` file to **MailParser** | ||
var MailParser = require("mailparser").MailParser, | ||
mailparser = new MailParser(), | ||
fs = require("fs"); | ||
```javascript | ||
var MailParser = require("mailparser").MailParser, | ||
mailparser = new MailParser(), | ||
fs = require("fs"); | ||
mailparser.on("end", function(mail_object){ | ||
console.log("Subject:", mail_object.subject); | ||
}); | ||
console.log("Subject:", mail_object.subject); | ||
}); | ||
fs.createReadStream("email.eml").pipe(mailparser); | ||
fs.createReadStream("email.eml").pipe(mailparser); | ||
``` | ||
### Attachments | ||
@@ -134,12 +134,13 @@ | ||
mailparser.on("end", function(mail_object){ | ||
for(var i=0; i<mail_object.attachments.length; i++){ | ||
console.log(mail_object.attachments[i].fileName); | ||
} | ||
```javascript | ||
mailparser.on("end", function(mail_object){ | ||
mail_object.attachments.forEach(function(attachment){ | ||
console.log(attachment.fileName); | ||
}); | ||
}); | ||
``` | ||
#### Default behavior | ||
By default attachments will be included in the attachment objects as Buffers. | ||
```javascript | ||
attachments = [{ | ||
@@ -156,3 +157,3 @@ contentType: 'image/png', | ||
}]; | ||
``` | ||
The property `generatedFileName` is usually the same as `fileName` but if several | ||
@@ -168,7 +169,7 @@ different attachments with the same name exist or there is no `fileName` set, an | ||
to the `MailParser` constructor. | ||
var mp = new MailParser({ | ||
streamAttachments: true | ||
} | ||
```javascript | ||
var mp = new MailParser({ | ||
streamAttachments: true | ||
} | ||
``` | ||
This way there will be no `content` property on final attachment objects | ||
@@ -180,12 +181,11 @@ (but the other fields will remain). | ||
`fileName`, `contentId`) and a readable Stream object `stream`. | ||
var mp = new MailParser({ | ||
streamAttachments: true | ||
} | ||
mp.on("attachment", function(attachment, mail){ | ||
var output = fs.createWriteStream(attachment.generatedFileName); | ||
attachment.stream.pipe(output); | ||
}); | ||
```javascript | ||
var mp = new MailParser({ | ||
streamAttachments: true | ||
} | ||
mp.on("attachment", function(attachment, mail){ | ||
var output = fs.createWriteStream(attachment.generatedFileName); | ||
attachment.stream.pipe(output); | ||
}); | ||
``` | ||
`generatedFileName` is unique for the parsed mail - if several attachments with | ||
@@ -204,9 +204,9 @@ the same name exist, `generatedFileName` is updated accordingly. Also there | ||
Install **MailParser** with dev dependencies | ||
npm install --dev mailparser | ||
```bash | ||
npm install --dev mailparser | ||
``` | ||
And then run | ||
npm test mailparser | ||
```bash | ||
npm test mailparser | ||
``` | ||
There aren't many tests yet but basics should be covered. | ||
@@ -213,0 +213,0 @@ |
@@ -536,3 +536,21 @@ "use strict"; | ||
}, | ||
"Content-Disposition filename*X* mixed": function(test) { | ||
var encodedText = "Content-Type: application/octet-stream\r\n" + | ||
"Content-Transfer-Encoding: QUOTED-PRINTABLE\r\n" + | ||
"Content-Disposition: attachment;\r\n" + | ||
" filename*0*=UTF-8''%C3%95%C3%84;\r\n" + | ||
" filename*1*=%C3%96%C3%9C;\r\n" + | ||
" filename*2=.txt\r\n" + | ||
"\r\n" + | ||
"=00=01=02=03=FD=FE=FF", | ||
mail = new Buffer(encodedText, "utf-8"); | ||
var mailparser = new MailParser(); | ||
mailparser.end(mail); | ||
mailparser.on("end", function(mail) { | ||
test.equal(mail.attachments && mail.attachments[0] && mail.attachments[0].content && mail.attachments[0].fileName, "ÕÄÖÜ.txt"); | ||
test.done(); | ||
}); | ||
}, | ||
"Content-Type name": function(test) { | ||
@@ -720,4 +738,25 @@ var encodedText = "Content-Type: application/octet-stream; name=\"=?UTF-8?Q?=C3=95=C3=84=C3=96=C3=9C?=\"\r\n" + | ||
}); | ||
}, | ||
"UUE filename with special characters": function(test) { | ||
var encodedText = "Content-Type: multipart/mixed; boundary=ABC\r\n" + | ||
"\r\n" + | ||
"--ABC\r\n" + | ||
"Content-Type: application/octet-stream\r\n" + | ||
"Content-Transfer-Encoding: uuencode\r\n" + | ||
"Content-Disposition: attachment; filename=\"hello ~!@#%.txt\"\r\n" + | ||
"\r\n" + | ||
"begin 644 hello ~!@#%.txt\r\n" + | ||
"#0V%T\r\n" + | ||
"`\r\n" + | ||
"end\r\n" + | ||
"--ABC--", | ||
mail = new Buffer(encodedText, "utf-8"); | ||
var mailparser = new MailParser(); | ||
mailparser.end(mail); | ||
mailparser.on("end", function(mail) { | ||
test.equal(mail.attachments && mail.attachments[0] && mail.attachments[0].content && mail.attachments[0].generatedFileName, "hello ~!@#%.txt"); | ||
test.done(); | ||
}); | ||
} | ||
}; | ||
@@ -1577,2 +1616,2 @@ | ||
} | ||
}; | ||
}; |
139686
3183
Updateduue@^2.1.1