From 092e00cf3d3d091bc0df491b84c3f83a211992e9 Mon Sep 17 00:00:00 2001 From: Pranav Dakshinamurthy Date: Mon, 5 Mar 2018 21:04:49 -0500 Subject: [PATCH 01/15] Updated mailparser version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 253e5a4..3df47a0 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "Mail listener library for node.js. Get notification when new email arrived.", "dependencies": { "imap": "~0.8.14", - "mailparser": "~0.4.6", + "mailparser": "^2.2.0", "async": "^0.9.0" }, "repository": { From 7efdc97eeb0449ea905db200fe72de9bcb253b1a Mon Sep 17 00:00:00 2001 From: Pranav dakshinamuthy Date: Wed, 7 Mar 2018 00:12:10 -0500 Subject: [PATCH 02/15] changes to publish as npm package --- index.js | 1 + package.json | 13 ++++++------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/index.js b/index.js index 183c911..56f46c4 100644 --- a/index.js +++ b/index.js @@ -59,6 +59,7 @@ function imapReady() { self.emit('error', err); } else { self.emit('server:connected'); + self.emit('mailbox', mailbox); if (self.fetchUnreadOnStart) { parseUnread.call(self); } diff --git a/package.json b/package.json index 3df47a0..6c79709 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { - "name": "mail-listener2", - "version": "0.3.1", + "name": "mail-listener4", + "version": "1.0.0", "description": "Mail listener library for node.js. Get notification when new email arrived.", "dependencies": { "imap": "~0.8.14", @@ -9,9 +9,9 @@ }, "repository": { "type": "git", - "url": "git://github.com/chirag04/mail-listener2.git" + "url": "git://github.com/Pranav-Dakshina/mail-listener2.git" }, - "homepage": "https://github.com/chirag04/mail-listener2", + "homepage": "https://github.com/Pranav-Dakshina/mail-listener2", "keywords": [ "mail", "job", @@ -21,9 +21,8 @@ "email parser" ], "author": { - "name": "Chirag Jain", - "email": "jain_chirag04@yahoo.com", - "url": "http://chiragjain.tumblr.com" + "name": "Pranav Dakshinamurthy", + "email": "pranav.dakshina@gmail.com" }, "license": "MIT" } From b3a0dbf411c5b29ad7297de63cf73c7b7a8db077 Mon Sep 17 00:00:00 2001 From: Pranav dakshinamuthy Date: Wed, 7 Mar 2018 00:15:55 -0500 Subject: [PATCH 03/15] Added keywords --- package.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 6c79709..0048cce 100644 --- a/package.json +++ b/package.json @@ -17,8 +17,12 @@ "job", "imap", "mail listener", + "mail listener2", + "mail listener3", "email", - "email parser" + "email parser", + "node imap", + "mail parser" ], "author": { "name": "Pranav Dakshinamurthy", From 4d901f18d22f96a43fc577db3ba1048e9056ced3 Mon Sep 17 00:00:00 2001 From: Pranav dakshinamuthy Date: Wed, 7 Mar 2018 00:28:22 -0500 Subject: [PATCH 04/15] updated readme --- readme.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 2f46edb..c11f751 100644 --- a/readme.md +++ b/readme.md @@ -2,9 +2,13 @@ Mail-listener2 library for node.js. Get notification when new email arrived to inbox or when message metadata (e.g. flags) changes externally. Uses IMAP protocol. +This package has few improvements and fixes over the mail-listener2. + - Fixing mime.extension is not function error + - adding a field which gives the total number of mails. + We are using these libraries: [node-imap](https://github.com/mscdex/node-imap), [mailparser](https://github.com/andris9/mailparser). -Heavily inspired by [mail-listener](https://github.com/circuithub/mail-listener). +Heavily inspired by [mail-listener2](https://github.com/chirag04/mail-listener2). ## Use @@ -31,7 +35,7 @@ var mailListener = new MailListener({ debug: console.log, // Or your custom function with only one incoming argument. Default: null tlsOptions: { rejectUnauthorized: false }, mailbox: "INBOX", // mailbox to monitor - searchFilter: ["UNSEEN", "FLAGGED"], // the search filter being used after an IDLE notification has been retrieved + searchFilter: ["ALL"], // the search filter being used after an IDLE notification has been retrieved markSeen: true, // all fetched email willbe marked as seen and not fetched next time fetchUnreadOnStart: true, // use it only if you want to get all unread email on lib start. Default is `false`, mailParserOptions: {streamAttachments: true}, // options to be passed to mailParser lib. @@ -48,6 +52,10 @@ mailListener.on("server:connected", function(){ console.log("imapConnected"); }); +mailListener.on("mailbox", function(mailbox){ + console.log("Total number of mails: ", mailbox.messages.total); // this field in mailbox gives the total number of emails +}); + mailListener.on("server:disconnected", function(){ console.log("imapDisconnected"); }); From 5aa2f77e50547832a3116643c25baed4f86f77f4 Mon Sep 17 00:00:00 2001 From: Pranav dakshinamuthy Date: Wed, 7 Mar 2018 00:28:46 -0500 Subject: [PATCH 05/15] 1.0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0048cce..99116af 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mail-listener4", - "version": "1.0.0", + "version": "1.0.1", "description": "Mail listener library for node.js. Get notification when new email arrived.", "dependencies": { "imap": "~0.8.14", From dba8a833e6e51deb2f565ed0c7217e2fe2f8dc42 Mon Sep 17 00:00:00 2001 From: Pranav dakshinamuthy Date: Wed, 7 Mar 2018 00:57:08 -0500 Subject: [PATCH 06/15] changed mail parser to 0.6.2 --- index.js | 1 - package.json | 4 ++-- test.js | 23 ++++++++++++++++------- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/index.js b/index.js index 56f46c4..183c911 100644 --- a/index.js +++ b/index.js @@ -59,7 +59,6 @@ function imapReady() { self.emit('error', err); } else { self.emit('server:connected'); - self.emit('mailbox', mailbox); if (self.fetchUnreadOnStart) { parseUnread.call(self); } diff --git a/package.json b/package.json index 99116af..f2da116 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,10 @@ { "name": "mail-listener4", - "version": "1.0.1", + "version": "1.1.0", "description": "Mail listener library for node.js. Get notification when new email arrived.", "dependencies": { "imap": "~0.8.14", - "mailparser": "^2.2.0", + "mailparser": "^0.6.2", "async": "^0.9.0" }, "repository": { diff --git a/test.js b/test.js index c22f3b5..3f3dee8 100644 --- a/test.js +++ b/test.js @@ -1,16 +1,21 @@ var MailListener = require("./"); var mailListener = new MailListener({ - username: "xxxx", + username: "xxxxx", password: "xxx", host: "imap.gmail.com", port: 993, tls: true, + connTimeout: 10000, // Default by node-imap + authTimeout: 5000, // Default by node-imap, + debug: console.log, // Or your custom function with only one incoming argument. Default: null tlsOptions: { rejectUnauthorized: false }, - mailbox: "INBOX", - markSeen: true, - fetchUnreadOnStart: true, - attachments: true, + mailbox: "INBOX", // mailbox to monitor + searchFilter: ["ALL"], // the search filter being used after an IDLE notification has been retrieved + markSeen: true, // all fetched email willbe marked as seen and not fetched next time + fetchUnreadOnStart: true, // use it only if you want to get all unread email on lib start. Default is `false`, + mailParserOptions: {streamAttachments: true}, // options to be passed to mailParser lib. + attachments: true, // download attachments as they are encountered to the project directory attachmentOptions: { directory: "attachments/" } }); @@ -20,6 +25,10 @@ mailListener.on("server:connected", function(){ console.log("imapConnected"); }); +mailListener.on("mailbox", function(mailbox){ + console.log("Total number of mails: ", mailbox.messages.total); +}); + mailListener.on("server:disconnected", function(){ console.log("imapDisconnected"); }); @@ -28,8 +37,8 @@ mailListener.on("error", function(err){ console.log(err); }); -mailListener.on("mail", function(mail){ - console.log(mail); +mailListener.on("mail", function(mail, seqno, attributes){ + console.log("Mail: ",mail); }); mailListener.on("attachment", function(attachment){ From e7dd1ff767da42d250025cb73068638c94fb77f4 Mon Sep 17 00:00:00 2001 From: Pranav dakshinamuthy Date: Wed, 7 Mar 2018 00:59:19 -0500 Subject: [PATCH 07/15] added mailbox emit --- index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/index.js b/index.js index 183c911..56f46c4 100644 --- a/index.js +++ b/index.js @@ -59,6 +59,7 @@ function imapReady() { self.emit('error', err); } else { self.emit('server:connected'); + self.emit('mailbox', mailbox); if (self.fetchUnreadOnStart) { parseUnread.call(self); } From 709c91197b321fbab296a634b7884a7d6f4793a4 Mon Sep 17 00:00:00 2001 From: Pranav dakshinamuthy Date: Wed, 7 Mar 2018 00:59:43 -0500 Subject: [PATCH 08/15] 1.1.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f2da116..09d5774 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mail-listener4", - "version": "1.1.0", + "version": "1.1.1", "description": "Mail listener library for node.js. Get notification when new email arrived.", "dependencies": { "imap": "~0.8.14", From a439fde7863d69548d70ed4b455df4863be2a200 Mon Sep 17 00:00:00 2001 From: Pranav Dakshinamurthy Date: Mon, 19 Mar 2018 18:50:36 -0400 Subject: [PATCH 09/15] Update readme.md --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index c11f751..c01efce 100644 --- a/readme.md +++ b/readme.md @@ -14,7 +14,7 @@ Heavily inspired by [mail-listener2](https://github.com/chirag04/mail-listener2) Install -`npm install mail-listener2` +`npm install mail-listener4` JavaScript Code: @@ -22,7 +22,7 @@ JavaScript Code: ```javascript -var MailListener = require("mail-listener2"); +var MailListener = require("mail-listener4"); var mailListener = new MailListener({ username: "imap-username", From 274b3bd48affd427b2ca970ec6cc96ab2d27f0e4 Mon Sep 17 00:00:00 2001 From: Pranav Date: Wed, 11 Apr 2018 15:03:56 -0400 Subject: [PATCH 10/15] update readme.md --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 09d5774..efc27a8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mail-listener4", - "version": "1.1.1", + "version": "1.1.2", "description": "Mail listener library for node.js. Get notification when new email arrived.", "dependencies": { "imap": "~0.8.14", From ddbb78659136e65ed9831759f2e22956243be82e Mon Sep 17 00:00:00 2001 From: Pranav Date: Wed, 11 Apr 2018 15:10:00 -0400 Subject: [PATCH 11/15] Update readme.md --- npm-debug.log | 27 +++++++++++++++++++++++++++ package.json | 2 +- readme.md | 2 +- 3 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 npm-debug.log diff --git a/npm-debug.log b/npm-debug.log new file mode 100644 index 0000000..7e9c3b8 --- /dev/null +++ b/npm-debug.log @@ -0,0 +1,27 @@ +0 info it worked if it ends with ok +1 verbose cli [ '/usr/bin/node', '/usr/bin/npm', 'version', '1.1.3' ] +2 info using npm@3.10.10 +3 info using node@v6.14.1 +4 info git [ 'status', '--porcelain' ] +5 verbose stack Error: Git working directory not clean. +5 verbose stack M readme.md +5 verbose stack at /usr/lib/node_modules/npm/lib/version.js:247:19 +5 verbose stack at /usr/lib/node_modules/npm/lib/utils/no-progress-while-running.js:21:8 +5 verbose stack at ChildProcess.exithandler (child_process.js:190:7) +5 verbose stack at emitTwo (events.js:106:13) +5 verbose stack at ChildProcess.emit (events.js:191:7) +5 verbose stack at maybeClose (internal/child_process.js:920:16) +5 verbose stack at Socket. (internal/child_process.js:351:11) +5 verbose stack at emitOne (events.js:96:13) +5 verbose stack at Socket.emit (events.js:188:7) +5 verbose stack at Pipe._handle.close [as _onclose] (net.js:509:12) +6 verbose cwd /home/pranav/Desktop/Email_Server/mail-listener2 +7 error Linux 4.13.0-38-generic +8 error argv "/usr/bin/node" "/usr/bin/npm" "version" "1.1.3" +9 error node v6.14.1 +10 error npm v3.10.10 +11 error Git working directory not clean. +11 error M readme.md +12 error If you need help, you may report this error at: +12 error +13 verbose exit [ 1, true ] diff --git a/package.json b/package.json index efc27a8..8e5ec80 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mail-listener4", - "version": "1.1.2", + "version": "1.1.3", "description": "Mail listener library for node.js. Get notification when new email arrived.", "dependencies": { "imap": "~0.8.14", diff --git a/readme.md b/readme.md index c01efce..16c5e34 100644 --- a/readme.md +++ b/readme.md @@ -1,6 +1,6 @@ # Overview -Mail-listener2 library for node.js. Get notification when new email arrived to inbox or when message metadata (e.g. flags) changes externally. Uses IMAP protocol. +Mail-listener4 library for node.js. Get notification when new email arrived to inbox or when message metadata (e.g. flags) changes externally. Uses IMAP protocol. This package has few improvements and fixes over the mail-listener2. - Fixing mime.extension is not function error From 1c132baab04cf07768f8be1ca892495b5ebcabe5 Mon Sep 17 00:00:00 2001 From: Pranav Date: Wed, 11 Apr 2018 15:10:45 -0400 Subject: [PATCH 12/15] Update readme.md --- .gitignore | 3 ++- npm-debug.log | 27 --------------------------- 2 files changed, 2 insertions(+), 28 deletions(-) delete mode 100644 npm-debug.log diff --git a/.gitignore b/.gitignore index 40b878d..1ca9571 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -node_modules/ \ No newline at end of file +node_modules/ +npm-debug.log diff --git a/npm-debug.log b/npm-debug.log deleted file mode 100644 index 7e9c3b8..0000000 --- a/npm-debug.log +++ /dev/null @@ -1,27 +0,0 @@ -0 info it worked if it ends with ok -1 verbose cli [ '/usr/bin/node', '/usr/bin/npm', 'version', '1.1.3' ] -2 info using npm@3.10.10 -3 info using node@v6.14.1 -4 info git [ 'status', '--porcelain' ] -5 verbose stack Error: Git working directory not clean. -5 verbose stack M readme.md -5 verbose stack at /usr/lib/node_modules/npm/lib/version.js:247:19 -5 verbose stack at /usr/lib/node_modules/npm/lib/utils/no-progress-while-running.js:21:8 -5 verbose stack at ChildProcess.exithandler (child_process.js:190:7) -5 verbose stack at emitTwo (events.js:106:13) -5 verbose stack at ChildProcess.emit (events.js:191:7) -5 verbose stack at maybeClose (internal/child_process.js:920:16) -5 verbose stack at Socket. (internal/child_process.js:351:11) -5 verbose stack at emitOne (events.js:96:13) -5 verbose stack at Socket.emit (events.js:188:7) -5 verbose stack at Pipe._handle.close [as _onclose] (net.js:509:12) -6 verbose cwd /home/pranav/Desktop/Email_Server/mail-listener2 -7 error Linux 4.13.0-38-generic -8 error argv "/usr/bin/node" "/usr/bin/npm" "version" "1.1.3" -9 error node v6.14.1 -10 error npm v3.10.10 -11 error Git working directory not clean. -11 error M readme.md -12 error If you need help, you may report this error at: -12 error -13 verbose exit [ 1, true ] From 5bd5063f1d7248cac7fe2cd0e61284281eb88a5d Mon Sep 17 00:00:00 2001 From: Matej Malicek <44388825+MatejMalicek@users.noreply.github.com> Date: Thu, 7 Mar 2019 11:37:35 +1100 Subject: [PATCH 13/15] Initial commit (still being tested) --- LICENSE | 4 +- index.js | 277 ++++++++++++++++++++++++--------------------- package-lock.json | 279 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 27 +++-- readme.md | 34 +++++- test.js | 8 +- 6 files changed, 480 insertions(+), 149 deletions(-) create mode 100644 package-lock.json diff --git a/LICENSE b/LICENSE index cdad213..e94ed42 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,6 @@ -Copyright (c) 2012-2014 Chirag Jain +Copyright (c) 2012-2014 Chirag Jain (mail-listener2) +Pranav Dakshinamurthy 2014-2018 (mail-listener4) +Matej Malicek 2019 (mail-listener5) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation diff --git a/index.js b/index.js index 56f46c4..fc8e7ed 100644 --- a/index.js +++ b/index.js @@ -1,149 +1,172 @@ +/**@module mail-listener5 + * @author Matej Malicek + * @version 1.0.0 + * @date 4 March 2019 + */ + + // Require statements var Imap = require('imap'); -var util = require('util'); var EventEmitter = require('events').EventEmitter; -var MailParser = require("mailparser").MailParser; -var fs = require("fs"); +var MailParser = require('mailparser').MailParser; +var fs = require('fs'); var path = require('path'); var async = require('async'); -module.exports = MailListener; - -function MailListener(options) { - this.markSeen = !! options.markSeen; - this.mailbox = options.mailbox || "INBOX"; - if ('string' === typeof options.searchFilter) { - this.searchFilter = [options.searchFilter]; - } else { - this.searchFilter = options.searchFilter || ["UNSEEN"]; - } - this.fetchUnreadOnStart = !! options.fetchUnreadOnStart; - this.mailParserOptions = options.mailParserOptions || {}; - if (options.attachments && options.attachmentOptions && options.attachmentOptions.stream) { - this.mailParserOptions.streamAttachments = true; +class MailListener extends EventEmitter { + constructor(options) { + super(); + this.markSeen = !! options.markSeen; + this.mailbox = options.mailbox || 'INBOX'; + if ('string' === typeof options.searchFilter) + { + this.searchFilter = [options.searchFilter]; + } + else + { + this.searchFilter = options.searchFilter || ['UNSEEN']; + } + this.fetchUnreadOnStart = !! options.fetchUnreadOnStart; + this.mailParserOptions = options.mailParserOptions || {}; + if (options.attachments && options.attachmentOptions && options.attachmentOptions.stream) + { + this.mailParserOptions.streamAttachments = true; + } + this.attachmentOptions = options.attachmentOptions || {}; + this.attachments = options.attachments || false; + this.attachmentOptions.directory = (this.attachmentOptions.directory ? this.attachmentOptions.directory : ''); + this.imap = new Imap({ + xoauth2: options.xoauth2, + user: options.username, + password: options.password, + host: options.host, + port: options.port, + tls: options.tls, + tlsOptions: options.tlsOptions || {}, + connTimeout: options.connTimeout || null, + authTimeout: options.authTimeout || null, + debug: options.debug || null + }); + this.imap.once('ready', this.imapReady.bind(this)); + this.imap.once('close', this.imapClose.bind(this)); + this.imap.on('error', this.imapError.bind(this)); } - this.attachmentOptions = options.attachmentOptions || {}; - this.attachments = options.attachments || false; - this.attachmentOptions.directory = (this.attachmentOptions.directory ? this.attachmentOptions.directory : ''); - this.imap = new Imap({ - xoauth2: options.xoauth2, - user: options.username, - password: options.password, - host: options.host, - port: options.port, - tls: options.tls, - tlsOptions: options.tlsOptions || {}, - connTimeout: options.connTimeout || null, - authTimeout: options.authTimeout || null, - debug: options.debug || null - }); - - this.imap.once('ready', imapReady.bind(this)); - this.imap.once('close', imapClose.bind(this)); - this.imap.on('error', imapError.bind(this)); -} -util.inherits(MailListener, EventEmitter); - -MailListener.prototype.start = function() { - this.imap.connect(); -}; + start() { + this.imap.connect(); + } -MailListener.prototype.stop = function() { - this.imap.end(); -}; + stop() { + this.imap.connect(); + } -function imapReady() { - var self = this; - this.imap.openBox(this.mailbox, false, function(err, mailbox) { - if (err) { - self.emit('error', err); - } else { - self.emit('server:connected'); - self.emit('mailbox', mailbox); - if (self.fetchUnreadOnStart) { - parseUnread.call(self); + imapReady() { + this.imap.openBox(this.mailbox, false, (error, mailbox) => { + if (error) + { + this.emit('error', error); } - var listener = imapMail.bind(self); - self.imap.on('mail', listener); - self.imap.on('update', listener); - } - }); -} - -function imapClose() { - this.emit('server:disconnected'); -} + else + { + this.emit('server:connected'); + this.emit('mailbox', mailbox); + if (this.fetchUnreadOnStart) + { + this.parseUnread.call(this); + } + let listener = this.imapMail.bind(this); + this.imap.on('mail', listener); + this.imap.on('update', listener); + } + }); + } -function imapError(err) { - this.emit('error', err); -} + imapClose() { + this.emit('server:disconnected'); + } -function imapMail() { - parseUnread.call(this); -} + imapError(error) { + this.emit('error', error); + } -function parseUnread() { - var self = this; - this.imap.search(self.searchFilter, function(err, results) { - if (err) { - self.emit('error', err); - } else if (results.length > 0) { - async.each(results, function( result, callback) { - var f = self.imap.fetch(result, { - bodies: '', - markSeen: self.markSeen - }); - f.on('message', function(msg, seqno) { - var parser = new MailParser(self.mailParserOptions); - var attributes = null; - var emlbuffer = new Buffer(''); + imapMail() { + this.parseUnread.call(this); + } - parser.on("end", function(mail) { - mail.eml = emlbuffer.toString('utf-8'); - if (!self.mailParserOptions.streamAttachments && mail.attachments && self.attachments) { - async.each(mail.attachments, function( attachment, callback) { - fs.writeFile(self.attachmentOptions.directory + attachment.generatedFileName, attachment.content, function(err) { - if(err) { - self.emit('error', err); - callback() - } else { - attachment.path = path.resolve(self.attachmentOptions.directory + attachment.generatedFileName); - self.emit('attachment', attachment); - callback() - } + parseUnread() { + let self = this; + self.imap.search(self.searchFilter, (error, results) => { + if (error) + { + self.emit('error', err); + } + else if (results.length > 0) + { + async.each(results, (result, callback) => { + let f = self.imap.fetch(result, { + bodies: '', + markSeen: self.markSeen + }); + f.on('message', (msg, seqno) => { + let parser = new MailParser(self.mailParserOptions); + let attributes = null; + let emailData = ''; + + parser.on('end', function(mail) { + mail.email = emailBuffer.toString('utf-8'); + if (!self.mailParserOptions.streamAttachments && mail.attachments && self.attachments) + { + async.each(mail.attachments, (attachment, callback) => { + fs.writeFile(`${self.attachmentOptions.directory}${attachment.generatedFileName}`, attachment.content, (error) => { + if(error) + { + self.emit('error', error); + callback(); + } + else + { + attachment.path = path.resolve(`${self.attachmentOptions.directory}${attachment.generatedFileName}`); + self.emit('attachment', attachment); + callback(); + } + }); + }, (error) => { + self.emit('mail', mail, seqno, attributes); + callback(); }); - }, function(err){ + } + else + { self.emit('mail', mail, seqno, attributes); - callback() + } + }); + parser.on('attachment', (attachment) => { + self.emit('attachment', attachment); + }); + msg.on('body', function(stream, info) { + stream.setEncoding(''); + stream.on('data', function(chunk) { + emailData += chunk; + }); + stream.once('end', function() { + parser.write(Buffer.from(emailData)); + parser.end(); }); - } else { - self.emit('mail',mail,seqno,attributes); - } - }); - parser.on("attachment", function (attachment) { - self.emit('attachment', attachment); - }); - msg.on('body', function(stream, info) { - stream.on('data', function(chunk) { - emlbuffer = Buffer.concat([emlbuffer, chunk]); }); - stream.once('end', function() { - parser.write(emlbuffer); - parser.end(); + msg.on('attributes', function(attrs) { + attributes = attrs; }); }); - msg.on('attributes', function(attrs) { - attributes = attrs; + f.once('error', (error) => { + self.emit('error', error); }); + }, (error) => { + if (error) + { + self.emit('error', error); + } }); - f.once('error', function(err) { - self.emit('error', err); - }); - }, function(err){ - if( err ) { - self.emit('error', err); - } - }); - } - }); -} + } + }); + } +}; +module.exports.MailListener = MailListener; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..78e8c80 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,279 @@ +{ + "name": "mail-listener5", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", + "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", + "requires": { + "lodash": "^4.17.11" + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "dom-serializer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", + "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", + "requires": { + "domelementtype": "^1.3.0", + "entities": "^1.1.1" + } + }, + "domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" + }, + "domhandler": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", + "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", + "requires": { + "domelementtype": "1" + } + }, + "domutils": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" + }, + "html-to-text": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-to-text/-/html-to-text-4.0.0.tgz", + "integrity": "sha512-QQl5EEd97h6+3crtgBhkEAO6sQnZyDff8DAeJzoSkOc1Dqe1UvTUZER0B+KjBe6fPZqq549l2VUhtracus3ndA==", + "requires": { + "he": "^1.0.0", + "htmlparser2": "^3.9.2", + "lodash": "^4.17.4", + "optimist": "^0.6.1" + } + }, + "htmlparser2": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", + "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", + "requires": { + "domelementtype": "^1.3.1", + "domhandler": "^2.3.0", + "domutils": "^1.5.1", + "entities": "^1.1.1", + "inherits": "^2.0.1", + "readable-stream": "^3.1.1" + }, + "dependencies": { + "readable-stream": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.2.0.tgz", + "integrity": "sha512-RV20kLjdmpZuTF1INEb9IA3L68Nmi+Ri7ppZqo78wj//Pn62fCoJyV9zalccNzDD/OuJpMG4f+pfMl8+L6QdGw==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "string_decoder": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.2.0.tgz", + "integrity": "sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "imap": { + "version": "0.8.19", + "resolved": "https://registry.npmjs.org/imap/-/imap-0.8.19.tgz", + "integrity": "sha1-NniHOTSrCc6mukh0HyhNoq9Z2NU=", + "requires": { + "readable-stream": "1.1.x", + "utf7": ">=1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "libbase64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/libbase64/-/libbase64-1.0.3.tgz", + "integrity": "sha512-ULQZAATVGTAgVNwP61R+MbbSGNBy1tVzWupB9kbE6p+VccWd+J+ICXgOwQic5Yqagzpu+oPZ8sI7yXdWJnPPkA==" + }, + "libmime": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/libmime/-/libmime-4.0.1.tgz", + "integrity": "sha512-mGgJLRkpkMxZZYE7ncVXokgKfi5ePrIB1H3W/Bv3GbkVnFydIHTsPrfAVW0edxalQHmFfqDMU9W45PidCLG6DA==", + "requires": { + "iconv-lite": "0.4.23", + "libbase64": "1.0.3", + "libqp": "1.1.0" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + } + } + }, + "libqp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/libqp/-/libqp-1.1.0.tgz", + "integrity": "sha1-9ebgatdLeU+1tbZpiL9yjvHe2+g=" + }, + "linkify-it": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.0.3.tgz", + "integrity": "sha1-2UpGSPmxwXnWT6lykSaL22zpQ08=", + "requires": { + "uc.micro": "^1.0.1" + } + }, + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" + }, + "mailparser": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/mailparser/-/mailparser-2.4.3.tgz", + "integrity": "sha512-VKfFVzpgXLL7fNYy2ryRCPzwBxdlWdnExAgS551bQrmDuJgP0pmE01f9eIGKXlRpsCB8xw7XwYTkWqHBGEEbNg==", + "requires": { + "he": "1.2.0", + "html-to-text": "4.0.0", + "iconv-lite": "0.4.24", + "libmime": "4.0.1", + "linkify-it": "2.0.3", + "mailsplit": "4.2.4", + "nodemailer": "4.6.8", + "tlds": "1.203.1" + } + }, + "mailsplit": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/mailsplit/-/mailsplit-4.2.4.tgz", + "integrity": "sha512-UZUSCv2RtjUMbPFRkECF2O9IIdquEbMNlvIIlEgDROt+HVa++vFqqZZLuu/3MDFt5AND6W/r1a1UfJt7pA1f+Q==", + "requires": { + "libbase64": "1.0.3", + "libmime": "4.0.1", + "libqp": "1.1.0" + } + }, + "minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=" + }, + "nodemailer": { + "version": "4.6.8", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-4.6.8.tgz", + "integrity": "sha512-A3s7EM/426OBIZbLHXq2KkgvmKbn2Xga4m4G+ZUA4IaZvG8PcZXrFh+2E4VaS2o+emhuUVRnzKN2YmpkXQ9qwA==" + }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "requires": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + } + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "semver": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=" + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + }, + "tlds": { + "version": "1.203.1", + "resolved": "https://registry.npmjs.org/tlds/-/tlds-1.203.1.tgz", + "integrity": "sha512-7MUlYyGJ6rSitEZ3r1Q1QNV8uSIzapS8SmmhSusBuIc7uIxPPwsKllEP0GRp1NS6Ik6F+fRZvnjDWm3ecv2hDw==" + }, + "uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" + }, + "utf7": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/utf7/-/utf7-1.0.2.tgz", + "integrity": "sha1-lV9JCq5lO6IguUVqCod2wZk2CZE=", + "requires": { + "semver": "~5.3.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" + } + } +} diff --git a/package.json b/package.json index 8e5ec80..493d4a5 100644 --- a/package.json +++ b/package.json @@ -1,17 +1,17 @@ { - "name": "mail-listener4", - "version": "1.1.3", + "name": "mail-listener5", + "version": "1.0.0", "description": "Mail listener library for node.js. Get notification when new email arrived.", "dependencies": { - "imap": "~0.8.14", - "mailparser": "^0.6.2", - "async": "^0.9.0" + "imap": "^0.8.19", + "mailparser": "^2.4.3", + "async": "^2.6.2" }, "repository": { "type": "git", - "url": "git://github.com/Pranav-Dakshina/mail-listener2.git" + "url": "git://github.com/MatejMalicek/mail-listener2.git" }, - "homepage": "https://github.com/Pranav-Dakshina/mail-listener2", + "homepage": "https://github.com/MatejMalicek/mail-listener2", "keywords": [ "mail", "job", @@ -19,14 +19,19 @@ "mail listener", "mail listener2", "mail listener3", + "mail listener4", "email", "email parser", "node imap", "mail parser" ], - "author": { - "name": "Pranav Dakshinamurthy", - "email": "pranav.dakshina@gmail.com" + "author": "Matej Malicek ", + "license": "MIT", + "bugs": { + "url": "https://github.com/MatejMalicek/mail-listener2/issues" }, - "license": "MIT" + "main": "index.js", + "scripts": { + "test": "test.js" + } } diff --git a/readme.md b/readme.md index 16c5e34..35fa493 100644 --- a/readme.md +++ b/readme.md @@ -1,20 +1,29 @@ # Overview -Mail-listener4 library for node.js. Get notification when new email arrived to inbox or when message metadata (e.g. flags) changes externally. Uses IMAP protocol. +Mail-listener5 library for node.js. Get notification when new email arrived to inbox or when message metadata (e.g. flags) changes externally. Uses IMAP protocol. -This package has few improvements and fixes over the mail-listener2. - - Fixing mime.extension is not function error - - adding a field which gives the total number of mails. +## Version Notes +THIS INITIAL COMMIT IS STILL UNDERGOING MORE THOROUGH TESTING. Expect further commits in the next week or so (mid-March 2019) after this testing has finished & passed. :-) + +This package has several improvements and fixes over the mail-listener2 & mail-listener4. Most of the improvements are designed to improve security, performance & usability, plus avoid deprecation warnings. + - Updating dependencies to newer versions, with security enhancements, etc. + - Updating code to use ES6 classes. The previous version used util.inherits(), which is now discouraged (see https://nodejs.org/dist/latest-v10.x/docs/api/util.html#util_util_inherits_constructor_superconstructor). + - Updating code to use safer Buffer constructors. Use of the new Buffer() expression is deprecated (see https://nodejs.org/en/docs/guides/buffer-constructor-deprecation/), so Buffer().from() is used instead. + - Updating code to use lexical variable declarations where appropriate. + - Updating code to use ES6 arrow functions within methods where appropriate. + - Updating test.js to use environment variables for credentials, etc (see new [Testing](#Testing) section below). We are using these libraries: [node-imap](https://github.com/mscdex/node-imap), [mailparser](https://github.com/andris9/mailparser). -Heavily inspired by [mail-listener2](https://github.com/chirag04/mail-listener2). +Heavily inspired by [mail-listener2](https://github.com/chirag04/mail-listener2) and [mail-listener5](https://github.com/Pranav-Dakshina/mail-listener2). + +NOTE: This version is designed to work with & tested on NodeJS v 10.15.2 LTS, the most recent LTS version as at March 2019. It might not work on older versions of Node. ## Use Install -`npm install mail-listener4` +`npm install mail-listener5` JavaScript Code: @@ -88,6 +97,19 @@ A specific download directory may be specified by setting `attachmentOptions: { Attachments may also be streamed using `attachmentOptions: { stream: "true"}`. The `"attachment"` event will be fired every time an attachment is encountered. Refer to the [mailparser docs](https://github.com/andris9/mailparser#attachment-streaming) for specifics on how to stream attachments. +## Testing +A test script is available at test.js. Before using the test script, it is necessary to set the following environment variables: + - IMAPUSER - IMAP account username. + - IMAPPASS - IMAP account password. + - IMAPHOST - IMAP server hostname (e.g. imap.example.com). + +The test script assumes that the IMAP host supports TLS and that the port is the usual 993. These values can be changed in test.js if necessary. + +To run the test script, simply execute: + +```bash +export IMAPUSER='user@example.com' IMAPPASS='password' IMAPHOST='imap.example.com'; node test.js +``` ## License diff --git a/test.js b/test.js index 3f3dee8..898c115 100644 --- a/test.js +++ b/test.js @@ -1,9 +1,9 @@ -var MailListener = require("./"); +var MailListener = require("./index.js").MailListener; var mailListener = new MailListener({ - username: "xxxxx", - password: "xxx", - host: "imap.gmail.com", + username: process.env.IMAPUSER, + password: process.env.IMAPPASS, + host: process.env.IMAPHOST, port: 993, tls: true, connTimeout: 10000, // Default by node-imap From 6a2daaf7adabb802bb68b87000cbc8926bf47939 Mon Sep 17 00:00:00 2001 From: Matej Malicek <44388825+MatejMalicek@users.noreply.github.com> Date: Tue, 19 Mar 2019 13:49:33 +1100 Subject: [PATCH 14/15] Updated to use simpleParser following testing --- .gitignore | 1 + index.js | 67 ++++++++++++++++------------------------------------ package.json | 2 +- readme.md | 43 +++++++++++++++++++++------------ test.js | 19 ++++++++++----- 5 files changed, 64 insertions(+), 68 deletions(-) diff --git a/.gitignore b/.gitignore index 1ca9571..08f6184 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules/ npm-debug.log +attachments/ \ No newline at end of file diff --git a/index.js b/index.js index fc8e7ed..3775572 100644 --- a/index.js +++ b/index.js @@ -7,7 +7,7 @@ // Require statements var Imap = require('imap'); var EventEmitter = require('events').EventEmitter; -var MailParser = require('mailparser').MailParser; +var simpleParser = require('mailparser').simpleParser; var fs = require('fs'); var path = require('path'); var async = require('async'); @@ -106,54 +106,29 @@ class MailListener extends EventEmitter { bodies: '', markSeen: self.markSeen }); - f.on('message', (msg, seqno) => { - let parser = new MailParser(self.mailParserOptions); - let attributes = null; - let emailData = ''; - - parser.on('end', function(mail) { - mail.email = emailBuffer.toString('utf-8'); - if (!self.mailParserOptions.streamAttachments && mail.attachments && self.attachments) + f.on('message', (msg, seqno) => { + msg.on('body', async (stream, info) => { + let parsed = await simpleParser(stream); + self.emit('mail', parsed, seqno); + self.emit('headers', parsed.headers, seqno); + self.emit('body', {html: parsed.html, text: parsed.text, textAsHtml: parsed.textAsHtml}, seqno); + if (parsed.attachments.length>0) { - async.each(mail.attachments, (attachment, callback) => { - fs.writeFile(`${self.attachmentOptions.directory}${attachment.generatedFileName}`, attachment.content, (error) => { - if(error) - { + for (let att of parsed.attachments) + { + if (self.attachments) + { + await fs.writeFile(`${self.attachmentOptions.directory}${att.filename}`, att.content, (error) =>{ self.emit('error', error); - callback(); - } - else - { - attachment.path = path.resolve(`${self.attachmentOptions.directory}${attachment.generatedFileName}`); - self.emit('attachment', attachment); - callback(); - } - }); - }, (error) => { - self.emit('mail', mail, seqno, attributes); - callback(); - }); + }); + self.emit('attachment', att, `${self.attachmentOptions.directory}${att.filename}`, seqno); + } + else + { + self.emit('attachment', att, null, seqno); + } + } } - else - { - self.emit('mail', mail, seqno, attributes); - } - }); - parser.on('attachment', (attachment) => { - self.emit('attachment', attachment); - }); - msg.on('body', function(stream, info) { - stream.setEncoding(''); - stream.on('data', function(chunk) { - emailData += chunk; - }); - stream.once('end', function() { - parser.write(Buffer.from(emailData)); - parser.end(); - }); - }); - msg.on('attributes', function(attrs) { - attributes = attrs; }); }); f.once('error', (error) => { diff --git a/package.json b/package.json index 493d4a5..fb25f74 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mail-listener5", - "version": "1.0.0", + "version": "2.0.0", "description": "Mail listener library for node.js. Get notification when new email arrived.", "dependencies": { "imap": "^0.8.19", diff --git a/readme.md b/readme.md index 35fa493..4dbc7ab 100644 --- a/readme.md +++ b/readme.md @@ -3,12 +3,16 @@ Mail-listener5 library for node.js. Get notification when new email arrived to inbox or when message metadata (e.g. flags) changes externally. Uses IMAP protocol. ## Version Notes -THIS INITIAL COMMIT IS STILL UNDERGOING MORE THOROUGH TESTING. Expect further commits in the next week or so (mid-March 2019) after this testing has finished & passed. :-) +THIS PACKAGE IS STILL UNDERGOING MORE THOROUGH TESTING AND IMPROVEMENT. Expect further commits as functionality is added. :-) -This package has several improvements and fixes over the mail-listener2 & mail-listener4. Most of the improvements are designed to improve security, performance & usability, plus avoid deprecation warnings. - - Updating dependencies to newer versions, with security enhancements, etc. +This package has several improvements and fixes over the mail-listener2 & mail-listener4. Most of the improvements are designed to improve security & usability, plus avoid deprecation warnings. The previous mail-listener packages used a now-deprecated version of MailParser and unsafe buffer constructors (see change notes below). + +This package uses the simpleParser function in NodeMailer. This parser is easier to implement & provides a Mail object from which any needed attributes can be extracted. However, it is more resource-intensive when it comes to larger emails, as attachments are not handled as streams, but rather are buffered in memory. In a future version, I plan to reintroduce the ability to stream attachments directly (rather than buffering them) so that larger attachments can be processed with fewer resources. + +Change notes: + + - Updating dependencies to newer versions, with security enhancements, etc. The previous mail-listeners all used now-deprecated versions of dependencies, many of which posed security problems as they used unsafe Buffer constructors (e.g. new Buffer() - see https://nodejs.org/en/docs/guides/buffer-constructor-deprecation/). - Updating code to use ES6 classes. The previous version used util.inherits(), which is now discouraged (see https://nodejs.org/dist/latest-v10.x/docs/api/util.html#util_util_inherits_constructor_superconstructor). - - Updating code to use safer Buffer constructors. Use of the new Buffer() expression is deprecated (see https://nodejs.org/en/docs/guides/buffer-constructor-deprecation/), so Buffer().from() is used instead. - Updating code to use lexical variable declarations where appropriate. - Updating code to use ES6 arrow functions within methods where appropriate. - Updating test.js to use environment variables for credentials, etc (see new [Testing](#Testing) section below). @@ -19,6 +23,11 @@ Heavily inspired by [mail-listener2](https://github.com/chirag04/mail-listener2) NOTE: This version is designed to work with & tested on NodeJS v 10.15.2 LTS, the most recent LTS version as at March 2019. It might not work on older versions of Node. +## Planned Future Improvements +Whilst this package is confirmed to work, the ability to stream attachments (present in the older versions of mail-listener) has been taken out, mainly because the MailParser library has changed significantly & a substantial amount of refactoring is required in order to allow the safe streaming of attachments (which may contain untrusted content). + +A future version will reintroduce this capability once the refactoring is complete. That version will allow attachments to be streamed directly to functions. At present, attachments are either saved to a file for later processing (if that option is selected) or an 'attachment' event is emitted, which contains a Buffer with the attachment content. This Buffer can then be processed as needed. + ## Use Install @@ -31,7 +40,7 @@ JavaScript Code: ```javascript -var MailListener = require("mail-listener4"); +var MailListener = require("mail-listener5"); var mailListener = new MailListener({ username: "imap-username", @@ -47,7 +56,6 @@ var mailListener = new MailListener({ searchFilter: ["ALL"], // the search filter being used after an IDLE notification has been retrieved markSeen: true, // all fetched email willbe marked as seen and not fetched next time fetchUnreadOnStart: true, // use it only if you want to get all unread email on lib start. Default is `false`, - mailParserOptions: {streamAttachments: true}, // options to be passed to mailParser lib. attachments: true, // download attachments as they are encountered to the project directory attachmentOptions: { directory: "attachments/" } // specify a download directory for attachments }); @@ -73,16 +81,22 @@ mailListener.on("error", function(err){ console.log(err); }); -mailListener.on("mail", function(mail, seqno, attributes){ - // do something with mail object including attachments - console.log("emailParsed", mail); - // mail processing code goes here +mailListener.on("headers", function(headers, seqno){ + // do something with mail headers }); -mailListener.on("attachment", function(attachment){ - console.log(attachment.path); +mailListener.on("body", function(body, seqno){ + // do something with mail body +}) + +mailListener.on("attachment", function(attachment, path, seqno){ + // do something with attachment }); +mailListener.on("mail", function(mail, seqno) { + // do something with the whole email as a single object +}) + // it's possible to access imap object from node-imap library for performing additional actions. E.x. mailListener.imap.move(:msguids, :mailboxes, function(){}) @@ -91,11 +105,10 @@ mailListener.imap.move(:msguids, :mailboxes, function(){}) That's easy! ## Attachments -Attachments can be streamed or buffered. This feature is based on how [mailparser](https://github.com/andris9/mailparser#attachments) handles attachments. +Attachments in this version are buffered. This feature is based on how [mailparser](https://github.com/andris9/mailparser#attachments)'s simpleParser function handles attachments. Setting `attachments: true` will download attachments as buffer objects by default to the project directory. A specific download directory may be specified by setting `attachmentOptions: { directory: "attachments/"}`. -Attachments may also be streamed using `attachmentOptions: { stream: "true"}`. The `"attachment"` event will be fired every time an attachment is encountered. -Refer to the [mailparser docs](https://github.com/andris9/mailparser#attachment-streaming) for specifics on how to stream attachments. +The `"attachment"` event will be fired every time an attachment is encountered. ## Testing A test script is available at test.js. Before using the test script, it is necessary to set the following environment variables: diff --git a/test.js b/test.js index 898c115..cdae320 100644 --- a/test.js +++ b/test.js @@ -8,13 +8,12 @@ var mailListener = new MailListener({ tls: true, connTimeout: 10000, // Default by node-imap authTimeout: 5000, // Default by node-imap, - debug: console.log, // Or your custom function with only one incoming argument. Default: null + debug: null, // Or your custom function with only one incoming argument. Default: null tlsOptions: { rejectUnauthorized: false }, mailbox: "INBOX", // mailbox to monitor searchFilter: ["ALL"], // the search filter being used after an IDLE notification has been retrieved markSeen: true, // all fetched email willbe marked as seen and not fetched next time fetchUnreadOnStart: true, // use it only if you want to get all unread email on lib start. Default is `false`, - mailParserOptions: {streamAttachments: true}, // options to be passed to mailParser lib. attachments: true, // download attachments as they are encountered to the project directory attachmentOptions: { directory: "attachments/" } }); @@ -37,10 +36,18 @@ mailListener.on("error", function(err){ console.log(err); }); -mailListener.on("mail", function(mail, seqno, attributes){ - console.log("Mail: ",mail); +mailListener.on("headers", function(headers, seqno){ + console.log(`Email#${seqno} headers: `, headers); }); -mailListener.on("attachment", function(attachment){ - console.log(attachment); +mailListener.on("body", function(body, seqno) { + console.log(`Email#${seqno} body: `, body); +}) + +mailListener.on("attachment", function(attachment, path, seqno){ + console.log(`Email#${seqno} Attachment stored at: `, path); }); + +mailListener.on("mail", function(mail, seqno) { + console.log(`Email#${seqno} - entire parsed object: `, mail); +}) From d4d4093fbf57d388bc303b443823802be0cfb532 Mon Sep 17 00:00:00 2001 From: snyk-test Date: Wed, 4 Sep 2019 23:40:57 +0000 Subject: [PATCH 15/15] chore: upgrade async from 2.6.2 to 2.6.3 Snyk have raised this PR to upgrade async from 2.6.2 to 2.6.3. See this package in NPM: https://www.npmjs.com/package/async See this project in Snyk: https://app.snyk.io/org/matejmalicek/project/1b568cb0-42a7-41a9-a2fd-df62e9b2369d?utm_source=github&utm_medium=upgrade-pr --- package-lock.json | 17 ++++++++++++----- package.json | 2 +- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 78e8c80..9343de9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,22 @@ { "name": "mail-listener5", - "version": "1.0.0", + "version": "2.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { "async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", - "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", "requires": { - "lodash": "^4.17.11" + "lodash": "^4.17.14" + }, + "dependencies": { + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + } } }, "core-util-is": { diff --git a/package.json b/package.json index fb25f74..41296ae 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "dependencies": { "imap": "^0.8.19", "mailparser": "^2.4.3", - "async": "^2.6.2" + "async": "^2.6.3" }, "repository": { "type": "git",