Node JS - nodemailer & imap-simple - Identify threads - node.js

(I feel sorry for my poor english, but i'll do my best !) :)
I'm trying to setup a local mailbox for a personnal project, and i'm trying to use imap-simple and nodemailer to do that.
I want to be able to identify a thread, when i send an e-mail.
Here's what i exactly want to do :
In my application, i'll be able to send an e-mail to a specific person (let's admit foo#bar.com)
When the mail is sent, a callback function will store mail content and subject in DB (for example, in a CRM app, i will store the sent mail which will be related to a specific record in my database).
The complex part is just after that :
When the person replies to this e-mail, i want using IMAP to identify that this person is answering to my previous mail, and then store it in DB too, also linked to the same record i used on my first e-mail.
I actually have this in a sandbox folder (For IMAP) :
var imaps = require('imap-simple');
var nodemailer = require('nodemailer');
var config = {
imap: {
user: 'catchall#xxxxxxxx.fr',
password: 'xxxxxxxx',
host: 'imap.gmail.com',
port: 993,
tls: true,
authTimeout: 3000
}
};
imaps.connect(config).then(function (connection) {
return connection.openBox('INBOX').then(function () {
var searchCriteria = [
'UNSEEN'
];
var fetchOptions = {
bodies: ['HEADER', 'TEXT'],
markSeen: false,
};
console.log('Passing there');
return connection.search(searchCriteria, fetchOptions).then(function (results) {
var subjects = results.map(function (res) {
return res.parts.filter(function (part) {
return part.which === 'HEADER';
})[0].body.subject[0];
});
console.log('BASE');
console.log(results[0]);
console.log('FIRST');
console.log(results[0].parts[0]);
console.log('SECOND');
console.log(results[0].parts[1]);
});
});
});
And here is the SMTP part :
var transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: 'catchall#xxxxxxxx.fr',
pass: 'xxxxxxxx'
}
});
const mailOptions = {
from: 'catchall#xxxxxxxx.fr', // sender address
to: 'xxxxxxxx#gmail.com', // list of receivers
subject: 'Subject of your email', // Subject line
html: '<p>Here is my test !</p>',// plain text body
headers: {
'collection': 'Pipelines',
'doc-ID': 'mydocid'
}
};
transporter.verify(function(error, success) {
if (error) {
console.log(error);
} else {
console.log("Server is ready to take our messages");
}
});
transporter.sendMail(mailOptions, function (err, info) {
if(err)
console.log(err)
else
console.log(info);
});
Here is a screen of what i want to be able to :
On IMAP, i'm getting exactly the information i want in console :
BASE
{ attributes:
{ date: 2019-12-05T16:53:07.000Z,
flags: [],
uid: 94,
modseq: '27800',
'x-gm-labels': [ '\\Important' ],
'x-gm-msgid': '1652099423356172171',
'x-gm-thrid': '1652099362185438260' },
x-gm-thrid allow me to identify a thread. Perhaps, i can't find this information in the nodemailer callback function :
Server is ready to take our messages
{ accepted: [ 'xxxxxxxxxxxxxxxxx#gmail.com' ],
rejected: [],
envelopeTime: 400,
messageTime: 819,
messageSize: 346,
response: '250 2.0.0 OK 1575566223 m3sm12955793wrs.53 - gsmtp',
envelope:
{ from: 'catchall#xxxxxxxxxx.fr',
to: [ 'xxxxxxxxxxxx#gmail.com' ] },
messageId: '<f93b3970-e17a-84b5-d0d1-ebb4fd6efe46#xxxxxxxxxx.fr>' }
Does anyone have an idea of how i could proceed ?
Thanks a lot btw !
Happy coding :)

For those who will read this post, here the answer, thanks to #arnt,
As #arnt said, there is for IMAP protocol, a reference attribute which is storing the previous message ID stored in results[0].parts[1] :
references: [ '<23df0af1-8ff1-0ffa-091e-a645a38e4a67#foobar.fr>' ],
'in-reply-to': [ '<23df0af1-8ff1-0ffa-091e-a645a38e4a67#foobar.fr>' ],
This one is also available when you send a message, in info :
envelope:
{ from: 'foobar#foobar.fr',
to: [ 'foobar#gmail.com' ] },
messageId: '<23df0af1-8ff1-0ffa-091e-a645a38e4a67#foobar.fr>' }
This way, we're able to correlate mail conversation.
Thanks a lot for help :)
Topic closed

Related

get only those mail which are send through email reply with attachment in node js

Hi,i am trying to get only those emails which are received as email reply send by my system.for more specific i am sending email with attachment .and receiver replies to that email with attachment.
I want history of email in my system which shows which attachment is received against which email. for example if i have send email to pearson B.Pearson B will reply to that email.i want history of this.
I am able to send and receive email.But the issue is that i am getting all email fetched betwwen a and b(I want only those email which is send as reply of particular email).Below i gave given code to fetch email.
async function mailreply(req, res) {
Employee.email_reply(req.params.email, function (err, employee) {
var imapConfig = {
user: '*****',
password: '****',
host: 'imap-mail.outlook.com',
port: 993,
tls: true,
tlsOptions: {
rejectUnauthorized: false
}
};
var imap = new Imap(imapConfig);
imap.once("ready", checkMail);
imap.once("error", function (err) {
console.log("Connection error: " + err.stack);
});
imap.connect();
function checkMail() {
imap.openBox("INBOX", false, function (err, mailBox) {
if (err) {
console.error(err);
return;
}
imap.search(["UNSEEN", ["FROM", req.params.email]], function (err, results) {
if (!results || !results.length) {
req.flash('error', 'No reply from selected user.')
res.locals.message = req.flash();
res.redirect(nodeSiteUrl+'/dashboard');
imap.end(); return; }
});
});
}
var mailListener = new MailListener({
username: "******",
password: "******",
host: "imap-mail.outlook.com",
port: 993, // imap port
tls: true,
connTimeout: 10000, // Default by node-imap
authTimeout: 5000, // Default by node-imap,
tlsOptions: { rejectUnauthorized: false },
mailbox: "INBOX", // mailbox to monitor
searchFilter: [ 'UNSEEN', ['FROM', req.params.email] ], // the search filter being used after an IDLE notification has been retrieved ,
markSeen: false, // 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
});
mailListener.start();
mailListener.on("server:connected", function(){
console.log("imapConnected");
});
mailListener.on("error", function(err){
console.log('hello');
});
mailListener.on("mail", function(mail, seqno, attributes){
console.log(seqno)
let attachments = [];
var attachment = mail.attachments;
if(attachment) {
for(var i = 0, len = attachment.length; i < len; ++i){
attachments.push(attachment[i].fileName);
}
}
passDatatoPage(mail, attachments);
mailListener.stop();
})
mailListener.on("attachment", function(attachment){
let filepath = './public/attachment/receive/';
let output = fs.createWriteStream(filepath + attachment.fileName);
attachment.stream.pipe(output).on("end", function () {
console.log("All the data in the file has been read");
}).on("close", function (err) {
console.log("Stream has been cloesd.");
});
});
function passDatatoPage(mail, attachments) {
var sender = mail.to[0].address;
var senderName = mail.from[0].name;
var reciver = mail.from[0].address;
const date = moment(mail.date).format('LL');
var subject = mail.subject;
var message = mail.text;
//console.log(attachments);
var result = attachments.map(function(val) {
return val;
}).join(',');
var attachmentArr = result.split(',');
console.log(attachmentArr)
res.render('email-reply', { title: 'Email Reply', to: sender, senderName: senderName, from: reciver, date: date, subject: subject, msg: message, attachments: attachmentArr});
}
});
};
exports.mailreply = mailreply;
In this code i am getting header error shown here
code error
May I know what is wrong with my code?
please provide possible solution in this code or provide way how i achive my task.
Thanks in advance.
you need to do two things
when you send email store message id in database
get that message id and change search filter acording to below code
(use below search filter to find message by id)
var mailListener = new MailListener({
username: "HR2#almashriq.edu.sa",
password: "Tab13510",
host: "imap-mail.outlook.com",
port: 993, // imap port
tls: true,
connTimeout: 10000, // Default by node-imap
authTimeout: 5000, // Default by node-imap,
tlsOptions: { rejectUnauthorized: false },
mailbox: "INBOX", // mailbox to monitor
searchFilter: [ ['HEADER','IN-REPLY-TO',messageId] ], // the search filter being used after an IDLE notification has been retrieved ,
markSeen: false, // 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
});

err_http_headers_sent]: cannot set headers after they are sent to the client in fetching email from server

I am trying to fetch email with attachment.I have used imap and MailListener2 library for that.i am facing following error as shown in image.i am getting all data fetched from email with attachment.can anyone tell what i have missed?
this is my code which i have used for fetching email .please provide any solution for this error.
async function mailreply(req, res) {
Employee.email_reply(req.params.email, function (err, employee) {
var imapConfig = {
user: '*****',
password: '****',
host: 'imap-mail.outlook.com',
port: 993,
tls: true,
tlsOptions: {
rejectUnauthorized: false
}
};
var imap = new Imap(imapConfig);
imap.once("ready", checkMail);
imap.once("error", function (err) {
console.log("Connection error: " + err.stack);
});
imap.connect();
function checkMail() {
imap.openBox("INBOX", false, function (err, mailBox) {
if (err) {
console.error(err);
return;
}
imap.search(["UNSEEN", ["FROM", req.params.email]], function (err, results) {
if (!results || !results.length) {
req.flash('error', 'No reply from selected user.')
res.locals.message = req.flash();
res.redirect(nodeSiteUrl+'/dashboard');
imap.end(); return; }
});
});
}
var mailListener = new MailListener({
username: "******",
password: "******",
host: "imap-mail.outlook.com",
port: 993, // imap port
tls: true,
connTimeout: 10000, // Default by node-imap
authTimeout: 5000, // Default by node-imap,
tlsOptions: { rejectUnauthorized: false },
mailbox: "INBOX", // mailbox to monitor
searchFilter: [ 'UNSEEN', ['FROM', req.params.email] ], // the search filter being used after an IDLE notification has been retrieved ,
markSeen: false, // 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
});
mailListener.start();
mailListener.on("server:connected", function(){
console.log("imapConnected");
});
mailListener.on("error", function(err){
console.log('hello');
});
mailListener.on("mail", function(mail, seqno, attributes){
console.log(seqno)
let attachments = [];
var attachment = mail.attachments;
if(attachment) {
for(var i = 0, len = attachment.length; i < len; ++i){
attachments.push(attachment[i].fileName);
}
}
passDatatoPage(mail, attachments);
mailListener.stop();
})
mailListener.on("attachment", function(attachment){
let filepath = './public/attachment/receive/';
let output = fs.createWriteStream(filepath + attachment.fileName);
attachment.stream.pipe(output).on("end", function () {
console.log("All the data in the file has been read");
}).on("close", function (err) {
console.log("Stream has been cloesd.");
});
});
function passDatatoPage(mail, attachments) {
var sender = mail.to[0].address;
var senderName = mail.from[0].name;
var reciver = mail.from[0].address;
const date = moment(mail.date).format('LL');
var subject = mail.subject;
var message = mail.text;
//console.log(attachments);
var result = attachments.map(function(val) {
return val;
}).join(',');
var attachmentArr = result.split(',');
console.log(attachmentArr)
res.render('email-reply', { title: 'Email Reply', to: sender, senderName: senderName, from: reciver, date: date, subject: subject, msg: message, attachments: attachmentArr});
}
});
};
exports.mailreply = mailreply;
you need to do two things
try to wrap up code with try catch block
do not fetch all emails from sender fetch only thhose mail witch is needed
For example fetch mail using message id as shown below
get that message id and change search filter acording to below code
(use below search filter to find message by id)
var mailListener = new MailListener({
username: "******",
password: "*****",
host: "imap-mail.outlook.com",
port: 993, // imap port
tls: true,
connTimeout: 10000, // Default by node-imap
authTimeout: 5000, // Default by node-imap,
tlsOptions: { rejectUnauthorized: false },
mailbox: "INBOX", // mailbox to monitor
searchFilter: [ ['HEADER','IN-REPLY-TO',messageId] ], // the search filter being used after an IDLE notification has been retrieved ,
markSeen: false, // 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
});
I believe the request may have finished once imap.once("ready", checkMail); fires, this is race condition. Once it has finished the connection will be closed so you can no longer change what is an already sent request. You will need to add some code to wait for all the events to finish before finishing off the request handler.

Sending email to dynamic sender address using MEAN and Node Mailer

I am struck with sending email to dynamic sender address using MEAN(Angular 2+) and Node Mailer. I couldn't find a single example or tutorial for sending email to dynamic sender address. Can any one give a very simple example with single value with html, TS, service and server file codes please.
var nodeMailer = require('nodemailer');
function sendEmail(email, callback) {
var transporter = nodeMailer.createTransport({
host: 'smtp.gmail.com',
port: 465,
secure: true,
auth: {
user: 'youremail#gmail.com',
pass: 'password'
}
});
var mailOptions = {
from: 'youremail#gmail.com',
to: email,
subject: 'Email Verification',
text: 'Hi there, a simple test mail'
//html: '' //for html code
};
transporter.sendMail(mailOptions, function (err, info) {
if (err) {
callback(err);
} else {
callback(null, 'success');
}
});
}
Everything is same till HTTP call. Just call the function with required email

Emails sent via nodemailer from my server come through as spam: (unknown sender)

First time using Node and working with email configuration. I downloaded this application from here, it works (uses mustache.js to generate templates for the emails), but the test email ends up in my gmail spam.
from: via vps1234.inmotionhosting.com
to: thisisme#gmail.com
date: Tue, Aug 8, 2017 at 5:30 PM
subject: Thanks! and review your experience
mailed-by: vps1234.inmotionhosting.com
security: Standard encryption (TLS) Learn more
-
var nodemailer = require('nodemailer');
let transporter = nodemailer.createTransport({
service: ' ',
secure: false,
port: 25,
auth: {
user: 'thisisme#mydomain.com',
pass: 'password1234'
},
tls: {
rejectUnauthorized: false,
}
}),
EmailTemplate = require('email-templates').EmailTemplate,
path = require('path'),
Promise = require('bluebird');
let users = [
{
name: 'John',
note: 'I found your purse',
email: 'recipient#gmail.com',
}
];
function sendEmail (obj) {
return transporter.sendMail(obj);
}
function loadTemplate (templateName, contexts) {
let template = new EmailTemplate(path.join(__dirname, 'templates', templateName));
return Promise.all(contexts.map((context) => {
return new Promise((resolve, reject) => {
template.render(context, (err, result) => {
if (err) reject(err);
else resolve({
email: result,
context,
});
});
});
}));
}
loadTemplate('welcome', users).then((results) => {
return Promise.all(results.map((result) => {
sendEmail({
to: result.context.email,
from: 'Me :)',
subject: result.email.subject,
html: result.email.html,
text: result.email.text,
});
}));
}).then(() => {
console.log('Yay!');
});
This is Nodemailer boilerplate, which I tested also on my server, and it worked correctly, and the email did not get flagged:
var nodemailer = require('nodemailer');
let transporter = nodemailer.createTransport({
service: ' ',
secure: false,
port: 25,
auth:{
user: 'thisisme#mydomain.com',
pass: 'password1234'
},
tls: {
rejectUnauthorized: false,
}
});
let helperOptions = {
from: '<thisisme#mydomain.com>',
to: 'recipient1234#gmail.com',
};
transporter.sendMail(helperOptions, (error, info) =>{
if(error){return alert(error);}
console.log("sent" . info);
})
A message being marked as spam is not so much a function of the code that generated it but of a few other things such as:
the actual content (text, links etc)
the domain it came from
The first issue is just something you have to play with. There are services such as MailMonitor and others that help you tweak your content to see how gmail and others handle it. Wording, HTML vs plain text, links vs none, etc all play a part.
As far as the domain, you'll want to setup your SPF (Sender Policy Framework) and DKIM entries to essentially validate your domain as a proper sender. The "unknown sender" is most likely a missing SPF record.
For SPF here's an article.
For DKIM here's another
Note that I just googled for this - they seemed like good articles but I am sure there are other great sources.
The gist of it is that you'll want to create a couple of TXT entries in your DNS. There are tools such as SPF generators to help you with this. It's not as complex as it may sound.
Once that is done you might still end up in spam but it will certainly help. You can experiment with services such as Amazon SES and SendGrid which might provide better sending "validity" than your current SMTP server.

Can't send mail node mailer

I am getting Recipient Error: Can't send mail - no recipient defined error while sending an email using npm node mailer. I am consulting the example as in the documentation. consider abc#gmail.com with my real email.
var emailAddress = "abc#gmail.com";
mailOptions = {
from: "Admin <abc#gmail.com>", // sender address
to: emailAddress, // list of receivers
subject: "Hello", // Subject line
text: "hello", // plaintext body
html: "<b>Hello</b>" // html body
}
smtpTransport = nodeMailer.createTransport("SMTP",{
service: "Gmail",
auth: {
user: "abc#gmail.com",
pass: "123"
}
});
smtpTransport.sendMail(mailJson, function(error, response){
if(error){
console.log(error);
}else{
console.log("Message sent: " + response.message);
}
// if you don't want to use this transport object anymore, uncomment following line
smtpTransport.close(); // shut down the connection pool, no more messages
});
The following advise would be useful (for others users):
mailJson is your configuration called mailOptions.
Would return in a promise your result, which is so useful when you're sending an email in an async code.
So, your code would be the following:
mailOptions = {
from: "Admin <abc#gmail.com>", // sender address
to: emailAddress, // list of receivers
subject: "Hello", // Subject line
text: "hello", // plaintext body
html: "<b>Hello</b>" // html body
}
smtpTransport = nodeMailer.createTransport("SMTP",{
service: "Gmail",
auth: {
user: "abc#gmail.com",
pass: "123"
}
});
return new Promise((resolve, reject) => {
transporter.sendMail(mailOptions, (error, info) => {
error ? reject(error) : resolve(info);
});
});
});
If no solution work for you
Go to that link and active less secure than try to send mail
enter link description here

Resources