I'm using AWSs API Gateway along with a Lambda function for an API.
In my Lambda function, I have the following (simplified) code however I'm finding that the await sendEmail
isn't being respected, instead, it keeps returning undefined
exports.handler = async (event) => {
let resultOfE = await sendEmail("[email protected]", "[email protected]")
console.log(resultOfE)
}
async function sendEmail(oldEmail, newEmail) {
var nodemailer = require('nodemailer');
var transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: 'xxx',
pass: 'xxx'
}
});
transporter.sendMail(mailOptions, function (error, info) {
if (error) {
console.log(error);
return false
} else {
console.log('Email sent: ' + info.response);
return true
}
});
}
Lambda is a compute service in AWS. By lambda we can run serverless applications. For further details go to this link. Using async/await we can write asynchronous function and simplify promise chain. Await keyword is valid only in an async function. ECMAScript 2017 brought this feature which is syntactic sugar on top of promises.
However, the large caveat is that async (along with many other wonderful ES2016 and ES2017 features) isn’t supported on AWS Lambda, according to node.green: No async/await? : ( (
If we send a HTTP request and that request is not fully sent over the network, if we return from the Lambda function, AWS will immediately suspend our Lambda container AND the partially sent request will be suspended as well.
There are many other excellent ways to avoid waiting and blocking in Lambda functions such as using Step functions, SQS queues and directly invoking Lambda functions as Events without waiting.
since you await sendMail
, this requires sendMail
to return a Promise
- your code uses callbacks to handle the asynchrony, so
async sendMail
doesn't do anything (except make sendMail
return a Promise that IMMEDIATELY resolves to undefined
async
since it won't need await
the code below should do it -
var nodemailer = require('nodemailer'); // don't put require inside a function!!
exports.handler = async (event) => {
const resultOfE = await sendEmail("[email protected]", "[email protected]")
console.log(resultOfE)
}
//doesn't need async, since there will be no await
function sendEmail(oldEmail, newEmail) {
return new Promise((resolve, reject) => { // note, reject is redundant since "error" is indicated by a false result, but included for completeness
const transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: 'xxx',
pass: 'xxx'
}
});
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
console.log(error);
resolve(false);
} else {
console.log('Email sent: ' + info.response);
resolve(true);
}
});
// without the debugging console.logs, the above can be just
// transporter.sendMail(mailOptions, error => resolve(!error));
});
}
as per comment by @ThalesMinussi,
transporter.sendMail
returns a Promise if you do not provide a callback function, so you could write: (sendEmail is now async)
async function sendEmail(oldEmail, newEmail) {
const transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: 'xxx',
pass: 'xxx'
}
});
try {
const info = await transporter.sendMail(mailOptions);
console.log('Email sent: ' + info.response);
return true;
}
} catch (error) {
console.log(error);
return false;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With