Send confirmation response after Nodemailer sendMail function done? - node.js

I need to return some response when I send a email through Nodemailer and I have this function:
async function dispatchEmail(email) {
const transporter = nodemailer.createTransport({
service: `${nconf.get('EMAIL_SMTP_SERVICE')}`,
auth: {
user: nconf.get('EMAIL_ACCOUNT'),
pass: nconf.get('EMAIL_PASSWORD'),
},
});
const mailOptions = {
from: `"Shagrat Team "${nconf.get('EMAIL_ACCOUNT')}`,
to: email,
subject: 'Hi from Shagrat Team !',
text: '',
html: '',
};
const success = await transporter.sendMail(mailOptions, async (error, sent) => {
if (error) {
return error;
}
return {some_response};
});
return success;
}
Where I need to send{some_response} with some value either true, false or something else, but I got 'undefined' value inside the same function or calling it externally:
const success = await dispatchEmail(emailConsumed);
What value can I return and catch it? because I need to test this function.

An exit is to return the transporter.sendmail () itself, which is a promise, in the return contera the data of the sending or the error, it is good to use a trycatch for other errors.
async function dispatchEmail(email) {
const transporter = nodemailer.createTransport({
service: `${nconf.get('EMAIL_SMTP_SERVICE')}`,
auth: {
user: nconf.get('EMAIL_ACCOUNT'),
pass: nconf.get('EMAIL_PASSWORD'),
},
});
const mailOptions = {
from: `"Shagrat Team "${nconf.get('EMAIL_ACCOUNT')}`,
to: email,
subject: 'Hi from Shagrat Team !',
text: '',
html: '',
};
return transporter.sendMail(mailOptions)
}
Another option is to use the nodemailer-promise module.
const success = await dispatchEmail(emailConsumed);
Result:
console.log(sucess);
{ envelope:
{ from: 'example#example.com',
to: [ 'example2#example.com' ] },
messageId:'01000167a4caf346-4ca62618-468f-4595-a117-8a3560703911' }

Related

not sure why nodemailer isnt working properly

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

Nodemailer not sending email in lambda function

I am developing an AWS lambda function using node.js 14.x for my runtime.
I create a nodemailer layer and upload it to my lambda function. I am trying to test my function and just return a simple console log but I don't see the console log anywhere including my cloud watch logs.
exports.handler = async (event) => {
// TODO implement
const nodemailer = require("nodemailer");
const transporter = nodemailer.createTransport({
service: "gmail",
auth: {
// user: process.env.USER_NAME,
// pass: process.env.EMAIL_PASS,
user: "********",
pass: "********",
},
});
const mailOptions = {
from: "taxs#gmail.com",
to: "trdmon#gmail.com",
subject: "subject",
text: "message",
};
transporter.sendMail(mailOptions, function (error, info) {
console.log('hit')
if (error) {
console.log(error);
} else {
console.log("Email sent: " + info.response);
}
});
const response = {
statusCode: 200,
body: JSON.stringify('Hello from Lambda!'),
};
return response;
};
If the transporter.sendEmail function were running I should see the console log. Any ideas why my function isn't running?

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;
});
};

How to make nodemailer reusable in multiple module?

I have implemented nodemailer after the user registration, in the following way:
let transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: process.env.EMAIL_USERNAME,
pass: process.env.EMAIL_PASSWORD
}
});
let mailOptions = {
from: process.env.EMAIL_USERNAME,
to: user.email,
subject: 'Verify your account',
text: 'Click here for verify your account'
};
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
return console.log(error);
}
});
I don't like much this code because if I need to send an email in another module, I need to rewrite all the stuff above.
Since I'm new to NodeJS, I would like to know if I can remove this code redundancy make something like a utility or maybe an helper class. The goal is import the wrapper class and call a simple function to send the email.
Which is the best way to handle that?
I refactored your code to look like below and then save it as mail.js
let transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: process.env.EMAIL_USERNAME,
pass: process.env.EMAIL_PASSWORD
}
});
let sendMail = (mailOptions)=>{
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
return console.log(error);
}
});
};
module.exports = sendMail;
in Your other modules, say activation.js
var mailer = require('./mail.js');
mailer({
from: process.env.EMAIL_USERNAME,
to: user.email,
subject: 'Verify your account',
text: 'Click here for verify your account'
};);
you can use module.exports as follow :
create common service mail.js and write your mail sent code here
mails.js
module.exports = function (){
// mail sent code
}
require mail.js where you write mail sent code in other service and call mail sent function
otherService.js
var mail = require('mail.js') // require mail sent in other service where you want to send mail
mail.sent() // call function of mail.js
I have created a class for this:
import NodeMailer from 'nodemailer'
import emailConfig from '../../config/mail' // read email credentials from your config
class EmailSender {
transport
constructor() {
this.transport = NodeMailer.createTransport({
host: emailConfig.MAIL_HOST,
port: emailConfig.MAIL_PORT,
auth: {
user: emailConfig.MAIL_USERNAME,
pass: emailConfig.MAIL_PASSWORD,
},
})
}
async sendMessage(to, subject, text, html) {
let mailOptions = {
from: emailConfig.MAIL_FROM_ADDRESS,
to,
subject,
text,
html,
}
await this.transport.sendMail(mailOptions)
}
}
export default new EmailSender()
Now you can implement it in your any routes:
router.get('/email', async (req, res) => {
try {
await EmailSender.sendMessage(
'bijaya#bijaya.com',
'Hello world',
'test',
'<h1>Test</h1>'
)
return res.status(200).send('Successfully sent email.')
} catch (exception) {
return res.status(500).send(exception.message)
}
})

Unable to send mail in node getting error as UnhandledPromiseRejectionWarning

Error while send mail:
(node:11928) UnhandledPromiseRejectionWarning: Error: Invalid login: 535 Authentication Failed
I tried nodemailer:
//library.js
const nodemailer = require("nodemailer");
module.exports
= {
transport:function(){
let transporter = nodemailer.createTransport({
host: "smtp.***.email",
port: 587,
secure: false,
auth: {
user: ****,
pass: ****
}
});
return transporter;
}
//controller.js
exports.sendemail = (require,res) => {
let mailOptions =
{
from: '"Fred Foo 👻" <foo#example.com>',
to: "baz#example.com",
subject: "Hello ✔",
text: "Hello world?",
html: "<b>Hello world?</b>"
};
transporter = transport.transporter();
let info = transporter.sendMail(mailOptions)
console.log("Message sent: %s", info.messageId);
}
Message sent:
b658f8ca-6296-ccf4-8306-87d57a0b4321#example.com
use same email at transporter and from on mail-options.
//library.js
const nodemailer = require("nodemailer");
module.exports = {
transport:function(){
let transporter = nodemailer.createTransport(
{
host: "smtp.***.email",
port: 587,
secure: false,
auth: {
user: 'foo#example.com',
pass: ****
}
});
return transporter; }}
//controller.js
exports.sendemail = (require,res) => {
let mailOptions =
{
from: '"Fred Foo 👻" <foo#example.com>',
to: "baz#example.com",
subject: "Hello ✔",
text: "Hello world?",
html: "<b>Hello world?</b>"
};
transporter = transport.transporter();
transporter.sendMail(mailOptions).then((info) =>
{
console.log(info);
return true;
}.catch(err =>
{
console.log("Error:", err);
return false;
});}
Sending a mail is asynchronous process. The warning means that there's rejected promise that wasn't chained. A example from the documentation was pasted the wrong way, await was omitted. sendMail returns a promise that needs to be chained:
transporter.sendMail(mailOptions)
.then(info => {
// success response
})
.catch(err => {
// error response
});

Resources