How to load all sql output data into html table - node.js

It is a simple email blast program which I build
I stuck in receiving data in a loop.
I want to print all the data from the result but i can able to print last data in the result.
Here is my code:
var mailer = require("nodemailer"),
config = require('./config'),
redshiftClient = require('./redshift.js'),
sql = require('./main');
var smtpTransport = mailer.createTransport({
service: "Outlook",
auth: {
user: config.user,
pass: config.passwd
}
});
console.log("Application started at : "+ new Date().getTime())
sql.log();
redshiftClient.query(getQuery())
.then(function (data) {
console.log("Query executed at " + new Date().getTime())
var element = data.rows[index];
for (let index = 0; index < data.rows.length; index++) {
var element = data.rows[index];
var mail = {
from: 'xxxxxxx#outlook.com',
to: 'xxxxx#gmail.co.in',
subject: `Daily AWS validation check for the ${new Date().getTime()}`,
html: `<h1> Hello Team, Here is the hourly data pull</h1> <br> <table><tr> <th>Hoursdata</th> <th>Book_Counts</th> <th>Search_Counts</th> <th>Hit_Counts</th> <tr><td>${element.run_hour}</td> <td>${element.book_counts}</td> <td>${element.search_counts}</td> <td>${element.hit_counts}</td></tr> </table>`
}
smtpTransport.sendMail(mail, function (error, response) {
if (error) {
console.log(error);
} else {
console.log("Email sent");
}
smtpTransport.close();
});
}
})
.catch(function (err) {
console.error(err);
});
redshiftClient.close();
My Output for the code: (It gave the last value)
Hoursdata Book_Counts Search_Counts Hit_Counts
2 2131 5645654 4355
Expected output: (I need all the value)
Hoursdata Book_Counts Search_Counts Hit_Counts
1 23425 457474 2534
2 2131 5645654 4355

What you are trying to do is, iterate over all the rows and for each row send a message, while you should be creating a mail message once with all the details in html. As suggested in my previous answer, use some npm package to create html and pass it to html while creating message and after that send email.

Related

SendGrid Multiple Emails to Multiple Recipients Node JS from Firebase Firestore

I am using SendGrid and Firebase Functions to send multiple emails to multiple recipients. The code that I am using works correctly when sending to a test list of 4 email addresses, but does not work when trying to send to 4,000 email addresses. There is also no error message from SendGrid.
This code also works and returns the list of email addresses printed in the console if the SendGrid block of code is commented out.
Do you know what could be going wrong?
Thank you
exports.adminSendGroupMessage = functions.region('europe-west2').https.onCall((data, context) => {
const emailHTMLData = emailHTMLData;
var emailDataArray = [];
//Fetch contacts list
let testContactsRef = db.collection('contacts-list');
return testContactsRef.get().then(snapshot => {
snapshot.forEach(doc => {
// console.log(doc.id, '=>', doc.data());
console.log("Fetched contact with ID: " + doc.id);
//Extract contact data
const firstName = doc.data().name || "";
const surname = doc.data().surname || "";
const emailAddress = doc.data().emailAddress;
var emailData = {
to: emailAddress,
from: 'fromEmail#email.com',
subject: messageSubject,
text: 'Email for ' + firstName,
html: emailHTMLData,
customArgs: {
ref: 'msg-ref'
},
}
//Add new email data to the array
emailDataArray.push(emailData);
});
return Promise.all(emailDataArray).then(results => {
//Send emails with all data once contact fetch complete
console.log("Success fetching contacts - send emails.");
sendGridGroupMessages(emailDataArray);
return { success : true, message: "Success sending emails" };
})
});
function sendGridGroupMessages(emailDataArray) {
console.log('Send emails to group function with data: ' + emailDataArray.length);
var i,j, splitArray,chunk = 998;
for (i=0,j=emailDataArray.length; i<j; i+=chunk) {
splitArray = emailDataArray.slice(i,i+chunk);
// do whatever
//Send emails
sgMail.send(splitArray, (error, result) => {
if (error) {
//Do something with the error
console.log("Error sending group emails: " + error);
// throw new functions.https.HttpsError('internal', 'There was an error sending the group emails - ' + error.message + ' (' + error.code + ')');
} else {
//Celebrate
console.log("Success sending group emials: " + JSON.stringify(result));
// return { success : true };
}
});
}
You must post the error log
If no errors it means they sent
but check SendGrid activities to see what happened to these emails

How to link progress-streamer with node-mailer for more than one attachments?

My code for sending mailing with multiple files as an attachment using node mailer js was working before adding progress-bar and for progress-bar I use progress-stream. It shows progress bar but the receiver only receives only one corrupted file.
My code is here
function mail() {
getSelected(); // this function store addresses of all the files in checked array
att = [];
var nodemailer = require('nodemailer');
var fs = require('fs');
var transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: document.getElementById("from").value,
pass: document.getElementById("ps").value
}
});
for (var i = 0; i < checked.length; i++) { //measuring total size of files
attSize += fs.statSync(checked[i])["size"];
}
var progress = require('progress-stream');
var str = progress({
length: attSize,
time: 100 /* ms */
});
for (var i = 0; i < checked.length; i++) { //adding all src/path of selected files in att
attSize += fs.statSync(path)["size"];
att.push({
filename: filename,
content: fs.createReadStream(path).pipe(str)
});
}
str.on('progress', function(progress) {
if (progress.length == 100) {
toast("Sending Email!", 500);
} else {
showToast('Uploading Attachment :' + progress.length + ' %');
}
});
var mailOptions = {
from: document.getElementById("from"),
to: document.getElementById("to").value,
subject: 'Custom Subject',
text: 'This is simple text ... That was easy!',
attachments: att
};
transporter.sendMail(mailOptions, function(error, info) {
if (error) {
toast(error, 2000);
} else {
toast('Email sent: ' + info.response, 2000);
}
});
}
I think the problem is here
content: fs.createReadStream(path).pipe(str)
So If I use .pipe(str) in more than one files progress bar is working but attachment images are corrupted and instead of multiple files receiver only receives one file

Why is this code sending duplicate emails?

We're running a scheduler on Azure that runs every minute and checks in a database to see what emails need to be sent for our app and sends them.
This works the vast majority of the time but once in a while, for a few hours, the scheduler starts sending most emails in duplicates (up to 5 copies).
query = "select id, email, textbody, htmlbody, subject from emailTable where sent = 0 AND DateSent IS NULL";
mssql.query(query, {
success: function(results) {
for(var i = 0 ; i < results.length; i++)
{
handleItem(results[i]);
}
},
error: function(err) {
console.log("Error : " + err);
}
});
function handleItem(item) {
sendMail(item);
var query = "update emailTable SET sent = 1, DateSent = GETDATE() where id = ?";
mssql.query(query, [item.id]);
}
function sendMail(objMail)
{
sendgrid.send({
to: objMail.email,
from: 'source#sourcemail.com',
fromname: "Source",
subject: objMail.subject,
text: objMail.textbody,
html: objMail.htmlbody
}, function(err, json) {
if (err) { return console.error(err); }
});
}
When it starts failing it's as if handleItem or sendMail is called multiple times for the same item. Is there anything wrong with the loop or the general logic that would explain this behavior ?
Try writing the update query in the callback function for sendMail(item)
eg. sendMail(item,function(){
var query = "update emailTable SET sent = 1, DateSent = GETDATE() where id = ?";
mssql.query(query, [item.id]);
});
function sendMail(objMail,cb)
{
sendgrid.send({
to: objMail.email,
from: 'source#sourcemail.com',
fromname: "Source",
subject: objMail.subject,
text: objMail.textbody,
html: objMail.htmlbody
}, function(err, json) {
if (err) { cb(err) }
cb(null,json)
});
}

Incorrect gmail parsing with node-imap and mailparser

I'm writing a Node.js script that retrieves unread emails from my gmail inbox using node-imap, parses them with mailparser, and then does some work with the parsed emails. I'm running into a problem where the raw email being received doesn't seem to be parsed correctly by mailparser. I'm not sure if I've done something wrong in calling node-imap or mailparser, or if the email itself is in a bad format for some reason. I've included the code I'm running as well as the output produced.
var Imap = require("imap"),
MailParser = require("mailparser").MailParser,
Promise = require("bluebird"),
request = require("request-promise").defaults({jar: true}),
log = require("winston"),
_ = require("underscore"),
config = require("config").jobs;
var logConfig = _.clone(config.logConfig.email);
if (process.env.LOG_DIR) {
logConfig.filename = process.env.LOG_DIR + "/" + logConfig.filename;
}
log.add(log.transports.File, logConfig || config.logConfig);
Promise.longStackTraces();
var imap = new Imap(config.emailConfig);
Promise.promisifyAll(imap);
imap.once("ready", execute);
imap.once("error", function (err) {
log.error("Connection error: " + err.stack);
});
imap.connect();
function execute() {
imap.openBoxAsync("INBOX", false)
.then(function () {
return imap.searchAsync(["UNSEEN"]);
})
.then(function (results) {
var f = imap.fetch(results, {bodies: ["HEADER.FIELDS (FROM SUBJECT)", "TEXT"]});
f.on("message", processMessage);
f.once("error", function (err) {
return Promise.reject(err);
});
f.once("end", function () {
log.info("Done fetching all unseen messages.");
imap.end();
});
})
.catch(function (err) {
log.error("Error fetching messages: " + err.stack);
imap.end();
});
}
function processMessage(msg, seqno) {
log.info("Processing msg #" + seqno);
var parser = new MailParser();
parser.on("headers", function(headers) {
log.info("Header: " + JSON.stringify(headers));
});
parser.on("end", function(msg) {
log.info("From: " + msg.from);
log.info("Subject: " + msg.subject);
log.info("Text: " + msg.text);
log.info("Html: " + msg.html);
});
msg.on("body", function (stream) {
stream.on("data", function (chunk) {
parser.write(chunk.toString("utf8"));
});
});
msg.once("end", function () {
log.info("Finished msg #" + seqno);
parser.end();
});
}
Output:
info: Processing msg #1
info: Finished msg #1
info: Done fetching all unseen messages.
info: Header: {"--001a11339690da942a051d866a04":"","content-type":"text/plain; charset=UTF-8"}
info: From: undefined
info: Subject: undefined
info: Text: Test app mail body!
- Jared
--001a11339690da942a051d866a04
Content-Type: text/html; charset=UTF-8
<div dir="ltr"><div>Test app mail body!<br><br></div>- Jared<br></div>
--001a11339690da942a051d866a04--
Subject: Here is a test appmail email
From: Jared Wolinsky <jared.wolinsky#gmail.com>
info: Html: undefined
You're fetching the raw body of the email. mailparser is expecting the full email, headers and body both. To fetch that instead, just specify an empty string '' instead of 'TEXT'.

Mocking email function in nodejs

I've got a mailer function I've built and trying to shore up the coverage. Trying to test parts of it have proven tricky, specifically this mailer.smtpTransport.sendMail
var nodemailer = require('nodemailer')
var mailer = {}
mailer.smtpTransport = nodemailer.createTransport('SMTP', {
'service': 'Gmail',
'auth': {
'XOAuth2': {
'user': 'test#test.com',
'clientId': 'googleClientID',
'clientSecret': 'superSekrit',
'refreshToken': '1/refreshYoSelf'
}
}
})
var mailOptions = {
from: 'Some Admin <test#tester.com>',
}
mailer.verify = function(email, hash) {
var emailhtml = 'Welcome to TestCo. Click this '+hash+''
var emailtxt = 'Welcome to TestCo. This is your hash: '+hash
mailOptions.to = email
mailOptions.subject = 'Welcome to TestCo!'
mailOptions.html = emailhtml
mailOptions.text = emailtxt
mailer.smtpTransport.sendMail(mailOptions, function(error, response){
if(error) {
console.log(error)
} else {
console.log('Message sent: '+response.message)
}
})
}
I'm unsure of how to go about testing, specifically ensuring that my mailer.smtpTransport.sendMail function is passing the correct parameters without actually sending the email. I'm trying to use https://github.com/whatser/mock-nodemailer/tree/master, but I'm probably doing it wrong. Should I be mocking out the method?
var _ = require('lodash')
var should = require('should')
var nodemailer = require('nodemailer')
var mockMailer = require('./helpers/mock-nodemailer')
var transport = nodemailer.createTransport('SMTP', '')
var mailer = require('../../../server/lib/account/mailer')
describe('Mailer', function() {
describe('.verify()', function() {
it('sends a verify email with a hashto an address when invoked', function(done) {
var email ={
'to': 'dave#testco.com',
'html': 'Welcome to Testco. Click this bleh',
'text': 'Welcome to Testco. This is your hash: bleh',
'subject': 'Welcome to Testco!'
}
mockMailer.expectEmail(function(sentEmail) {
return _.isEqual(email, sentEmail)
}, done)
mailer.verify('dave#testco.com','bleh')
transport.sendMail(email, function() {})
})
})
You can use a 'Stub' transport layer on your test instead of SMTP.
var stubMailer = require("nodemailer").createTransport("Stub"),
options = {
from: "from#email.com",
to: "to#email.com",
text: "My Message!"
};
stubMailer.sendMail(options, function(err, response){
var message = response.message;
})
So, in that case, 'message' will be the email in text format. Something like this:
MIME-Version: 1.0
X-Mailer: Nodemailer (0.3.43; +http://www.nodemailer.com/)
Date: Fri, 25 Feb 2014 11:11:48 GMT
Message-Id: <123412341234.e23232#Nodemailer>
From: from#email.com
To: to#email.com
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
My Message!
For more examples, take a look at nodemailer test suite:
https://github.com/andris9/Nodemailer/blob/master/test/nodemailer-test.js
You can directly mock the sendMail function but it's not obvious how to access it from the tests. A Mailer instance is returned when you create a transport so you need to directly import that class in to your test.
const Mailer = require('nodemailer/lib/mailer')
Then you can mock or stub the sendMail method on the prototype in the usual way. Using Jasmine, you can do it like this:
beforeEach(function () {
spyOn(Mailer.prototype, 'sendMail').and.callFake(function (mailOptions, cb) {
cb(null, true)
})
})
The callFake ensures that the sendMail's callback is still executed encase you need to test what happens next. You can easily simulate an error by passing a first argument to cb: cb(new Error('Email failed'))
Now that the mock is set up, you can check everything is working as intended:
expect(Mailer.prototype.sendMail).toHaveBeenCalled()
expectEmail simply hooks into the transport layer, and expects you to identify the email ( return true if this is the email you are expecting ) by looking at the sentEmail contents.
In this case, return sentEmail.to === 'dave#testco.com' should suffice.
Keep in mind however, this module was designed in an environment where tests are ran in a random order and concurrently. You should propably randomize your data heavily to prevent collisions and false positives. BTW we use something like: var to = Date.now().toString(36) + Faker.Internet.email();
This example works fine for me
======== myfile.js ========
// SOME CODE HERE
transporter.sendMail(mailOptions, (err, info) => {
// PROCESS RESULT HERE
});
======== myfile.spec.js (unit test file) ========
const sinon = require('sinon');
const nodemailer = require('nodemailer');
const sandbox = sinon.sandbox.create();
describe('XXX', () => {
afterEach(function() {
sandbox.restore();
});
it('XXX', done => {
const transport = {
sendMail: (data, callback) => {
const err = new Error('some error');
callback(err, null);
}
};
sandbox.stub(nodemailer, 'createTransport').returns(transport);
// CALL FUNCTION TO TEST
// EXPECT RESULT
});
});

Resources