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
Related
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.
As part of small email CRM project, i have created a Nodejs app. While i send email through gmail send api, the messages are not grouped.
const sendObject = {}
output.data.messages.map(each => {
sendObject.threadId = each.threadId // ThreadID is unique.
each.payload.headers.map(head => {
if (head.name === 'From') {
sendObject.replyTo = head.value
} else if (head.name === 'Subject') {
if (head.value.indexOf('Re:') >= 0) {
sendObject.subject = head.value
} else {
sendObject.subject = 'Re: ' + head.value
}
} else if (head.name === 'Message-Id') {
sendObject.inReplyTo = head.value // The last thread messageId is inserted into In-Reply-To tag
sendObject.reference.push(head.value) // All the messageId are appended as part of References tag
}
})
})
const email_lines = []
email_lines.push('References:' + sendObject.reference.join(' '))
email_lines.push('In-Reply-To:' + sendObject.inReplyTo)
email_lines.push('Subject: ' + sendObject.subject)
email_lines.push('To:' + sendObject.replyTo)
email_lines.push('')
email_lines.push(req.body.body)
const email = email_lines.join('\r\n').trim()
let base64EncodedEmail = new Buffer(email).toString('base64')
base64EncodedEmail = base64EncodedEmail.replace(/\+/g, '-').replace(/\//g, '_')
emailConfig.gmail.users.messages.send({
userId: 'me',
threadId: sendObject.threadId,
resource: {
raw: base64EncodedEmail
}
}, async (err) => {
if (err) {
console.log('The Threads API returned an error: ' + err)
}
})
When i login to gmail through browser, i can see 2 different emails instead of one thread.
You should put threadId inside of the resource.
const response = await this.gmail.users.messages.send({
auth: this.oAuth2Client,
userId: this.gmailAddress,
uploadType: 'multipart',
resource: {
threadId: email.threadId,
raw: raw
}
})
For more details, you can check my Gmail-APIs-wrapper here
I'm trying to collect the of returned values of two functions, send-mail and sendsms, into a variable(var ordermessage). It picks up the returned value from send-sms just fine.
I'm using the mailgun api for send-mail, and ordermessage just picks up 'undefined'. But send-mail keeps running.
I've tried `await mailgun.messages().send(...)`
I've tried `const myvar = await mailgun.messages().send(...)`
and also `let myvar = await mailgun.messages().send...`
Nada.
I tried using a function that had the api call as a callback. Still got undefined. The email and sms both get sent, but I need the reply from the email server. I'm using Mailgun trial so I need to return a response.
send-mail.js
var mailgun = require('mailgun-js')({apiKey: process.env.MAILGUN_API_KEY, domain: process.env.MAILGUN_DOMAIN});
var processresponse = "\n";
var data = {
from: 'Zigy Demo Store <admin_demo#zigy.com>',
to: email,
subject: 'You have placed an order.',
text: body
};
console.log("\n----------START EMAIL-------------\n");
mailgun.messages()
.send(data, function (error, body) {
console.log("\nFinally running MAILGUN. Return body is\n", body);
if (body == undefined || body == false) {
console.log("Got nothing from server.");
} else {
processresponse += body.message;
console.log("***********************Gotten reply from Mailgun server.*******************************\n", processresponse);
}
});
OrderController function
module.exports = {
neworder: async function(req, res) {
var sendemail = require('./send-mail');
var sendtext = require('./send-sms');
var orderdetails = 'New order created at '+ new Date() + '\nItem ---> Price'; //Message that will be sent to users.
var item;
var printcart = await Shoppingcart.findOne({
where: {
id: req.body.cart,
owner: req.body.user
}
}).populate('product');
var ordermessage = '';
for (items in printcart.product) {
item = printcart.product[items];
orderdetails += '\n' + item.name + ' ---> ' + item.price;
}
console.log(orderdetails);
//to get email addr and phone number
phone = req.body.phone;
var email = req.body.email;
var user = await User.findOne({id:printcart.owner});
ordermessage += await sendemail(email, orderdetails);
console.log("\nAfter email, the message is ", ordermessage);
ordermessage += await sendtext(phone, orderdetails);
console.log("\nAfter text, Printing order message to be returned to browser ", ordermessage);
console.log("Final message ", ordermessage);
res.send(ordermessage);
}
};
Terminal
----------START EMAIL-------------
Calling test function
After email, the message is
Finally running MAILGUN. Return body is
{ id:
'<20190222062410.1.FD7A4868FA0ADF5E#sandbox612cf746219c46ad93d5dc588f9341ff.mailgun.org>',
message: 'Queued. Thank you.' }
***********************Gotten reply from Mailgun server.*******************************
Queued. Thank you.
Checking list of verified numbers...
Found the phonenumber!
You will receive an SMS message with your order details soon.
After text, Printing order message to be returned to browser
You will receive an SMS message with your order details soon.
Final message
You will receive an SMS message with your order details soon.
SM9bc04208f9354834a153fb1ffd7dc8bb
Any help will be greatly appreciated.
Edit: I called res.write from inside send-mail.js and send-sms.js instead and got rid of the variable ordermessage.
This is a guess: I think the mailgun.messages().send(...) method doesn't return anything as it uses a classic callback. So you will always get undefined from it.
But you get the result from the body parameter in the callback. You could use Promisify to transform the callback into a promise style method.
const util = require('util');
const fs = require('fs');
const messages = mailgun.messages();
const sendPromisified = util.promisify(messages.send());
sendPromisified(data).then((body) => {
// Do something with `body`
}).catch((error) => {
// Handle mailgun error
});
// Async / await style
try {
const mailBody = await sendPromisified(data);
} catch (err) {
// handle mailgun error `err`
}
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)
});
}
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'.