How to fetch msg body using node-imap module - node.js

I'm using node-imap npm module to fetch the email and i'm getting pretty everything but the content of msg.
I used an already provided example on their git, shown below
openInbox(function(err, box) {
if (err) throw err;
var f = imap.seq.fetch(box.messages.total + ':*', { bodies: ['HEADER.FIELDS (FROM)','TEXT'] });
f.on('message', function(msg, seqno) {
console.log('Message #%d', seqno);
var prefix = '(#' + seqno + ') ';
msg.on('body', function(stream, info) {
if (info.which === 'TEXT')
console.log(prefix + 'Body [%s] found, %d total bytes', inspect(info.which), info.size);
var buffer = '', count = 0;
stream.on('data', function(chunk) {
count += chunk.length;
buffer += chunk.toString('utf8');
console.log('BUFFER', buffer) //HEre i am able to view the body
if (info.which === 'TEXT')
console.log(prefix + 'Body [%s] (%d/%d)', inspect(info.which), count, info.size);
});
stream.once('end', function() {
if (info.which !== 'TEXT')
console.log(prefix + 'Parsed header: %s', inspect(Imap.parseHeader(buffer)));
else
console.log(prefix + 'Body [%s] Finished', inspect(info.which));
});
});
msg.once('attributes', function(attrs) {
console.log(prefix + 'Attributes: %s', inspect(attrs, false, 8));
});
msg.once('end', function() {
console.log(prefix + 'Finished');
});
});
f.once('error', function(err) {
console.log('Fetch error: ' + err);
});
f.once('end', function() {
console.log('Done fetching all messages!');
imap.end();
});
});
In this example i am able to console out the content of the msg but i am unable to return it as json.

The returned value is a buffer. If you want a string, you can call the toString() method on the buffer. You said you want JSON. If the email body is properly formatted JSON you could also decode it:
var json = JSON.parse(buffer.ToString());

Related

Searching for emails with specific string in subject with Node-IMAP

My goal is to use IMAP to retrieve and display emails (pushed to an array called 'email') from a Gmail account as long as they have a specific string in the subject line. This is my first time using Node-IMAP. So far, I am able to return all emails found in the inbox, but as soon as I try to use imap.search it returns an empty array. I assume I'm missing something, but I can't figure out what.
var email = [];
imap.once('ready', function() {
openInbox(function(err, box) {
if (err) throw err;
imap.search([[ 'HEADER', 'SUBJECT', 'ABCDEFG'] ], function(err, results) {
if (err) throw err;
var f = imap.seq.fetch(results, {
bodies: 'HEADER.FIELDS (FROM SUBJECT DATE)',
});
f.on('message', function(msg, seqno) {
var prefix = '(#' + seqno + ') ';
msg.on('body', function(stream, info) {
var buffer = '';
stream.on('data', function(chunk) {
buffer += chunk.toString('utf8');
});
stream.once('end', function() {
email.push(prefix + inspect(Imap.parseHeader(buffer)));
});
});
});

Use node-imap to retrieve emails

Here is a module retrieve_email.js which connects to my gmail account and download the UNSEEN emails after a date. The code is pretty much copied from the example of the [imap module]1.
const Imap = require('imap');
const inspect = require('util').inspect;
const simpleParser = require('mailparser').simpleParser;
const imap = new Imap({
user: 'mygmail#gmail.com',
password: 'mypassword',
host: 'imap.gmail.com',
port: 993,
tls: true
});
function openInbox(callback) {
imap.openBox('INBOX', true, callback);
};
async function parse_email(body) {
let parsed = simpleParser(body);
...............
};
module.exports = function() {
imap.once('ready', function() {
openInbox(function(err, box) {
if (error) throw err;
imap.search(['UNSEEN', ['SINCE', 'May 20, 2018']], function(err, results){
if (err) throw err;
var f = imap.fetch(results, {bodies: ''});
f.on('message', function(msg, seqno) {
console.log('Message #%d', seqno);
var prefix = '(#' + seqno + ') ';
msg.on('body', function(stream, info) {
if (info.which === 'TEXT')
console.log(prefix + 'Body [%s] found, %d total bytes', inspect(info.which), info.size);
var buffer = '', count = 0;
stream.on('data', function(chunk) {
count += chunk.length;
buffer += chunk.toString('utf8');
parse_email(buffer);
if (info.which === 'TEXT')
console.log(prefix + 'Body [%s] (%d/%d)', inspect(info.which), count, info.size);
});
stream.once('end', function() {
if (info.which !== 'TEXT')
console.log(prefix + 'Parsed header: %s', inspect(Imap.parseHeader(buffer)));
else
console.log(prefix + 'Body [%s] Finished', inspect(info.which));
});
});
msg.once('attributes', function(attrs) {
console.log(prefix + 'Attributes: %s', inspect(attrs, false, 8));
});
msg.once('end', function() {
console.log(prefix + 'Finished');
});
});
f.once('error', function(err) {
console.log('Fetch error: ' + err);
});
f.once('end', function() {
console.log('Done fetching all messages');
imap.end();
});
});
});
});
imap.once('error', function(err) {
console.log(err);
});
imap.once('end', function() {
console.log('Connection ended');
});
imap.connect();
};
When the module is called in index.js, I can see in debug that code is scanned from top to the bottom and the last line of code scanned is imap.connect() and then back to the next line in index.js, with no connection to the gmail account and no action of retrieving the emails. What is wrong with the code above?
UPDATED: status after socket.connect() in debug:
Have a look at this, this is the Gmail API reference from Google. On that page there is an example of how to connect to it using Node.js.
https://developers.google.com/gmail/api/quickstart/nodejs
And here is an example from the same docs that show you how to search and retrieve message list using the q parameter:
https://developers.google.com/gmail/api/v1/reference/users/messages/list
P.S. In my comment i was just asking you if you were sure that you did all the other configuration stuff needed to access your Gmail account by code, meaning creating the app, authorizing OAuth or in what seemed to be your case authorizing less secure application access, just have a look at the links you might find that you are missing something.
And do you really need to use IMAP package ???
The problem found was with Avast mail shield as middle man intercepting the IMAP traffic and causes the HTTPS fails. Also the IDE debugger stops at somewhere to keep the connecting active but not ready. Here is the detail of the solution.

Nodemailer not sending response

I'm working on my first express project. I'm using Nodemailer and it's sending emails just fine but I'm not getting a response. Any insights? Here is the function I'm using to send the emails. It console logs message sent just fine, but doesn't seem to respond.
exports.email = function(req, res, options, tokens) {
receiver_id= options.email.receiver_id;
message= options.email.message;
sender_email = options.email.sender_email;
sender_name = options.email.sender_name;
slug=options.info.slug;
org_name=options.info.org_name;
dir_url=options.info.dir_url;
var https = require('https');
str = '';
//getting user email by id
path = '/api/v1/people/' + receiver_id +'?__proto__=&access_token=' + tokens[slug];
var options = {
host: slug + '.nationbuilder.com',
path: path,
method: "GET",
json: true,
headers: {
"content-type": "application/json",
"accept": "application/json"
},
}
var nb_req = https.get(options, req_callback);
function req_callback(response, res) {
response.on('data', function(chunk) {
str += chunk;
});
response.on('end', function() {
object = JSON.parse(str);
receiver_email = object.person.email1;
var nodemailer = require('nodemailer');
var transporter = nodemailer.createTransport({
port:465,
host:"smtp.gmail.com",
auth: {
user: 'connect#alumninations.com', // Your email id
pass: '69$6FK$b6PQu' // Your password
}
});
var html = '<p>From: ' + sender_email + '<br>';
html += 'To: ' + receiver_email + '</p>';
html += "<p>"+message + "</p>"
html += "<p>This message was delivered by the " + org_name + " alumni directory website, " + "<a href='" + dir_url
+ "'>" + dir_url + "</p>";
var mailOptions = {
from: 'connect#alumninations.com', // sender address
to: 'petervankoughnett#gmail.com', // list of receivers
subject: "A message from " + sender_name, // Subject line
/*text: "Message sent to", // plaintext body*/
html: html
};
transporter.sendMail(mailOptions, function(error, info){
if(error){
console.log(error);
res.json({yo: 'error'});
}else{
console.log('Message sent: ' + info.response);
res.sendStatus(200);
};
return res.sendStatus(200);
});
});
}
}
You are missing res.end() after res.sendStatus(200);.
transporter.sendMail(mailOptions, function(error, info){
if (error){
console.log(error);
res.json({yo: 'error'});
res.sendStatus(500);
}else{
console.log('Message sent: ' + info.response);
res.sendStatus(200);
};
return res.end();
}) ;
The following code worked for me in the transporter verify and sendMail functions.
transporter.verify(function (error, success) {
if (error) {
console.log(error);
} else {
console.log("Server is ready to take our messages");
res.send(success);
res.status(200);
}
});
transporter.sendMail(mailData, function (err, info) {
if (err) {
console.log("error: ", err);
} else {
console.log("all good", info);
res.sendStatus(200);
}
return res.status(200).end();
});
}
This is the asynchronous problem of JavaScript. I also have the same problem. When you call the email function outside it will not return anything so you will get 'undefined', because you returned a response within a callback function.
router.post('/"your api path"',async(req,res)=>{
//remaining codes
transporter.sendMail(mailOptions, function(error, info){
if(error){
console.log(error);
res.status(400).json({yo: 'error'});
}else{
console.log('Message sent: ' + info.response);
res.sendStatus(200);
};
return res.sendStatus(200);
});
}
use res.status(200).json() instead:
transporter.sendMail(mailOptions, function(error, info){
if (error){
console.log(error);
res.json({yo: 'error'});
res.sendStatus(500);
}else{
console.log('Message sent: ' + info.response);
res.status(200).json({"msg": "mesage has been sent"})
};});

Imap with Node.js, marking Email as read

I'm using Imap with node.js, and every time i connect it, it fetch al the emails from a data i gave it, but doens't mark them as read, so the following time it re-fecth them again.
Here is my code(All the functions implemented here are called in a main.js file), what can I change to mark the e-mail I'm fetching as read?
I've tried to do like written here (how to mark unseen email as seen with node-imap in node.js) but it didn't work..
var Imap = require('imap');
var inspect = require('util').inspect;
var formatter = require('./formatter.js');
var mailError = exports.mailError = [];
var imap = new Imap({
user: 'aaaaaaaaa#gmail.com',
password: 'xxxxxxx',
host: 'imap.gmail.com',
port: 993, //Perchè non 143, standard IMAP?
tls: true,
markSeen: true
});
function openInbox(cb) {
imap.openBox('INBOX', false, cb);
}
var onBodyCb = exports.onBodyCb = function(parsedHeaders, body){
var pos = (body.indexOf("Delivery to the following recipient failed permanently:") + 55);
var address = body.substr(pos,50);
var at = address.indexOf("#");
address = address.substr(0,at+formatter.company.length+formatter.domain.length+2);
address = address.replace(/ /g,'');
address = address.replace(/(\r\n|\n|\r)/gm,"");
console.log("onBodyCB: "+address+'\n');
mailError.push(address);
};
var onFinishedFetching = exports.onFinishedFetching = function(){};
imap.once('ready', function() {
var fs = require('fs'), fileStream;
openInbox(function(err, box) {
if (err) throw err;
imap.search([ 'UNSEEN', ['SINCE', 'July 10, 2014'] ], function(err, results) {
if (err) throw err;
// a questo abbiamo la box a cui possiamo accedere
var f = imap.fetch(results, { bodies: '' });
f.on('message', function(msg, seqno) {
//console.log('Message #%d', seqno);
var prefix = '(#' + seqno + ') ';
msg.on('body', function(stream, info) {
console.log(prefix + 'Body');
var buffer = '';
stream.on('data', function(chunk) {
buffer += chunk.toString('utf8');
});
//console.log(buffer);
stream.once('end', function() {
//console.log(prefix + 'Parsed header: %s', inspect());
var header = Imap.parseHeader(buffer);
exports.onBodyCb(header, buffer);
});
});
//msg.once('attributes', function(attrs) {
// console.log(prefix + 'Attributes: %s', inspect(attrs, false, 8));
//});
msg.once('end', function() {
//console.log(prefix + 'Finished');
});
});
f.once('error', function(err) {
console.log('Fetch error: ' + err);
});
f.once('end', function() {
console.log('Done fetching all messages!');
imap.end();
exports.onFinishedFetching();
});
});
});
});
imap.once('error', function(err) {
console.log(err);
});
imap.once('end', function() {
console.log('Connection ended');
});
exports.connect = function(){
imap.connect();
};
EDIT:
I've changed as suggested but it still doesn't work...
var Imap = require('imap');
var inspect = require('util').inspect;
var formatter = require('./formatter.js');
var mailError = exports.mailError = [];
var imap = new Imap({
user: 'marco.loco.recruiter#gmail.com',
password: 'coci2014',
host: 'imap.gmail.com',
port: 993, //Perchè non 143, standard IMAP?
tls: true,
markSeen : true,
markRead : true
});
function openInbox(cb) {
imap.openBox('INBOX', false, cb);
}
var onBodyCb = exports.onBodyCb = function(parsedHeaders, body){
var pos = (body.indexOf("Delivery to the following recipient failed permanently:") + 55);
var address = body.substr(pos,50);
var at = address.indexOf("#");
address = address.substr(0,at+formatter.company.length+formatter.domain.length+2);
address = address.replace(/ /g,'');
address = address.replace(/(\r\n|\n|\r)/gm,"");
console.log("onBodyCB: "+address+'\n');
mailError.push(address);
};
var onFinishedFetching = exports.onFinishedFetching = function(){};
imap.once('ready', function() {
var fs = require('fs'), fileStream;
openInbox(function(err, box) {
if (err) throw err;
imap.search([ 'UNSEEN', ['SINCE', 'July 10, 2014'] ], function(err, results) {
if (err) throw err;
// a questo abbiamo la box a cui possiamo accedere
var f = imap.fetch(results, { bodies: '' });
f.on('message', function(msg, seqno) {
//console.log('Message #%d', seqno);
var prefix = '(#' + seqno + ') ';
msg.on('body', function(stream, info) {
//console.log(prefix + 'Body');
var buffer = '';
stream.on('data', function(chunk) {
buffer += chunk.toString('utf8');
});
//console.log(buffer);
stream.once('end', function() {
//console.log(prefix + 'Parsed header: %s', inspect());
var header = Imap.parseHeader(buffer);
exports.onBodyCb(header, buffer);
});
});
//msg.once('attributes', function(attrs) {
// console.log(prefix + 'Attributes: %s', inspect(attrs, false, 8));
//});
msg.once('end', function() {
//console.log(prefix + 'Finished');
});
});
f.once('error', function(err) {
console.log('Fetch error: ' + err);
});
f.once('end', function() {
console.log('Done fetching all messages!');
imap.end();
exports.onFinishedFetching();
});
});
},false);
});
imap.once('error', function(err) {
console.log(err);
});
imap.once('end', function() {
console.log('Connection ended');
});
exports.connect = function(){
imap.connect();
};
var Imap = require("imap");
var MailParser = require("mailparser").MailParser;
var Promise = require("bluebird");
Promise.longStackTraces();
var imapConfig = {
user: 'USERNAME',
password: 'PASSWORD',
host: 'HOST',
port: 993,
tls: true
};
var imap = new Imap(imapConfig);
Promise.promisifyAll(imap);
imap.once("ready", execute);
imap.once("error", function(err) {
log.error("Connection error: " + err.stack);
});
imap.connect();
function execute() {
imap.openBox("INBOX", false, function(err, mailBox) {
if (err) {
console.error(err);
return;
}
imap.search(["UNSEEN"], function(err, results) {
if(!results || results.length){console.log("No unseen email available"); imap.end();return;}
imap.setFlags(results, ['\\Seen'], function(err) {
if (!err) {
console.log("marked as read");
} else {
console.log(JSON.stringify(err, null, 2));
}
});
var f = imap.fetch(results, { bodies: "" });
f.on("message", processMessage);
f.once("error", function(err) {
return Promise.reject(err);
});
f.once("end", function() {
console.log("Done fetching all unseen messages.");
imap.end();
});
});
});
}
function processMessage(msg, seqno) {
console.log("Processing msg #" + seqno);
// console.log(msg);
var parser = new MailParser();
parser.on("headers", function(headers) {
console.log("Header: " + JSON.stringify(headers));
});
parser.on('data', data => {
if (data.type === 'text') {
console.log(seqno);
console.log(data.text); /* data.html*/
}
// if (data.type === 'attachment') {
// console.log(data.filename);
// data.content.pipe(process.stdout);
// // data.content.on('end', () => data.release());
// }
});
msg.on("body", function(stream) {
stream.on("data", function(chunk) {
parser.write(chunk.toString("utf8"));
});
});
msg.once("end", function() {
// console.log("Finished msg #" + seqno);
parser.end();
});
}
{markRead: true} flag sometime it doesn't work, so you need to call set imap.setFlags([uuids], ['\Seen'], cb) explicitly
This is old question, but I had the same problem today. in the imap.seq.fetch call, there needs to be markSeen:true besides the bodies:"" . it should look like fetch(results,{bodies:"", markSeen:true}) –
And don't forget to open the Inbox in read-write mode as so many have said. imap.openBox('INBOX', false, cb)
Here is a working example to do the same.
var Imap = require('imap'),
inspect = require('util').inspect;
var imap = new Imap({
user: 'USERNAME',
password: 'PASSWORD',
host: 'IMAP_HOST',
port: 993, // Default port is 993
tls: true,
tlsOptions: {rejectUnauthorized: false}
});
function openInbox(cb) {
// openReadOnly = false
imap.openBox('Inbox', false, cb);
}
imap.once('ready', function () {
openInbox(function (err, box) {
if (err) throw err;
// Search emails having "Some Subject" in their Subject headers
imap.search([['HEADER', 'SUBJECT', 'Some Subject']], function (err, results) {
if (err) throw err;
try {
var f = imap.fetch(results, {bodies: 'TEXT'});
f.on('message', function (msg, seqno) {
msg.on('body', function (stream, info) {
var buffer = '';
stream.on('data', function (chunk) {
buffer += chunk.toString('utf8');
});
stream.once('end', function () {
// Mark the above mails as read
msg.once('attributes', function (attrs) {
let uid = attrs.uid;
imap.addFlags(uid, ['\\Seen'], function (err) {
if (err) {
console.log(err);
} else {
console.log("Marked as read!")
}
});
});
});
});
});
f.once('end', function () {
imap.end();
});
} catch (errorWhileFetching) {
console.log(errorWhileFetching.message);
imap.end();
}
});
});
});
imap.connect();

Read email body with node js imap

I'm trying to read the body of an e-mail that is retrieved with node js. I'm using this npm module: https://github.com/mscdex/node-imap
And I can get pretty much all the information of the email, except reading the content of the body.
Any ideas?
Thanks,
You can use this code to fetch email body and mark it as seen
var Imap = require("imap");
var MailParser = require("mailparser").MailParser;
var Promise = require("bluebird");
Promise.longStackTraces();
var imapConfig = {
user: 'USERNAME',
password: 'PASSWORD',
host: 'HOST',
port: 993,
tls: true
};
var imap = new Imap(imapConfig);
Promise.promisifyAll(imap);
imap.once("ready", execute);
imap.once("error", function(err) {
log.error("Connection error: " + err.stack);
});
imap.connect();
function execute() {
imap.openBox("INBOX", false, function(err, mailBox) {
if (err) {
console.error(err);
return;
}
imap.search(["UNSEEN"], function(err, results) {
if(!results || !results.length){console.log("No unread mails");imap.end();return;}
/* mark as seen
imap.setFlags(results, ['\\Seen'], function(err) {
if (!err) {
console.log("marked as read");
} else {
console.log(JSON.stringify(err, null, 2));
}
});*/
var f = imap.fetch(results, { bodies: "" });
f.on("message", processMessage);
f.once("error", function(err) {
return Promise.reject(err);
});
f.once("end", function() {
console.log("Done fetching all unseen messages.");
imap.end();
});
});
});
}
function processMessage(msg, seqno) {
console.log("Processing msg #" + seqno);
// console.log(msg);
var parser = new MailParser();
parser.on("headers", function(headers) {
console.log("Header: " + JSON.stringify(headers));
});
parser.on('data', data => {
if (data.type === 'text') {
console.log(seqno);
console.log(data.text); /* data.html*/
}
// if (data.type === 'attachment') {
// console.log(data.filename);
// data.content.pipe(process.stdout);
// // data.content.on('end', () => data.release());
// }
});
msg.on("body", function(stream) {
stream.on("data", function(chunk) {
parser.write(chunk.toString("utf8"));
});
});
msg.once("end", function() {
// console.log("Finished msg #" + seqno);
parser.end();
});
}
hope this code will help you :)
The Body of the message is in the spot where i have console.log("BUFFER", buffer)
I'm using node-imap npm module
imap.once('ready', function() {
openInbox(function(err, box) {
if (err) throw err;
var f = imap.seq.fetch(box.messages.total + ':*', { bodies: ['HEADER.FIELDS (FROM)','TEXT'] });
f.on('message', function(msg, seqno) {
console.log('Message #%d', seqno);
var prefix = '(#' + seqno + ') ';
msg.on('body', function(stream, info) {
if (info.which === 'TEXT')
console.log(prefix + 'Body [%s] found, %d total bytes', inspect(info.which), info.size);
var buffer = '', count = 0;
stream.on('data', function(chunk) {
count += chunk.length;
buffer += chunk.toString('utf8');
console.log("BUFFER", buffer)
if (info.which === 'TEXT')
console.log(prefix + 'Body [%s] (%d/%d)', inspect(info.which), count, info.size);
});
stream.once('end', function() {
if (info.which !== 'TEXT')
console.log(prefix + 'Parsed header: %s', inspect(Imap.parseHeader(buffer)));
else
console.log(prefix + 'Body [%s] Finished', inspect(info.which));
});
});
msg.once('attributes', function(attrs) {
console.log(prefix + 'Attributes: %s', inspect(attrs, false, 8));
});
msg.once('end', function() {
console.log(prefix + 'Finished');
});
});
f.once('error', function(err) {
console.log('Fetch error: ' + err);
});
f.once('end', function() {
console.log('Done fetching all messages!');
imap.end();
});
});
});
Try:
msg.once('end', function() {
console.log(buffer);
});

Resources