├── .gitignore ├── LICENSE ├── README.md ├── app.js ├── bin └── eml-unpack.js ├── index.js ├── lib └── eml-format.js ├── package.json └── test ├── build.js ├── common.js ├── fixtures ├── cc.eml ├── multipart.eml ├── nodejs.png └── sample.eml ├── parse.js ├── read.js ├── unpack.js └── unpack ├── index.html ├── index.txt └── nodejs.png /.gitignore: -------------------------------------------------------------------------------- 1 | # Additional 2 | .docs 3 | logs 4 | *.log 5 | test/unpack 6 | npm-debug.log* 7 | package-lock.json 8 | 9 | # Runtime data 10 | pids 11 | *.pid 12 | *.seed 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directory 30 | node_modules 31 | 32 | # Optional npm cache directory 33 | .npm 34 | 35 | # Optional REPL history 36 | .node_repl_history 37 | 38 | # Additional resource files 39 | .docs -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 papnkukn 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## EML file format 2 | 3 | A pure Node.js library for parsing and building EML files, i.e. the e-mail message format described in [RFC 822](http://www.ietf.org/rfc/rfc0822.txt) ([another link](https://www.w3.org/Protocols/rfc822/)). EML is returned by the POP3 protocol and handled by many e-mail agents like Mozilla Thunderbird or Microsoft Outlook. An EML file consists of headers and body similar to the HTTP structure. 4 | 5 | ``` 6 | File extension: .eml 7 | Mime type: message/rfc822 8 | ``` 9 | 10 | ### What does EML look like? 11 | 12 | ``` 13 | Date: Wed, 29 Jan 2014 11:10:06 +0100 14 | To: "Foo Bar" 15 | From: Online Shop 16 | Subject: Winter promotions 17 | Content-Type: text/plain; charset=utf-8 18 | 19 | Lorem ipsum... 20 | ``` 21 | 22 | ### Getting Started 23 | 24 | Setup 25 | ``` 26 | npm install -g eml-format 27 | ``` 28 | 29 | Read EML file 30 | ```javascript 31 | var fs = require('fs'); 32 | var emlformat = require('eml-format'); 33 | 34 | var eml = fs.readFileSync("sample.eml", "utf-8"); 35 | emlformat.read(eml, function(error, data) { 36 | if (error) return console.log(error); 37 | fs.writeFileSync("sample.json", JSON.stringify(data, " ", 2)); 38 | console.log(data); 39 | }); 40 | ``` 41 | 42 | Output structure 43 | ```javascript 44 | { 45 | "subject": "Winter promotions", 46 | "from": "Online Shop ", 47 | "to": "\"Foo Bar\" ", 48 | "headers": { 49 | "Date": "Wed, 29 Jan 2014 11:10:06 +0100", 50 | "To": "\"Foo Bar\" ", 51 | "From": "Online Shop ", 52 | "Subject": "Winter promotions", 53 | "Content-Type": "multipart/related; type=\"text/html\";\r\nboundary=\"b1_4afb675bba4c412783638afbee8e8c71\"", 54 | "MIME-Version": "1.0" 55 | }, 56 | "html": "\r\n\r\n\r\nLorem ipsum\r\n=09Lorem ipsum...
', 205 | attachments: [ 206 | { 207 | name: "sample.txt", 208 | contentType: "text/plain; charset=utf-8", 209 | data: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi eget elit turpis. Aliquam lorem nunc, dignissim in risus at, tempus aliquet justo..." 210 | }, 211 | { 212 | name: "nodejs.png", 213 | contentType: "image/png", 214 | data: fs.readFileSync("nodejs.png"), 215 | inline: true 216 | } 217 | ] 218 | }; 219 | 220 | emlformat.build(data, function(error, eml) { 221 | if (error) return console.log(error); 222 | fs.writeFileSync("build.eml", eml); 223 | console.log("Done!"); 224 | }); 225 | ``` 226 | 227 | ### Multiple e-mail addresses 228 | 229 | ```javascript 230 | var data = { 231 | from: "no-reply@bar.com", 232 | to: [ 233 | { name: "Foo", email: "foo@example.com" }, 234 | { name: "Bar", email: "bar@example.com" } 235 | ], 236 | cc: [ 237 | { name: "Foo Bar", email: "foo@bar.com" }, 238 | { email: "info@bar.com" } 239 | ], 240 | subject: "Winter promotions", 241 | ... 242 | }; 243 | ``` 244 | 245 | ### Register a new mime type file extension 246 | 247 | ```javascript 248 | var emlformat = require('eml-format'); 249 | emlformat.fileExtensions["application/zip"] = ".zip"; 250 | emlformat.fileExtensions["application/octet-stream"] = ".bin"; 251 | ``` 252 | 253 | ### Extract e-mail address and name 254 | 255 | Plain text name 256 | ```javascript 257 | var emlformat = require('eml-format'); 258 | var data = emlformat.getEmailAddress('"Foo Bar" '); 259 | //data.name == "Foo Bar"; 260 | //data.email == "foo@bar.com"; 261 | ``` 262 | 263 | UTF-8 encoded name 264 | ```javascript 265 | var emlformat = require('eml-format'); 266 | var data = emlformat.getEmailAddress('=?UTF-8?Q?You=E2=80=99re=20Foo=20Bar?= '); 267 | //data.name == "You’re Foo Bar"; 268 | //data.email == "foo@bar.com"; 269 | ``` 270 | 271 | Multiple e-mail addresses 272 | ```javascript 273 | var emlformat = require('eml-format'); 274 | var data = emlformat.getEmailAddress('"Foo Bar" , Example '); 275 | //data = [ 276 | // { name: "Foo Bar", email: "foo@bar.com" }, 277 | // { name: "Example", email: "info@example.com" } 278 | //] 279 | ``` 280 | 281 | ## Build e-mail address 282 | 283 | ```javascript 284 | var emlformat = require('eml-format'); 285 | var string = emlformat.toEmailAddress({ 286 | name: "Foo Bar", 287 | email: "foo@bar.com" 288 | }); 289 | //string = "Foo Bar" 290 | ``` 291 | 292 | ### Decode "quoted-printable" 293 | 294 | ```javascript 295 | var emlformat = require('eml-format'); 296 | var message = emlformat.unquotePrintable("Join line 1=\r\n=20with line 2=0D=0A"); 297 | ``` 298 | 299 | ### Decode "=?UTF-8?...?=" string 300 | 301 | ```javascript 302 | var emlformat = require('eml-format'); 303 | var message = emlformat.unquoteUTF8("=?UTF-8?B?V2hhdOKAmXMgeW91ciBvbmxpbmUgc2hvcHBpbmcgc3R5bGU/?="); 304 | ``` 305 | 306 | ### Decode other character set 307 | 308 | ```javascript 309 | var emlformat = require('eml-format'); 310 | var message = emlformat.unquoteString("=?ISO-8859-2?Q?Po=B9ta?="); 311 | ``` 312 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | var os = require('os'); 2 | var fs = require('fs'); 3 | var path = require('path'); 4 | var emlformat = require('./lib/eml-format.js'); 5 | 6 | var config = { 7 | verbose: process.env.NODE_VERBOSE == "true" || process.env.NODE_VERBOSE == "1", 8 | json: false, 9 | unpack: true 10 | }; 11 | 12 | //Prints help message 13 | function help() { 14 | console.log("Usage:"); 15 | console.log(" eml-unpack [options] [message.eml] [directory]"); 16 | console.log(""); 17 | console.log("Options:"); 18 | console.log(" --help Print this message"); 19 | console.log(" --verbose Enable detailed logging"); 20 | console.log(" --version Print version number"); 21 | console.log(" --json Create parsed.json and manifest.json"); 22 | console.log(" --no-unpack Used with --json to skip unpacking"); 23 | console.log(""); 24 | console.log("Examples:"); 25 | console.log(" eml-unpack message.eml ."); 26 | console.log(" eml-unpack --verbose sample.eml folder"); 27 | console.log(" eml-unpack --json --no-unpack ./sample.eml ./folder"); 28 | } 29 | 30 | //Command line arguments 31 | var args = process.argv.slice(2); 32 | for (var i = 0; i < args.length - 2; i++) { 33 | switch (args[i]) { 34 | case "--help": 35 | help(); 36 | process.exit(0); 37 | break; 38 | 39 | case "--version": 40 | console.log(require('./package.json').version); 41 | process.exit(0); 42 | break; 43 | 44 | case "--version": 45 | config.verbose = true; 46 | break; 47 | 48 | case "--json": 49 | config.json = true; 50 | break; 51 | 52 | case "--no-unpack": 53 | config.unpack = false; 54 | break; 55 | 56 | default: 57 | console.error("Unknown command line argument: " + args[i]); 58 | process.exit(1); 59 | break; 60 | } 61 | } 62 | 63 | if (args.length < 2) { 64 | help(); 65 | process.exit(1); 66 | } 67 | 68 | try { 69 | var src = args[args.length - 2]; 70 | var dst = args[args.length - 1]; 71 | 72 | if (!src) { 73 | throw new Error("Missing .eml file path!"); 74 | } 75 | 76 | if (!dst) { 77 | throw new Error("Missing output directory path or folder name!"); 78 | } 79 | 80 | var options = { }; 81 | if (config.json) { 82 | options.parsedJsonFile = "parsed.json"; 83 | options.readJsonFile = "manifest.json"; 84 | } 85 | if (!config.unpack) { 86 | options.simulate = true; 87 | } 88 | 89 | var eml = fs.readFileSync(src, "utf-8"); 90 | emlformat.verbose = config.verbose; 91 | emlformat.unpack(eml, dst, options, function(error, result) { 92 | if (error) { 93 | console.error(error); 94 | process.exit(1); 95 | return; 96 | } 97 | 98 | console.log("Done!"); 99 | }); 100 | } 101 | catch (e) { 102 | console.error(e); 103 | process.exit(1); 104 | } -------------------------------------------------------------------------------- /bin/eml-unpack.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | require('../app.js'); -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./lib/eml-format.js'); -------------------------------------------------------------------------------- /lib/eml-format.js: -------------------------------------------------------------------------------- 1 | /****************************************************************************************** 2 | * EML format parser. EML is raw e-mail message header + body as returned by POP3 protocol. 3 | * RFC 822: http://www.ietf.org/rfc/rfc0822.txt 4 | * RFC 1521: https://www.ietf.org/rfc/rfc1521.txt 5 | ******************************************************************************************/ 6 | 7 | var iconv = require('iconv-lite'); 8 | 9 | //Default character set 10 | var defaultCharset = 'utf-8'; //to use if charset=... is missing 11 | 12 | //Gets the character encoding name for iconv, e.g. 'iso-8859-2' -> 'iso88592' 13 | function getCharsetName(charset) { 14 | return charset.toLowerCase().replace(/[^0-9a-z]/g, ""); 15 | } 16 | 17 | //Generates a random id 18 | function guid() { 19 | return 'xxxxxxxxxxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { 20 | var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8); 21 | return v.toString(16); 22 | }).replace("-", ""); 23 | } 24 | 25 | //Word-wrap the string 's' to 'i' chars per row 26 | function wrap(s, i) { 27 | var a = [ ]; 28 | do { a.push(s.substring(0, i)) } 29 | while( (s = s.substring(i, s.length)) != "" ); 30 | return a.join("\r\n"); 31 | } 32 | 33 | //Overridable properties and functions 34 | var emlformat = { 35 | verbose: false, 36 | fileExtensions: { 37 | "text/plain": ".txt", 38 | "text/html": ".html", 39 | "image/png": ".png", 40 | "image/jpg": ".jpg", 41 | "image/jpeg": ".jpg", 42 | }, 43 | //Gets file extension by mime type 44 | getFileExtension: function(mimeType) { 45 | return emlformat.fileExtensions[mimeType] || ""; 46 | }, 47 | //Gets the boundary name 48 | getBoundary: function(contentType) { 49 | var match = /boundary="?(.+?)"?(\s*;[\s\S]*)?$/g.exec(contentType); 50 | return match ? match[1] : undefined; 51 | }, 52 | //Gets character set name, e.g. contentType='.....charset="iso-8859-2"....' 53 | getCharset: function(contentType) { 54 | var match = /charset\s*=\W*([\w\-]+)/g.exec(contentType); 55 | return match ? match[1] : undefined; 56 | }, 57 | //Gets name and e-mail address from a string, e.g. "PayPal" => { name: "PayPal", email: "noreply@paypal.com" } 58 | getEmailAddress: function(raw) { 59 | var list = [ ]; 60 | 61 | //Split around ',' char 62 | //var parts = raw.split(/,/g); //Will also split ',' inside the quotes 63 | //var parts = raw.match(/(".*?"|[^",\s]+)(?=\s*,|\s*$)/g); //Ignore ',' within the double quotes 64 | var parts = raw.match(/("[^"]*")|[^,]+/g); //Ignore ',' within the double quotes 65 | 66 | for (var i = 0; i < parts.length; i++) { 67 | var address = { }; 68 | 69 | //Quoted name but without the e-mail address 70 | if (/^".*"$/g.test(parts[i])) { 71 | address.name = emlformat.unquoteString(parts[i]).replace(/"/g, "").trim(); 72 | i++; //Shift to another part to capture e-mail address 73 | } 74 | 75 | var regex = /^(.*?)(\s*\<(.*?)\>)$/g; 76 | var match = regex.exec(parts[i]); 77 | if (match) { 78 | var name = emlformat.unquoteString(match[1]).replace(/"/g, "").trim(); 79 | if (name && name.length) { 80 | address.name = name; 81 | } 82 | address.email = match[3].trim(); 83 | list.push(address); 84 | } 85 | else { 86 | //E-mail address only (without the name) 87 | address.email = parts[i].trim(); 88 | list.push(address); 89 | } 90 | } 91 | 92 | //Return result 93 | if (list.length == 0) { 94 | return null; //No e-mail address 95 | } 96 | if (list.length == 1) { 97 | return list[0]; //Only one record, return as object, required to preserve backward compatibility 98 | } 99 | return list; //Multiple e-mail addresses as array 100 | }, 101 | //Builds e-mail address string, e.g. { name: "PayPal", email: "noreply@paypal.com" } => "PayPal" 102 | toEmailAddress: function(data) { 103 | var email = ""; 104 | if (typeof data == "undefined") { 105 | //No e-mail address 106 | } 107 | else if (typeof data == "string") { 108 | email = data; 109 | } 110 | else if (typeof data == "object") { 111 | if (Array.isArray(data)) { 112 | for (var i = 0; i < data.length; i++) { 113 | email += (email.length ? ', ' : ''); 114 | if (data[i].name) { 115 | email += '"' + data[i].name + '"'; 116 | } 117 | if (data[i].email) { 118 | email += (email.length ? ' ' : '') + '<' + data[i].email + '>'; 119 | } 120 | } 121 | } 122 | else { 123 | if (data.name) { 124 | email += '"' + data.name + '"'; 125 | } 126 | if (data.email) { 127 | email += (email.length ? ' ' : '') + '<' + data.email + '>'; 128 | } 129 | } 130 | } 131 | return email; 132 | }, 133 | //Decodes string by detecting the charset 134 | unquoteString: function(s) { 135 | var regex = /=\?([^?]+)\?(B|Q)\?(.+?)(\?=)/gi; 136 | var match = regex.exec(s); 137 | if (match) { 138 | var charset = getCharsetName(match[1] || defaultCharset); //eq. match[1] = 'iso-8859-2'; charset = 'iso88592' 139 | var type = match[2].toUpperCase(); 140 | var value = match[3]; 141 | if (type == "B") { //Base64 142 | if (charset == "utf8") { 143 | return Buffer.from(value.replace(/\r?\n/g, ""), "base64").toString("utf8"); 144 | } 145 | else { 146 | return iconv.decode(Buffer.from(value.replace(/\r?\n/g, ""), "base64"), charset); 147 | } 148 | } 149 | else if (type == "Q") { //Quoted printable 150 | return emlformat.unquotePrintable(value, charset); 151 | } 152 | } 153 | return s; 154 | }, 155 | //Decodes string like =?UTF-8?B?V2hhdOKAmXMgeW91ciBvbmxpbmUgc2hvcHBpbmcgc3R5bGU/?= or =?UTF-8?Q?...?= 156 | unquoteUTF8: function(s) { 157 | var regex = /=\?UTF\-8\?(B|Q)\?(.+?)(\?=)/gi; 158 | var match = regex.exec(s); 159 | if (match) { 160 | var type = match[1].toUpperCase(); 161 | var value = match[2]; 162 | if (type == "B") { //Base64 163 | return Buffer.from(value.replace(/\r?\n/g, ""), "base64").toString("utf8"); 164 | } 165 | else if (type == "Q") { //Quoted printable 166 | return emlformat.unquotePrintable(value); 167 | } 168 | } 169 | return s; 170 | }, 171 | //Decodes "quoted-printable" 172 | unquotePrintable: function(s, charset) { 173 | //Convert =0D to '\r', =20 to ' ', etc. 174 | if (!charset || charset == "utf8" || charset == "utf-8") { 175 | return s 176 | .replace(/=([\w\d]{2})=([\w\d]{2})=([\w\d]{2})/gi, function(matcher, p1, p2, p3, offset, string) { return Buffer.from([ parseInt(p1, 16), parseInt(p2, 16), parseInt(p3, 16) ]).toString("utf8"); }) 177 | .replace(/=([\w\d]{2})=([\w\d]{2})/gi, function(matcher, p1, p2, offset, string) { return Buffer.from([ parseInt(p1, 16), parseInt(p2, 16) ]).toString("utf8"); }) 178 | .replace(/=([\w\d]{2})/gi, function(matcher, p1, offset, string) { return String.fromCharCode(parseInt(p1, 16)); }) 179 | .replace(/=\r?\n/gi, ""); //Join line 180 | } 181 | else { 182 | return s 183 | .replace(/=([\w\d]{2})=([\w\d]{2})/gi, function(matcher, p1, p2, offset, string) { return iconv.decode(Buffer.from([ parseInt(p1, 16), parseInt(p2, 16) ]), charset); }) 184 | .replace(/=([\w\d]{2})/gi, function(matcher, p1, offset, string) { return iconv.decode(Buffer.from([ parseInt(p1, 16) ]), charset); }) 185 | .replace(/=\r?\n/gi, ""); //Join line 186 | } 187 | } 188 | }; 189 | 190 | /****************************************************************************************** 191 | * Unpacks EML message and attachments to a directory. 192 | * @params eml EML file content or object from 'parse' 193 | * @params directory Folder name or directory path where to unpack 194 | * @params options Optional parameters: { parsedJsonFile, readJsonFile, simulate } 195 | * @params callback Callback function(error) 196 | ******************************************************************************************/ 197 | emlformat.unpack = function(eml, directory, options, callback) { 198 | var fs = require("fs"); 199 | var path = require("path"); 200 | 201 | //Shift arguments 202 | if (typeof options == "function" && typeof callback == "undefined") { 203 | callback = options; 204 | options = null; 205 | } 206 | 207 | if (typeof callback != "function") { 208 | callback = function(error, result) { }; 209 | } 210 | 211 | var result = { files: [ ] }; 212 | 213 | function _unpack(data) { 214 | try { 215 | //Create the target directory 216 | if (!fs.existsSync(directory)) { 217 | fs.mkdirSync(directory); 218 | } 219 | 220 | //Plain text file 221 | if (typeof data.text == "string") { 222 | result.files.push("index.txt"); 223 | if (options && options.simulate) { 224 | //Skip writing to file 225 | } 226 | else { 227 | fs.writeFileSync(path.join(directory, "index.txt"), data.text); 228 | } 229 | } 230 | 231 | //Message in HTML format 232 | if (typeof data.html == "string") { 233 | result.files.push("index.html"); 234 | if (options && options.simulate) { 235 | //Skip writing to file 236 | } 237 | else { 238 | fs.writeFileSync(path.join(directory, "index.html"), data.html); 239 | } 240 | } 241 | 242 | //Attachments 243 | if (data.attachments && data.attachments.length > 0) { 244 | for (var i = 0; i < data.attachments.length; i++) { 245 | var attachment = data.attachments[i]; 246 | var filename = attachment.name; 247 | if (!filename) { 248 | filename = "attachment_" + (i + 1) + emlformat.getFileExtension(attachment.mimeType); 249 | } 250 | result.files.push(filename); 251 | if (options && options.simulate) continue; //Skip writing to file 252 | fs.writeFileSync(path.join(directory, filename), attachment.data); 253 | } 254 | } 255 | 256 | callback(null, result); 257 | } 258 | catch (e) { 259 | callback(e); 260 | } 261 | } 262 | 263 | //Check the directory argument 264 | if (typeof directory != "string" || directory.length == 0) { 265 | return callback(new Error("Directory argument is missing!")); 266 | } 267 | 268 | //Argument as EML file content or "parsed" version of object 269 | if (typeof eml == "string" || (typeof eml == "object" && eml.headers && eml.body)) { 270 | emlformat.parse(eml, function(error, parsed) { 271 | if (error) return callback(error); 272 | 273 | //Save parsed EML as JSON file 274 | if (options && options.parsedJsonFile) { 275 | var file = path.resolve(directory, options.parsedJsonFile); 276 | var dir = path.dirname(file); 277 | if (!fs.existsSync(dir)) { 278 | fs.mkdirSync(dir); 279 | } 280 | result.files.push(options.parsedJsonFile); 281 | fs.writeFileSync(file, JSON.stringify(parsed, " ", 2)); 282 | } 283 | 284 | //Convert parsed EML object to a friendly object with text, html and attachments 285 | emlformat.read(parsed, function(error, data) { 286 | if (error) return callback(error); 287 | 288 | //Save read structure as JSON file 289 | if (options && options.readJsonFile) { 290 | var file = path.resolve(directory, options.readJsonFile); 291 | var dir = path.dirname(file); 292 | if (!fs.existsSync(dir)) { 293 | fs.mkdirSync(dir); 294 | } 295 | result.files.push(options.readJsonFile); 296 | var json = data.attachments ? JSON.stringify(data) : JSON.stringify(data, " ", 2); //Attachments may be large, so make a compact JSON string 297 | fs.writeFileSync(file, json); 298 | } 299 | 300 | //Extract files from the EML file 301 | _unpack(data); 302 | }); 303 | }); 304 | } 305 | else if (typeof eml != "object") { 306 | return callback(new Error("Expected string or object as argument!")); 307 | } 308 | else { 309 | _unpack(eml); 310 | } 311 | }; 312 | 313 | /****************************************************************************************** 314 | * Parses EML file content and return user-friendly object. 315 | * @params data EML structure 316 | * @params options EML build options 317 | * @params callback Callback function(error, data) 318 | ******************************************************************************************/ 319 | emlformat.build = function(data, options, callback) { 320 | //Shift arguments 321 | if (typeof options == "function" && typeof callback == "undefined") { 322 | callback = options; 323 | options = null; 324 | } 325 | 326 | if (typeof callback != "function") { 327 | callback = function(error, result) { }; 328 | } 329 | 330 | var eml = ""; 331 | var EOL = "\r\n"; //End-of-line 332 | 333 | try { 334 | if (!data || typeof data != "object") { 335 | throw new Error("Argument 'data' expected to be an object!"); 336 | } 337 | 338 | if (!data.headers) { 339 | data.headers = { }; 340 | } 341 | 342 | if (typeof data.subject == "string") { 343 | data.headers["Subject"] = data.subject; 344 | } 345 | 346 | if (typeof data.from != "undefined") { 347 | data.headers["From"] = (typeof data.from == "string" ? data.from : emlformat.toEmailAddress(data.from)); 348 | } 349 | 350 | if (typeof data.to != "undefined") { 351 | data.headers["To"] = (typeof data.to == "string" ? data.to : emlformat.toEmailAddress(data.to)); 352 | } 353 | 354 | if (typeof data.cc != "undefined") { 355 | data.headers["Cc"] = (typeof data.cc == "string" ? data.cc : emlformat.toEmailAddress(data.cc)); 356 | } 357 | 358 | if (!data.headers["To"]) { 359 | throw new Error("Missing 'To' e-mail address!"); 360 | } 361 | 362 | var boundary = "----=" + guid(); 363 | if (typeof data.headers["Content-Type"] == "undefined") { 364 | data.headers["Content-Type"] = 'multipart/mixed;' + EOL + 'boundary="' + boundary + '"'; 365 | } 366 | else { 367 | var name = emlformat.getBoundary(data.headers["Content-Type"]); 368 | if (name) { 369 | boundary = name; 370 | } 371 | } 372 | 373 | //Build headers 374 | var keys = Object.keys(data.headers); 375 | for (var i = 0; i < keys.length; i++) { 376 | var key = keys[i]; 377 | var value = data.headers[key]; 378 | if (typeof value == "undefined") { 379 | continue; //Skip missing headers 380 | } 381 | else if (typeof value == "string") { 382 | eml += key + ": " + value.replace(/\r?\n/g, EOL + " ") + EOL; 383 | } 384 | else { //Array 385 | for (var j = 0; j < value.length; j++) { 386 | eml += key + ": " + value[j].replace(/\r?\n/g, EOL + " ") + EOL; 387 | } 388 | } 389 | } 390 | 391 | //Start the body 392 | eml += EOL; 393 | 394 | //Plain text content 395 | if (data.text) { 396 | eml += "--" + boundary + EOL; 397 | eml += "Content-Type: text/plain; charset=utf-8" + EOL; 398 | eml += EOL; 399 | eml += data.text; 400 | eml += EOL + EOL; 401 | } 402 | 403 | //HTML content 404 | if (data.html) { 405 | eml += "--" + boundary + EOL; 406 | eml += "Content-Type: text/html; charset=utf-8" + EOL; 407 | eml += EOL; 408 | eml += data.html; 409 | eml += EOL + EOL; 410 | } 411 | 412 | //Append attachments 413 | if (data.attachments) { 414 | for (var i = 0; i < data.attachments.length; i++) { 415 | var attachment = data.attachments[i]; 416 | eml += '--' + boundary + EOL; 417 | eml += 'Content-Type: ' + (attachment.contentType || "application/octet-stream") + EOL; 418 | eml += 'Content-Transfer-Encoding: base64' + EOL; 419 | eml += 'Content-Disposition: ' + (attachment.inline ? "inline" : "attachment") + '; filename="' + (attachment.filename || attachment.name || ("attachment_" + (i + 1))) + '"' + EOL; 420 | if (attachment.cid) { 421 | eml += 'Content-ID: <' + attachment.cid + ">" + EOL; 422 | } 423 | eml += EOL; 424 | if (typeof attachment.data == "string") { 425 | var content = Buffer.from(attachment.data).toString("base64"); 426 | eml += wrap(content, 76) + EOL; 427 | } 428 | else { //Buffer 429 | var content = attachment.data.toString("base64"); 430 | eml += wrap(content, 76) + EOL; 431 | } 432 | eml += EOL; 433 | } 434 | } 435 | 436 | //Finish the boundary 437 | eml += "--" + boundary + "--" + EOL; 438 | 439 | callback(null, eml); 440 | } 441 | catch (e) { 442 | callback(e); 443 | } 444 | }; 445 | 446 | /****************************************************************************************** 447 | * Parses EML file content and return user-friendly object. 448 | * @params eml EML file content or object from 'parse' 449 | * @params options EML parse options 450 | * @params callback Callback function(error, data) 451 | ******************************************************************************************/ 452 | emlformat.read = function(eml, options, callback) { 453 | //Shift arguments 454 | if (typeof options == "function" && typeof callback == "undefined") { 455 | callback = options; 456 | options = null; 457 | } 458 | 459 | if (typeof callback != "function") { 460 | callback = function(error, result) { }; 461 | } 462 | 463 | function _read(data) { 464 | try { 465 | var result = { }; 466 | if (data.headers["Date"]) { 467 | result.date = new Date(data.headers["Date"]); 468 | } 469 | if (data.headers["Subject"]) { 470 | result.subject = emlformat.unquoteString(data.headers["Subject"]); 471 | } 472 | if (data.headers["From"]) { 473 | result.from = emlformat.getEmailAddress(data.headers["From"]); 474 | } 475 | if (data.headers["To"]) { 476 | result.to = emlformat.getEmailAddress(data.headers["To"]); 477 | } 478 | if (data.headers["CC"]) { 479 | result.cc = emlformat.getEmailAddress(data.headers["CC"]); 480 | } 481 | if (data.headers["Cc"]) { 482 | result.cc = emlformat.getEmailAddress(data.headers["Cc"]); 483 | } 484 | result.headers = data.headers; 485 | 486 | //Appends the boundary to the result 487 | function _append(headers, content) { 488 | var contentType = headers["Content-Type"]; 489 | var charset = getCharsetName(emlformat.getCharset(contentType) || defaultCharset); 490 | var encoding = headers["Content-Transfer-Encoding"] || result.headers["Content-Transfer-Encoding"]; 491 | if (typeof encoding == "string") { 492 | encoding = encoding.toLowerCase(); 493 | } 494 | if (encoding == "base64") { 495 | if (contentType.indexOf("gbk") >= 0) { 496 | content = new Buffer(iconv.decode(new Buffer(content, 'base64'), 'gb2312'), 'utf8'); 497 | } 498 | else { 499 | content = Buffer.from(content.replace(/\r?\n/g, ""), "base64"); 500 | } 501 | } 502 | else if (encoding == "quoted-printable") { 503 | content = emlformat.unquotePrintable(content, charset); 504 | } 505 | else if (charset != "utf8" && (encoding.startsWith("binary") || encoding.startsWith("8bit"))) { 506 | //"8bit", "binary", "8bitmime", "binarymime" 507 | content = iconv.decode(Buffer.from(content,'binary'), charset); 508 | } 509 | if (!result.html && contentType && contentType.indexOf("text/html") >= 0) { 510 | if (typeof content != "string") { 511 | //content = content.toString("utf8"); 512 | content = iconv.decode(Buffer.from(content), charset); 513 | } 514 | //Message in HTML format 515 | result.html = content; 516 | } 517 | else if (!result.text && contentType && contentType.indexOf("text/plain") >= 0) { 518 | if (typeof content != "string") { 519 | //content = content.toString("utf8"); 520 | content = iconv.decode(Buffer.from(content), charset); 521 | } 522 | //Plain text message 523 | result.text = content; 524 | } 525 | else if(!result.text && contentType && contentType.indexOf("multipart") >= 0) { 526 | if(Array.isArray(content)){ 527 | for(var i=0;iLorem ipsum...
', 16 | attachments: [ 17 | { 18 | name: "sample.txt", 19 | contentType: "text/plain; charset=utf-8", 20 | data: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi eget elit turpis. Aliquam lorem nunc, dignissim in risus at, tempus aliquet justo. In in libero pharetra, tristique est sed, semper diam. Phasellus faucibus eleifend neque. Etiam vitae dolor non turpis finibus condimentum id vitae dolor. Pellentesque vulputate nisi erat, porttitor iaculis ligula euismod nec. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed laoreet, turpis at blandit consequat, mauris enim volutpat augue, vel congue nisi quam quis nibh. Pellentesque ultrices tellus eget ullamcorper accumsan. Suspendisse mattis sit amet enim eu congue." 21 | }, 22 | { 23 | name: "nodejs.png", 24 | contentType: "image/png", 25 | data: fs.readFileSync(path.join(__dirname, "./fixtures/nodejs.png")), 26 | inline: true 27 | } 28 | ] 29 | }; 30 | 31 | emlformat.verbose = false; 32 | emlformat.build(data, function(error, eml) { 33 | if (error) { 34 | test.ok(false, error.message); 35 | } 36 | else { 37 | //fs.writeFileSync("build.eml", eml); 38 | test.ok(typeof eml == "string", "Expected to be string"); 39 | test.ok(eml.length > 0, "Expected string length > 0"); 40 | test.ok(eml.indexOf("From: no-reply@bar.com\r\n") >= 0, "Expected the 'From' header"); 41 | test.ok(eml.indexOf("To: \"Foo Bar\" \r\n") >= 0, "Expected the 'To' header"); 42 | test.ok(eml.indexOf("\r\n\r\n") >= 0, "Expected new lines between header and body"); 43 | } 44 | test.done(); 45 | }); 46 | }; 47 | 48 | exports["Rebuild sample.eml"] = function(test) { 49 | var expected, actual; 50 | var src = path.join(__dirname, "./fixtures/sample.eml"); 51 | var eml = fs.readFileSync(src, "utf-8"); 52 | 53 | emlformat.verbose = false; 54 | emlformat.read(eml, function(error, data) { 55 | if (error) { 56 | test.ok(false, error.message); 57 | test.done(); 58 | return; 59 | } 60 | 61 | emlformat.build(data, function(error, eml) { 62 | if (error) { 63 | test.ok(false, error.message); 64 | } 65 | else { 66 | //fs.writeFileSync("rebuild.eml", eml); 67 | test.ok(typeof eml == "string", "Expected to be string"); 68 | test.ok(eml.length > 0, "Expected string length > 0"); 69 | test.ok(eml.indexOf("From: " + data.headers["From"] + "\r\n") >= 0, "Expected the 'From' header"); 70 | test.ok(eml.indexOf("To: " + data.headers["To"] + "\r\n") >= 0, "Expected the 'To' header"); 71 | test.ok(eml.indexOf("Subject: " + data.headers["Subject"] + "\r\n") >= 0, "Expected the 'Subject' header"); 72 | test.ok(eml.indexOf("\r\n\r\n") >= 0, "Expected new lines between header and body"); 73 | } 74 | test.done(); 75 | }); 76 | }); 77 | }; 78 | -------------------------------------------------------------------------------- /test/common.js: -------------------------------------------------------------------------------- 1 | var fs = require("fs"); 2 | var path = require("path"); 3 | var emlformat = require("../lib/eml-format.js"); 4 | 5 | exports["File extension"] = function(test) { 6 | var mimeType = "text/plain"; 7 | var ext = emlformat.getFileExtension(mimeType); 8 | test.ok(ext == ".txt", "Expected .txt but got " + ext); 9 | test.done(); 10 | }; 11 | 12 | exports["Email address"] = function(test) { 13 | var email, data; 14 | 15 | email = "foo@bar.com"; 16 | data = emlformat.getEmailAddress(email); 17 | test.ok(typeof data == "object"); 18 | test.ok(typeof data.email == "string"); 19 | test.ok(data.email == "foo@bar.com"); 20 | 21 | email = ""; 22 | data = emlformat.getEmailAddress(email); 23 | test.ok(typeof data == "object"); 24 | test.ok(typeof data.email == "string"); 25 | test.ok(data.email == "foo_12.36@bar.com"); 26 | 27 | email = "Foo Bar "; 28 | data = emlformat.getEmailAddress(email); 29 | test.ok(typeof data == "object"); 30 | test.ok(typeof data.name == "string"); 31 | test.ok(typeof data.email == "string"); 32 | test.ok(data.email == "foo@bar.com", 'Expected "foo@bar.com" but got ' + data.email); 33 | test.ok(data.name == "Foo Bar", 'Expected "Foo Bar" but got ' + data.name); 34 | 35 | email = '"Foo Bar" '; 36 | data = emlformat.getEmailAddress(email); 37 | test.ok(typeof data == "object"); 38 | test.ok(typeof data.name == "string"); 39 | test.ok(typeof data.email == "string"); 40 | test.ok(data.email == "foo@bar.com", 'Expected "foo@bar.com" but got ' + data.email); 41 | test.ok(data.name == "Foo Bar", 'Expected "Foo Bar" but got ' + data.name); 42 | 43 | email = '=?UTF-8?Q?You=E2=80=99re=20Foo=20Bar?= '; 44 | data = emlformat.getEmailAddress(email); 45 | test.ok(typeof data == "object"); 46 | test.ok(typeof data.name == "string"); 47 | test.ok(typeof data.email == "string"); 48 | test.ok(data.email == "foo@bar.com", 'Expected "foo@bar.com" but got ' + data.email); 49 | test.ok(data.name == "You’re Foo Bar", 'Expected "You’re Foo Bar" but got ' + data.name); 50 | 51 | email = 'foo@example.com, "Bar" , =?UTF-8?Q?You=E2=80=99re=20Foo=20Bar?= '; 52 | data = emlformat.getEmailAddress(email); 53 | test.ok(typeof data == "object"); 54 | test.ok(Array.isArray(data)); 55 | test.ok(data.length == 3); 56 | test.ok(typeof data[0].name == "undefined"); 57 | test.ok(typeof data[0].email == "string"); 58 | test.ok(typeof data[1].name == "string"); 59 | test.ok(typeof data[1].email == "string") 60 | test.ok(data[1].name == "Bar", 'Expected "Bar" but got ' + data[1].name); 61 | test.ok(typeof data[2].name == "string"); 62 | test.ok(typeof data[2].email == "string") 63 | test.ok(data[2].name == "You’re Foo Bar", 'Expected "You’re Foo Bar" but got ' + data[2].name); 64 | 65 | //Build e-mail address string from array 66 | //expected = ', "Bar" , "You\'re Foo Bar" '; 67 | //actual = emlformat.toEmailAddress(data); 68 | //test.ok(actual == expected, 'Expected "' + expected + '" but got "' + actual + '"'); 69 | 70 | test.done(); 71 | }; 72 | 73 | exports["Unquote string"] = function(test) { 74 | var fixture, expected, actual; 75 | 76 | //Q = Quoted 77 | fixture = "=?UTF-8?Q?You=E2=80=99ve_added_a_card?="; 78 | expected = "You’ve_added_a_card"; 79 | actual = emlformat.unquoteString(fixture); 80 | test.ok(actual == expected, 'Expected "' + expected + '" but got "' + actual + '"'); 81 | 82 | //B = Base64 83 | fixture = "=?UTF-8?B?V2hhdOKAmXMgeW91ciBvbmxpbmUgc2hvcHBpbmcgc3R5bGU/?="; 84 | expected = "What’s your online shopping style?"; 85 | actual = emlformat.unquoteString(fixture); 86 | test.ok(actual == expected, 'Expected "' + expected + '" but got "' + actual + '"'); 87 | 88 | //ISO 8859-2 character set 89 | fixture = "=?ISO-8859-2?Q?Po=B9ta?="; 90 | expected = "Pošta"; 91 | actual = emlformat.unquoteString(fixture); 92 | test.ok(actual == expected, 'Expected "' + expected + '" but got "' + actual + '"'); 93 | 94 | test.done(); 95 | }; 96 | 97 | 98 | exports["Unquote UTF8"] = function(test) { 99 | var fixture, expected, actual; 100 | 101 | //Q = Quoted 102 | fixture = "=?UTF-8?Q?You=E2=80=99ve_added_a_card?="; 103 | expected = "You’ve_added_a_card"; 104 | actual = emlformat.unquoteUTF8(fixture); 105 | test.ok(actual == expected, 'Expected "' + expected + '" but got "' + actual + '"'); 106 | 107 | //B = Base64 108 | fixture = "=?UTF-8?B?V2hhdOKAmXMgeW91ciBvbmxpbmUgc2hvcHBpbmcgc3R5bGU/?="; 109 | expected = "What’s your online shopping style?"; 110 | actual = emlformat.unquoteUTF8(fixture); 111 | test.ok(actual == expected, 'Expected "' + expected + '" but got "' + actual + '"'); 112 | 113 | test.done(); 114 | }; 115 | 116 | exports["Unquote printable"] = function(test) { 117 | var fixture, expected, actual; 118 | 119 | fixture = "You=E2=80=99ve added a card"; 120 | expected = "You’ve added a card"; 121 | actual = emlformat.unquotePrintable(fixture); 122 | test.ok(actual == expected, 'Expected "' + expected + '" but got "' + actual + '"'); 123 | 124 | fixture = "A line=0D=0A"; 125 | expected = "A line\r\n"; 126 | actual = emlformat.unquotePrintable(fixture); 127 | test.ok(actual == expected, 'Expected "' + expected + '" but got "' + actual + '"'); 128 | 129 | fixture = "Join line 1=\r\n=20with line 2=0D=0A"; 130 | expected = "Join line 1 with line 2\r\n"; 131 | actual = emlformat.unquotePrintable(fixture); 132 | test.ok(actual == expected, 'Expected "' + expected + '" but got "' + actual + '"'); 133 | 134 | test.done(); 135 | }; 136 | -------------------------------------------------------------------------------- /test/fixtures/cc.eml: -------------------------------------------------------------------------------- 1 | Delivered-To: foo.bar@example.com 2 | Return-Path: 3 | To: Foo Bar , info@example.com 4 | Cc: foo@example.com, Bar 5 | From: =?UTF-8?Q?Foo_Bar?= 6 | Subject: To and Cc headers 7 | Message-ID: 8 | Date: Sat, 12 Oct 2019 20:09:08 +0200 9 | User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:60.0) Gecko/20100101 10 | Thunderbird/60.8.0 11 | MIME-Version: 1.0 12 | Content-Type: text/plain; charset=utf-8; format=flowed 13 | Content-Transfer-Encoding: 7bit 14 | Content-Language: en-US 15 | X-ZohoMailClient: External 16 | 17 | -------------------------------------------------------------------------------- /test/fixtures/multipart.eml: -------------------------------------------------------------------------------- 1 | From: Foo Bar 2 | Subject: Multi-part boundary 3 | To: foo.bar@example.com 4 | Date: Sun, 29 Apr 2018 14:05:09 -0400 5 | User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 6 | Thunderbird/52.7.0 7 | MIME-Version: 1.0 8 | Content-Type: multipart/mixed; 9 | boundary="------------194F0B6C07FF2414138ED9B2" 10 | Content-Language: en-US 11 | 12 | This is a multi-part message in MIME format. 13 | --------------194F0B6C07FF2414138ED9B2 14 | Content-Type: text/plain; charset=utf-8; format=flowed 15 | Content-Transfer-Encoding: 7bit 16 | 17 | please see attached 18 | 19 | 20 | --------------194F0B6C07FF2414138ED9B2 21 | Content-Type: image/jpeg; 22 | name="tired_boot.FJ010019.jpeg" 23 | Content-Transfer-Encoding: base64 24 | Content-Disposition: attachment; 25 | filename="tired_boot.FJ010019.jpeg" 26 | 27 | /9j/4AAQSkZJRgABAQEAYABgAAD//gA7Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJ 28 | SkcgSlBFRyB2ODApLCBxdWFsaXR5ID0gOTAK/9sAQwADAgIDAgIDAwMDBAMDBAUIBQUEBAUK 29 | BwcGCAwKDAwLCgsLDQ4SEA0OEQ4LCxAWEBETFBUVFQwPFxgWFBgSFBUU/9sAQwEDBAQFBAUJ 30 | BQUJFA0LDRQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQU 31 | FBQU/8AAEQgAyACFAwEiAAIRAQMRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkK 32 | C//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHw 33 | JDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3 34 | eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY 35 | 2drh4uPk5ebn6Onq8fLz9PX29/j5+v/EAB8BAAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkK 36 | C//EALURAAIBAgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1Lw 37 | FWJy0QoWJDThJfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2 38 | d3h5eoKDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW 39 | 19jZ2uLj5OXm5+jp6vLz9PX29/j5+v/aAAwDAQACEQMRAD8Aow+LJby2+z/2i8Mlu+3JGN30 40 | rZl8TTtbOseog/J84bnA9q51/D1j5cXntZWVs6cSzbt6n19BxVuz0zw22jT3aa010Adqi1GC 41 | fbPpQBPonjPR2RpI7nzp4zs8uMZP41qzWsuu6VcSW8e4g5279pP4ZFYmj+F9Gtom1VZlsbkN 42 | k/JkH03e9Y9/8Mpr/VJtQTW9TFxJnYlspCke2OKANGJCuAIGtynBJPBrO1PxCItRh05LFxv5 43 | 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 220 | iiigBM5oOc0UUAJu9eKKKKAP/9k= 221 | --------------194F0B6C07FF2414138ED9B2-- 222 | -------------------------------------------------------------------------------- /test/fixtures/nodejs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/papnkukn/eml-format/5f4abb637d493e7263bd4d26a45bbe308874c15b/test/fixtures/nodejs.png -------------------------------------------------------------------------------- /test/fixtures/sample.eml: -------------------------------------------------------------------------------- 1 | Date: Wed, 29 Jan 2014 11:10:06 +0100 2 | To: "Foo Bar" 3 | From: Online Shop 4 | Subject: Winter promotions 5 | Content-Type: multipart/related; type="text/html"; 6 | boundary="b1_4afb675bba4c412783638afbee8e8c71" 7 | MIME-Version: 1.0 8 | 9 | --b1_4afb675bba4c412783638afbee8e8c71 10 | Content-Type: multipart/alternative; 11 | boundary="b2_4afb675bba4c412783638afbee8e8c71" 12 | 13 | --b2_4afb675bba4c412783638afbee8e8c71 14 | Content-Type: text/plain; charset="UTF-8" 15 | Content-Transfer-Encoding: quoted-printable 16 | 17 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris enim orci, = 18 | semper vel egestas nec, tempor sit amet nunc. Quisque pulvinar eleifend mas= 19 | sa, sit amet posuere lorem vehicula et. Nam elementum nulla eget nisl ultri= 20 | ces vulputate. Sed molestie ipsum at neque molestie tempor vel et augue. Na= 21 | m magna velit, cursus sed lectus eu, bibendum viverra orci. Morbi quis risu= 22 | s sed nunc pharetra mattis. Suspendisse ut consectetur risus. Donec in susc= 23 | ipit purus, eget aliquet dui. In vitae suscipit est. Suspendisse sollicitud= 24 | in, nisl sed scelerisque pulvinar, nibh mi viverra diam, et convallis nibh = 25 | urna id sem. Nunc eros ante, semper sed ex vitae, iaculis tristique sapien.= 26 | Maecenas molestie leo a iaculis viverra. Vivamus tristique enim vel ligula= 27 | semper tristique et congue ex. Praesent auctor egestas augue ut molestie. = 28 | Integer vulputate tortor quis tempor faucibus.=0D=0A 29 | Curabitur sed accumsan od 30 | io. Integer vestibulum in sem nec vestibulum. Donec imperdiet turpis a fauc= 31 | ibus volutpat. Suspendisse varius rhoncus eros, non rutrum justo pellentesq= 32 | ue sit amet. In risus lectus, blandit sit amet magna a, porttitor pulvinar = 33 | justo. Curabitur tincidunt metus at luctus fermentum. Cras vehicula dui ege= 34 | t semper vulputate. Ut sed leo non arcu imperdiet ultrices et eu dolor. Ves= 35 | tibulum aliquet sed elit a gravida. Aenean vitae est nec tellus molestie fr= 36 | ingilla in eget enim. Morbi sodales auctor erat, eget posuere nisl condimen= 37 | tum aliquet. Phasellus commodo metus aliquet vestibulum ultricies. Quisque = 38 | eleifend in mi vitae imperdiet. Quisque sit amet luctus nisl, vel sagittis = 39 | mi. Etiam tellus tortor, blandit ut eros quis, iaculis eros.=0D=0A 40 | 41 | --b2_4afb675bba4c412783638afbee8e8c71 42 | Content-Type: text/html; charset="UTF-8" 43 | Content-Transfer-Encoding: quoted-printable 44 | 45 | 46 | 47 | 48 | Lorem ipsum 49 | =0= 50 | 9 54 | =09 56 | =09 58 | 59 | 60 | =09

Lorem ipsum dolor sit amet, co= 61 | nsectetur adipiscing elit. Mauris enim orci, semper vel egestas nec, tempor= 62 | sit amet nunc. Quisque pulvinar eleifend massa, sit amet posuere lorem veh= 63 | icula et. Nam elementum nulla eget nisl ultrices vulputate. Sed molestie ip= 64 | sum at neque molestie tempor vel et augue. Nam magna velit, cursus sed lect= 65 | us eu, bibendum viverra orci. Morbi quis risus sed nunc pharetra mattis. Su= 66 | spendisse ut consectetur risus. Donec in suscipit purus, eget aliquet dui. = 67 | In vitae suscipit est. Suspendisse sollicitudin, nisl sed scelerisque pulvi= 68 | nar, nibh mi viverra diam, et convallis nibh urna id sem. Nunc eros ante, s= 69 | emper sed ex vitae, iaculis tristique sapien. Maecenas molestie leo a iacul= 70 | is viverra. Vivamus tristique enim vel ligula semper tristique et congue ex= 71 | . Praesent auctor egestas augue ut molestie. Integer vulputate tortor quis = 72 | tempor faucibus.

73 | =09

Curabitur sed accumsan odio. Integer vestibulum= 74 | in sem nec vestibulum. Donec imperdiet turpis a faucibus volutpat. Suspend= 75 | isse varius rhoncus eros, non rutrum justo pellentesque sit amet. In risus = 76 | lectus, blandit sit amet magna a, porttitor pulvinar justo. Curabitur tinci= 77 | dunt metus at luctus fermentum. Cras vehicula dui eget semper vulputate. Ut= 78 | sed leo non arcu imperdiet ultrices et eu dolor. Vestibulum aliquet sed el= 79 | it a gravida. Aenean vitae est nec tellus molestie fringilla in eget enim. = 80 | Morbi sodales auctor erat, eget posuere nisl condimentum aliquet. Phasellus= 81 | commodo metus aliquet vestibulum ultricies. Quisque eleifend in mi vitae i= 82 | mperdiet. Quisque sit amet luctus nisl, vel sagittis mi. Etiam tellus torto= 83 | r, blandit ut eros quis, hendrerit iaculis eros.

84 | 85 | 86 | 87 | 88 | --b2_4afb675bba4c412783638afbee8e8c71-- 89 | 90 | --b1_4afb675bba4c412783638afbee8e8c71 91 | Content-Type: image/png; name="nodejs.png" 92 | Content-Transfer-Encoding: base64 93 | Content-Disposition: inline; filename="nodejs.png" 94 | 95 | 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 451 | 452 | --b1_4afb675bba4c412783638afbee8e8c71-- 453 | -------------------------------------------------------------------------------- /test/parse.js: -------------------------------------------------------------------------------- 1 | var fs = require("fs"); 2 | var path = require("path"); 3 | var emlformat = require("../lib/eml-format.js"); 4 | 5 | exports["Parse sample.eml"] = function(test) { 6 | var expected, actual; 7 | var src = path.join(__dirname, "./fixtures/sample.eml"); 8 | var eml = fs.readFileSync(src, "utf-8"); 9 | 10 | emlformat.verbose = false; 11 | emlformat.parse(eml, function(error, result) { 12 | if (error) { 13 | test.ok(false, error.message); 14 | } 15 | else { 16 | //fs.writeFileSync("parse.json", JSON.stringify(result, " ", 2)) 17 | 18 | test.ok(typeof result == "object"); 19 | test.ok(typeof result.headers == "object"); 20 | test.ok(typeof result.body == "object"); 21 | 22 | expected = "Wed, 29 Jan 2014 11:10:06 +0100"; 23 | actual = result.headers["Date"]; 24 | test.ok(actual == expected, 'Expected "' + expected + '" but got "' + actual + '"'); 25 | 26 | expected = "Winter promotions"; 27 | actual = result.headers["Subject"]; 28 | test.ok(actual == expected, 'Expected "' + expected + '" but got "' + actual + '"'); 29 | 30 | expected = 'multipart/related; type="text/html";\r\nboundary="b1_4afb675bba4c412783638afbee8e8c71"'; 31 | actual = result.headers["Content-Type"]; 32 | test.ok(actual == expected, 'Expected "' + expected + '" but got "' + actual + '"'); 33 | 34 | expected = 2; 35 | actual = result.body.length; 36 | test.ok(actual == expected, 'Expected "' + expected + '" but got "' + actual + '"'); 37 | } 38 | test.done(); 39 | }); 40 | }; 41 | -------------------------------------------------------------------------------- /test/read.js: -------------------------------------------------------------------------------- 1 | var fs = require("fs"); 2 | var path = require("path"); 3 | var emlformat = require("../lib/eml-format.js"); 4 | 5 | exports["Read sample.eml"] = function(test) { 6 | var expected, actual; 7 | var src = path.join(__dirname, "./fixtures/sample.eml"); 8 | var eml = fs.readFileSync(src, "utf-8"); 9 | 10 | emlformat.verbose = false; 11 | emlformat.read(eml, function(error, result) { 12 | if (error) { 13 | test.ok(false, error.message); 14 | } 15 | else { 16 | //fs.writeFileSync("read.json", JSON.stringify(result, " ", 2)) 17 | 18 | test.ok(typeof result == "object"); 19 | test.ok(typeof result.headers == "object"); 20 | test.ok(typeof result.subject == "string"); 21 | test.ok(typeof result.from == "object"); 22 | test.ok(typeof result.to == "object"); 23 | test.ok(typeof result.text == "string"); 24 | test.ok(typeof result.html == "string"); 25 | 26 | expected = "Winter promotions"; 27 | actual = result.subject; 28 | test.ok(actual == expected, 'Expected "' + expected + '" but got "' + actual + '"'); 29 | 30 | expected = "Foo Bar"; 31 | actual = result.to.name; 32 | test.ok(actual == expected, 'Expected "' + expected + '" but got "' + actual + '"'); 33 | 34 | expected = "foo.bar@example.com"; 35 | actual = result.to.email; 36 | test.ok(actual == expected, 'Expected "' + expected + '" but got "' + actual + '"'); 37 | 38 | expected = "Online Shop"; 39 | actual = result.from.name; 40 | test.ok(actual == expected, 'Expected "' + expected + '" but got "' + actual + '"'); 41 | 42 | expected = "no-reply@example.com"; 43 | actual = result.from.email; 44 | test.ok(actual == expected, 'Expected "' + expected + '" but got "' + actual + '"'); 45 | 46 | expected = "Lorem ipsum dolor sit amet"; 47 | actual = result.text; 48 | test.ok(actual.indexOf(expected) == 0, 'Expected "' + expected + '" but got "' + actual + '"'); 49 | 50 | actual = result.text; 51 | test.ok(actual.indexOf("=") == -1, 'Expected quoted-printable string to be decoded!'); 52 | 53 | expected = ""; 54 | actual = result.html; 55 | test.ok(actual.indexOf(expected) == 0, 'Expected "' + expected + '" but got "' + actual + '"'); 56 | } 57 | test.done(); 58 | }); 59 | }; 60 | 61 | exports["Read multi-part boundaries"] = function(test) { 62 | var expected, actual; 63 | var src = path.join(__dirname, "./fixtures/multipart.eml"); 64 | var eml = fs.readFileSync(src, "utf-8"); 65 | 66 | emlformat.verbose = false; 67 | emlformat.read(eml, function(error, result) { 68 | if (error) { 69 | test.ok(false, error.message); 70 | } 71 | else { 72 | test.ok(typeof result == "object"); 73 | test.ok(typeof result.headers == "object"); 74 | test.ok(typeof result.subject == "string"); 75 | test.ok(typeof result.from == "object"); 76 | test.ok(typeof result.to == "object"); 77 | test.ok(typeof result.text == "string"); 78 | test.ok(typeof result.attachments != "undefined"); 79 | test.ok(result.attachments.length == 1); 80 | 81 | expected = "Multi-part boundary"; 82 | actual = result.subject; 83 | test.ok(actual == expected, 'Expected "' + expected + '" but got "' + actual + '"'); 84 | 85 | expected = "Foo Bar"; 86 | actual = result.from.name; 87 | test.ok(actual == expected, 'Expected "' + expected + '" but got "' + actual + '"'); 88 | 89 | expected = "foo.bar@example.com"; 90 | actual = result.to.email; 91 | test.ok(actual == expected, 'Expected "' + expected + '" but got "' + actual + '"'); 92 | 93 | expected = "please see attached"; 94 | actual = result.text; 95 | test.ok(actual.indexOf(expected) == 0, 'Expected "' + expected + '" but got "' + actual + '"'); 96 | 97 | expected = "tired_boot.FJ010019.jpeg"; 98 | actual = result.attachments[0].name; 99 | test.ok(actual.indexOf(expected) == 0, 'Expected "' + expected + '" but got "' + actual + '"'); 100 | } 101 | test.done(); 102 | }); 103 | }; 104 | 105 | exports["Read multiple To and Cc"] = function(test) { 106 | var expected, actual; 107 | var src = path.join(__dirname, "./fixtures/cc.eml"); 108 | var eml = fs.readFileSync(src, "utf-8"); 109 | 110 | emlformat.verbose = false; 111 | emlformat.read(eml, function(error, result) { 112 | if (error) { 113 | test.ok(false, error.message); 114 | } 115 | else { 116 | test.ok(typeof result == "object"); 117 | test.ok(typeof result.headers == "object"); 118 | test.ok(typeof result.from == "object"); 119 | test.ok(typeof result.to == "object"); 120 | test.ok(typeof result.cc == "object"); 121 | test.ok(Array.isArray(result.to), "Expected array from 'To' header"); 122 | test.ok(result.to.length == 2, "Expected two e-mail in 'To' header"); 123 | test.ok(Array.isArray(result.cc), "Expected array from 'Cc' header"); 124 | test.ok(result.cc.length == 2, "Expected two e-mail in 'Cc' header"); 125 | 126 | expected = "Foo_Bar"; 127 | actual = result.from.name; 128 | test.ok(actual == expected, 'Expected "' + expected + '" but got "' + actual + '"'); 129 | 130 | expected = "Foo Bar"; 131 | actual = result.to[0].name; 132 | test.ok(actual == expected, 'Expected "' + expected + '" but got "' + actual + '"'); 133 | 134 | expected = "foo.bar@example.com"; 135 | actual = result.to[0].email; 136 | test.ok(actual == expected, 'Expected "' + expected + '" but got "' + actual + '"'); 137 | 138 | expected = "Bar"; 139 | actual = result.cc[1].name; 140 | test.ok(actual == expected, 'Expected "' + expected + '" but got "' + actual + '"'); 141 | 142 | expected = "bar@example.com"; 143 | actual = result.cc[1].email; 144 | test.ok(actual == expected, 'Expected "' + expected + '" but got "' + actual + '"'); 145 | } 146 | test.done(); 147 | }); 148 | }; 149 | -------------------------------------------------------------------------------- /test/unpack.js: -------------------------------------------------------------------------------- 1 | var fs = require("fs"); 2 | var path = require("path"); 3 | var emlformat = require("../lib/eml-format.js"); 4 | 5 | exports["Unpack sample.eml"] = function(test) { 6 | var expected, actual; 7 | var src = path.join(__dirname, "./fixtures/sample.eml"); 8 | var eml = fs.readFileSync(src, "utf-8"); 9 | 10 | var dst = path.join(__dirname, "./unpack"); 11 | if (!fs.existsSync(dst)) { 12 | fs.mkdirSync(dst); 13 | } 14 | 15 | emlformat.verbose = false; 16 | emlformat.unpack(eml, dst, function(error, result) { 17 | if (error) { 18 | test.ok(false, error.message); 19 | } 20 | else { 21 | test.ok(fs.readdirSync(dst).length > 0, "Expected at least one output file!"); 22 | } 23 | test.done(); 24 | }); 25 | }; 26 | -------------------------------------------------------------------------------- /test/unpack/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Lorem ipsum 5 | =09 6 | 7 | 8 | 9 | 10 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris enim orci, semper vel egestas nec, tempor sit amet nunc. Quisque pulvinar eleifend massa, sit amet posuere lorem vehicula et. Nam elementum nulla eget nisl ultrices vulputate. Sed molestie ipsum at neque molestie tempor vel et augue. Nam magna velit, cursus sed lectus eu, bibendum viverra orci. Morbi quis risus sed nunc pharetra mattis. Suspendisse ut consectetur risus. Donec in suscipit purus, eget aliquet dui. In vitae suscipit est. Suspendisse sollicitudin, nisl sed scelerisque pulvinar, nibh mi viverra diam, et convallis nibh urna id sem. Nunc eros ante, semper sed ex vitae, iaculis tristique sapien. Maecenas molestie leo a iaculis viverra. Vivamus tristique enim vel ligula semper tristique et congue ex. Praesent auctor egestas augue ut molestie. Integer vulputate tortor quis tempor faucibus.

11 |

Curabitur sed accumsan odio. Integer vestibulum in sem nec vestibulum. Donec imperdiet turpis a faucibus volutpat. Suspendisse varius rhoncus eros, non rutrum justo pellentesque sit amet. In risus lectus, blandit sit amet magna a, porttitor pulvinar justo. Curabitur tincidunt metus at luctus fermentum. Cras vehicula dui eget semper vulputate. Ut sed leo non arcu imperdiet ultrices et eu dolor. Vestibulum aliquet sed elit a gravida. Aenean vitae est nec tellus molestie fringilla in eget enim. Morbi sodales auctor erat, eget posuere nisl condimentum aliquet. Phasellus commodo metus aliquet vestibulum ultricies. Quisque eleifend in mi vitae imperdiet. Quisque sit amet luctus nisl, vel sagittis mi. Etiam tellus tortor, blandit ut eros quis, hendrerit iaculis eros.

12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /test/unpack/index.txt: -------------------------------------------------------------------------------- 1 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris enim orci, semper vel egestas nec, tempor sit amet nunc. Quisque pulvinar eleifend massa, sit amet posuere lorem vehicula et. Nam elementum nulla eget nisl ultrices vulputate. Sed molestie ipsum at neque molestie tempor vel et augue. Nam magna velit, cursus sed lectus eu, bibendum viverra orci. Morbi quis risus sed nunc pharetra mattis. Suspendisse ut consectetur risus. Donec in suscipit purus, eget aliquet dui. In vitae suscipit est. Suspendisse sollicitudin, nisl sed scelerisque pulvinar, nibh mi viverra diam, et convallis nibh urna id sem. Nunc eros ante, semper sed ex vitae, iaculis tristique sapien. Maecenas molestie leo a iaculis viverra. Vivamus tristique enim vel ligula semper tristique et congue ex. Praesent auctor egestas augue ut molestie. Integer vulputate tortor quis tempor faucibus. 2 | 3 | Curabitur sed accumsan od 4 | io. Integer vestibulum in sem nec vestibulum. Donec imperdiet turpis a faucibus volutpat. Suspendisse varius rhoncus eros, non rutrum justo pellentesque sit amet. In risus lectus, blandit sit amet magna a, porttitor pulvinar justo. Curabitur tincidunt metus at luctus fermentum. Cras vehicula dui eget semper vulputate. Ut sed leo non arcu imperdiet ultrices et eu dolor. Vestibulum aliquet sed elit a gravida. Aenean vitae est nec tellus molestie fringilla in eget enim. Morbi sodales auctor erat, eget posuere nisl condimentum aliquet. Phasellus commodo metus aliquet vestibulum ultricies. Quisque eleifend in mi vitae imperdiet. Quisque sit amet luctus nisl, vel sagittis mi. Etiam tellus tortor, blandit ut eros quis, iaculis eros. 5 | 6 | -------------------------------------------------------------------------------- /test/unpack/nodejs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/papnkukn/eml-format/5f4abb637d493e7263bd4d26a45bbe308874c15b/test/unpack/nodejs.png --------------------------------------------------------------------------------