Nodemailer is not working in live but locally working fine - node.js

function sendEmail(num, email, customerName) {
var readHTMLFile = function (path, callback) {
fs.readFile(path, { encoding: 'utf-8' }, function (err, html) {
if (err) {
throw err;
callback(err);
}
else {
callback(null, html);
}
});
};
let transporter = nodemailer.createTransport({
host: "smtp.gmail.com",
secure: true,
port: 465,
auth: {
user:process.env.USEREMAIL,
pass:process.env.USERPASS
},
});
readHTMLFile(__dirname + '/views/layouts/first.html', function (err, html) {
var template = handlebars.compile(html);
var replacements = {
otp: `${num}`,
customerName: `${customerName}`
};
var htmlToSend = template(replacements);
var mailOptions = {
from: process.env.USEREMAIL,
to: email,
subject: "Hello ✔",
html: htmlToSend
};
transporter.sendMail(mailOptions, function (error, response) {
if (error) {
console.log(error);
} else {
console.log("Email sent");
}
});
});
}
All this is working fine with my localhost:8000 but after I upload(hosted) with my cyclic.sh account, my app works and getting success message, but did not get any mail with my box. sendEmail function not working in live but working locally. what is issues of the sendEmail function

I had a same problem and fixed it by wrapping sendmail with a promise
new Promise((resolve, reject) => {
transporter.sendMail(mailOptions, function (error, response) {
if (error) {
reject(error)
} else {
resolve("email sent")
}
});
})

Related

Why Nodemailer is working locally but not in Production?

When I try to send an email locally it works but in production, in the network tab I get everything right just email doesn't want to send and I don't get any error.
try {
const { name, email, message } = req.body;
const transporter = nodemailer.createTransport({
port: 465,
host: "smtp.gmail.com",
auth: {
user: process.env.NEXT_PUBLIC_GMAIL_EMAIL,
pass: process.env.NEXT_PUBLIC_GMAIL_PASSWORD,
},
secure: true,
});
const mailData = {
from: process.env.NEXT_PUBLIC_GMAIL_EMAIL,
to: process.env.NEXT_PUBLIC_EMAIL_WHICH_RECIEVES_CONTACT_INFO,
subject: `Message From ${email}`,
text: message,
};
transporter.sendMail(mailData, function (err, info) {
if (err) console.log(err);
else console.log(info);
});
res.status(200).json({ message: "Email sent" });
} catch (error: any) {
res.status(500).json({ message: error.message });
}
I kind of had a similar issue with nodemailer and Next.js, try to wrap the transporter in a Promise, hopefully it works for you too:
await new Promise((resolve, reject) => {
transporter.sendMail(mailData, (err, info) => {
if (err) {
console.error(err);
reject(err);
} else {
resolve(info);
}
});
});

Nodemailer not working when deploying to Heroku

I am using nodemailer to send email in my server using express. Everything worked perfectly in the localhost but when I deploy it on Heroku, it does not work anymore, look like it not support nodemailer on Heroku (that is what I have researched). This is my code, would you please help me out to deal with it. Thank you so much and have a good day
This is sending single mail
exports.send_mail = (req, res, next) => {
var {subjectTo, mailList, content} = req.body;
var {attachURL} = req;
var transporter = nodemailer.createTransport({
service: 'gmail',
secure: false,
port: 465,
auth: {
user: process.env.EMAIL,
pass: process.env.PASSWORD,
},
});
var mailOptions = {
from: 'sale.shopeeholic#gmail.com',
to: mailList,
cc: mailList,
subject: subjectTo,
text: `${content} \n Attached files: ${attachURL}`,
};
transporter.sendMail(mailOptions, (err, info) => {
if (err) {
console.log(err);
return res.status(400).json({err});
} else {
return res.status(200).json({message: `Mail sent to ${mailList}`});
}
});
};
This is sending merge mail/multiple mail
exports.merge_mail = (req, res, next) => {
console.log('merge mail begin');
const mailOptionList = req.body;
// {mails, mailContent, mailTitle}
var counter = 0;
var transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: process.env.EMAIL,
pass: process.env.PASSWORD,
},
});
for (var i = 0; i < mailOptionList.length; i++) {
var mailOptions = {
from: 'sale.shopeeholic#gmail.com',
to: mailOptionList[i].mails.join(','),
cc: mailOptionList[i].mails.join(','),
subject: mailOptionList[i].mailTitle,
text: mailOptionList[i].mailContent,
};
transporter.sendMail(mailOptions, (err, info) => {
if (err) {
console.log(err);
return res
.status(400)
.json({err, message: `trouble in sending mail at index ${i}`});
} else {
console.log(`mail sent to ${JSON.stringify(mailOptionList[i].mails)}`);
counter++;
}
});
console.log(`mail sent to ${JSON.stringify(mailOptionList[i].mails)}`);
counter++;
console.log(counter);
}
if (counter === mailOptionList.length) {
return res.status(200).json({message: 'mail sent all'});
}
Probably process.env.EMAIL and process.env.PASSWORD are undefined. You have to set env variables in Heroku. Here's how:
https://devcenter.heroku.com/articles/config-vars

ERR_HTTP_HEADERS_SENT in Nodejs Server (AWS)

I'm asking again with this code provided Please Help Thank you. I am calling this API with Firebase function from Android using okhttp3, here the code below. I already subscribed to a plan in firebase to call external API
Firebase Cloud Function Code
exports.CustomerProfile = functions.https.onRequest((req, res) => {
const options = {
method: "POST",
uri: "http://3.xxxx.xx.xx2:3000/api/customers/profile",
formData: {
session_token: req.body.session_token
},
headers: {
"content-type": "application/x-www-form-urlencoded",
"x-auth-token": "xxxxxxE"
},
resolveWithFullResponse: true,
json: true,
simple: false
};
rp(options)
.then(function(response) {
res.send(response.body);
})
.catch(function(err) {
res.send(err);
});
});
API CODE
router.post("/profile", async (req, res) =>{
const customers = new Customers();
var data = req.body;
var token = req.body.session_token;
customers.findBySessionToken(token, (err, result) => {
if (!err) {
if(result[0].provider === 'gmail'){
var gmail = result[0].access;
customers.findByGmail(gmail, (err, result) => {
res.status(200).send(result);
});
}else if(result[0].provider === 'facebook') {
var facebook = result[0].access;
customers.findByFb(facebook, (err, result) => {
res.status(200).send(result);
});
}else if(result[0].provider === 'mobile') {
var mobile = result[0].access;
customers.findByMobile(mobile, (err, result) => {
res.status(200).send(result);
});
}
} else {
if (err.code === "ER_SIGNAL_EXCEPTION") {
res.status(400).send([{ message: err.sqlMessage }]);
} else {
res.status(400).send(err);
}
}
});
});
this means that you have already sent a response res.send... somewhere else , you cant do more than one response for a request.

Node.js callback from one controller method to other

I have created a emailHelper in my project for sending emails.
I wan to get a callback once the email sent successfully
//emailHelper.js
module.exports = {
sendMail: (options) => {
var transporter = nodemailer.createTransport({
service: 'SendGrid',
auth: {
user: keys.sendGridUsername,
pass: keys.sendGridPassword
}
});
const mailOptions = {
from: options.from,
to: options.to,
subject: options.subject,
html: options.content
};
transporter.sendMail(mailOptions, (err, info) => {
if(err) {
console.log(err);
return false;
}
else {
console.log('mail sent');
return true;
}
});
}
}
I want to save data to database only if the email is sent
const { sendMail } = require('../helpers/emailHelper');
mail: (req, res, next) => {
const emailOptions = {
from: 'from#email.com',
to: 'to#email.com',
subject: 'subject',
content: 'text'
};
const mailResetLink = sendMail(emailOptions);
if(mailResetLink) {
//success save data
} else {
//failure trrow error
}
}
thank you
Wrap your sendMail in promise and return it:
return new Promise((resolve, reject) => {
transporter.sendMail(mailOptions, (err, info) => {
if(err) {
console.log(err);
reject();
}
else {
console.log('mail sent');
resolve();
}
});
});
Than you would be able to do this:
sendMail(emailOptions).then(() => {
// success save data
}).catch(() => {
// failure trrow error
});
Using async/await you would need to change promise to return some identifier in any case, boolean in this case, and than tweak mail function:
return new Promise((resolve) => {
transporter.sendMail(mailOptions, (err, info) => {
if(err) {
console.log(err);
resolve(false);
}
else {
console.log('mail sent');
resolve(true);
}
});
});
mail: async (req, res, next) => {
const emailOptions = {
from: 'from#email.com',
to: 'to#email.com',
subject: 'subject',
content: 'text'
};
const mailResetLink = await sendMail(emailOptions);
if(mailResetLink) {
//success save data
} else {
//failure trrow error
}
}

Nodemailer returns nothing on sending mail

I'm using nodemailer to try and get an admin to send an email, but the code I have so far returns no info or error.
The promise returns with no issue, but it's always empty.
Trying to use transporter.verify returns no info or error as well.
There are no issues with finding the admin in question.
var deferred = Q.defer();
Admin.findOne({username: 'admin'}, function(err, res)
{
if(err) deferred.resolve(err);
if(res)
{
var admin = _.omit(res.toJSON(), 'password');
var transporter = nodemailer.createTransport("SMTP", {
service: 'gmail',
auth: {
user: 'sender#gmail.com',
pass: "password_here"
}
});
var mailOptions = {
from: 'sender#gmail.com',
to: 'destination#hotmail.com',
subject: 'TEST',
text: 'TEST',
html: '<p> TEST EMAIL </p>'
};
transporter.sendMail(mailOptions, function (err, info) {
if (err) deferred.reject(err);
if(info){
deferred.resolve(info);
} else {
deferred.resolve();
}
});
} else {
deferred.reject("Cannot find admin");
}
});
return deferred.promise;
Please edit the code, it looks like you have an error on mongo with 'Admin.findOne'
if(err) deferred.resolve(err);
to
if(err) deferred.reject(err);

Resources