not sure why nodemailer isnt working properly - node.js

Not sure why this isnt working properly. i think the configuration looks right but I keep getting this error :getaddrinfo ENOTFOUND smpt.mydomian.com
let transporter = nodemailer.createTransport({
host: "smtp.mydomain.com",
port: 465,
secure: true,
auth: {
user: "abc#mydomain.com",
pass: "password",
},
});
let mailOptions = {
from: email,
to: "abc#domail.com",
subject: `New Lead ${fullName}`,
text: newMail,
};
// step 3
transporter.sendMail(mailOptions, (err, data) => {
if (err) {
console.log("there is an error " + err);
} else {
console.log("mail sent successfully");
}
});
});

in my opinion its better to create a class for that just like this
class Mailer {
sendMail = async (emailAddress) => {
let transporter = nodemailer.createTransport({
service: "gmail",
auth: {
user: testUser,
pass: testPass,
},
});
const option = {
from: `${EMAIL_ADDRESS}`,
to: emailAddress,
subject: "test Subject",
text: "Test text",
};
await transporter.sendMail(option, (err, info) => {
if (!err) {
console.log(`Email sent Successfully ... !`.green.underline.bold);
return true;
} else {
console.log(
`We have problem while sendil Email ... !`.red.underline.bold
);
return false;
}
});
};
}
i hope this class help you

Related

response: '535-5.7.8 Username and Password not accepted. Learn more at\n'

My Node js code is sending proper email on localhost but in backend there showing email and password not valid ?
const nodemailer = require("nodemailer");
const sendEmail = async (subject, message, send_to, sent_from, reply_to) => {
// Create Email Transporter
const transporter = nodemailer.createTransport({
host: process.env.EMAIL_HOST,
port: 465,
secure: true,
auth: {
user: process.env.EMAIL_USER,
pass: process.env.EMAIL_PASS,
},
});
// Options for sending email
const options = {
from: sent_from,
to: send_to,
reply_to: reply_to,
subject: subject,
html: message,
};
// Check email sent successfully or not
transporter.sendMail(options, function (err, info) {
if (err) {
console.log(err);
} else {
console.log(info);
}
});
};
module.exports = sendEmail;

Nodemailer Error: Missing credentials for "PLAIN" - OR - Error Error: Mail command failed: 530-5.7.0 Authentication Required. Env variable issue

I am really struggling with Nodemailer using Gmail in my NodeJS backend application. I have tried both OAuth and 2 factor authentication but am getting the following errors:
Either
Error Error: Mail command failed: 530-5.7.0 Authentication Required.
OR
Nodemailer Error: Missing credentials for "PLAIN"
Nodemailer set up is as below with OAuth when I am receiving the Authentication required error:
import nodemailer from "nodemailer";
interface mailOptions {
from: string;
to: string;
subject: string;
html: string;
}
const transporter = nodemailer.createTransport({
host: "smtp.gmail.com",
service: "gmail",
port: "587",
secure: false,
auth: {
type: "OAuth2",
user: 'EMAIL',
pass: 'EMAIL PASSWORD',
clientId: 'CLIENTID',
clientSecret: 'CLIENT SECRET',
refreshToken: 'OAUTH REFRESH TOKEN',
},
});
transporter.verify((err, success) => {
err
? console.log(err)
: console.log(`=== Server is ready to take messages: ${success} ===`);
});
export const sendMail = (mailOptions: mailOptions) =>
transporter.sendMail(mailOptions, function (err, data) {
if (err) {
console.log("Error " + err);
} else {
console.log("Email sent successfully");
}
});
The Missing credentials for "PLAIN" error is set up as below using 2 factor authentication:
import nodemailer from "nodemailer";
interface mailOptions {
from: string;
to: string;
subject: string;
html: string;
}
const transporter = nodemailer.createTransport({
service: "gmail",
auth: {
user: 'EMAIL',
pass: '2 FACTOR GENERATED PASSWORD FOR THE APP',
},
});
transporter.verify((err, success) => {
err
? console.log(err)
: console.log(`=== Server is ready to take messages: ${success} ===`);
});
export const sendMail = (mailOptions: mailOptions) =>
transporter.sendMail(mailOptions, function (err, data) {
if (err) {
console.log("Error " + err);
} else {
console.log("Email sent successfully");
}
});
controller code is as such:
ForgotPassword: async (req: Request, res: Response) => {
try {
const user = await userSchema.findOne({ email: req.body.email });
const username = user?.username;
if (user) {
const secret = process.env.ACCESS_TOKEN + user.password;
const payload = {
email: user.email,
id: user._id,
};
const token = jwt.sign(payload, secret, { expiresIn: "15m" });
const link = `http://localhost:${process.env.PORT}/user/reset-password/${user._id}/${token}`;
// console.log(link, token);
// Add in logic for sending the link via email to user here
const mailOptions = {
from: 'EMAIL',
to: 'EMAIL',
subject: "Password Reset",
html: "HTML",
};
sendMail(mailOptions);
res.status(200).send("Password reset link has been sent to your email");
} else {
res.status(404).send("User not found!");
}
} catch (e: unknown) {}
},
Edit:
The issue appears to be with loading environment variables, I added the email and generated password for 2 step verification into my app and it works perfectly. How to I get this to work with env variables?
After posting the edit, I ended up thinking that maybe I need to enable dotenv in my service file for the nodemailer. This worked perfectly. The following is the code I now have.
import nodemailer from "nodemailer";
import * as dotenv from "dotenv";
dotenv.config();
interface mailOptions {
from: string;
to: string;
subject: string;
html: string;
}
const transporter = nodemailer.createTransport({
service: "gmail",
auth: {
user: 'EMAIL',
pass: '2 FACTOR GENERATED PASSWORD FOR THE APP',
},
});
transporter.verify((err, success) => {
err
? console.log(err)
: console.log(`=== Server is ready to take messages: ${success} ===`);
});
export const sendMail = (mailOptions: mailOptions) =>
transporter.sendMail(mailOptions, function (err, data) {
if (err) {
console.log("Error " + err);
} else {
console.log("Email sent successfully");
}
});

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

nodemailer sendEmail doesn't wait in Node.js

When I make a request to my endpoint I need to get a successful response only if the email is sent! otherwise, it should throw an error:
myendpoint.js
router.post("/", upload.none(), async (req, res) => {
try {
let body = JSON.parse(req.body.contact);
await getDb("messages").insertOne({
name: body.name,
email: body.email,
phone: body.phone,
subject: body.subject,
message: body.message,
});
await sendEmail(body);
res.send(
JSON.stringify({
success: true,
msg: "Message has been sent successfully",
})
);
} catch (err) {
res.send(JSON.stringify({ success: false, msg: err }));
}
});
sendEmail.js
const sendEmail = async function (props) {
const transporter = nodemailer.createTransport({
service: process.env.EMAIL_SERVICE,
host: process.env.EMAIL_HOST,
auth: {
user: process.env.EMAIL_FROM,
pass: process.env.EMAIL_PASS,
},
});
const mailOptions = {
from: process.env.EMAIL_FROM,
to: process.env.EMAIL_TO,
name: props.name,
email: props.email,
phone: props.phone,
subject: props.subject,
text: props.message,
};
transporter.sendMail(mailOptions, function (error, info) {
if (error) {
throw new Error("Message did Not send!");
}
});
};
the problem is before "await sendEmail(body);" ends and i get the error, i get the "Message has been sent successfully" and then server crashes!
what am i missing?
Check document function sendMail from nodemailer at here
If callback argument is not set then the method returns a Promise object. Nodemailer itself does not use Promises internally but it wraps the return into a Promise for convenience.
const sendEmail = async function (props) {
const transporter = nodemailer.createTransport({
service: process.env.EMAIL_SERVICE,
host: process.env.EMAIL_HOST,
auth: {
user: process.env.EMAIL_FROM,
pass: process.env.EMAIL_PASS,
},
});
const mailOptions = {
from: process.env.EMAIL_FROM,
to: process.env.EMAIL_TO,
name: props.name,
email: props.email,
phone: props.phone,
subject: props.subject,
text: props.message,
};
// remove callback and function sendMail will return a Promise
return transporter.sendMail(mailOptions);
};
Hello you can change your Transporter sendMail to :
return await transporter.sendMail(mailOptions);
Or You can Use Promise.
const handler = async ({ subject, name, body, contact }) => {
const transporter = nodemailer.createTransport({
service: "zoho",
// Disable MFA here to prevent authentication failed: https://accounts.zoho.com/home#multiTFA/modes
// ********************* OR *****************
// set up Application-Specific Passwords here: https://accounts.zoho.com/home#security/device_logins
auth: { user: process.env.NEXT_PUBLIC_EMAIL_ADDRESS, pass: process.env.NEXT_PUBLIC_EMAIL_PASSWORD },
});
return transporter
.sendMail(mailOptions({ subject, name, body, contact }))
.then((info) => {
if (process.env.NODE_ENV !== "production") console.log("Email sent: " + info.response);
return true;
})
.catch((err) => {
if (process.env.NODE_ENV !== "production") console.log("error sending mail", err);
return false;
});
};

Resources