I'm trying to send an email from Lambda with a previously SES authenticated account; with node.js using Nodemailer. There is no error, but it doesn't send neither.
This is the process I'm using for:
module.exports.eviarCorreoPrueba = (event, context, callback) => {
context.callbackWaitsForEmptyEventLoop = false;
console.log('inicia envio de correos');
var transporter = nodemailer.createTransport({
//pool: true,
host: 'email-smtp.us-east-1.amazonaws.com',
port: 465,
secure: true,
auth: {
user: 'user',
pass: 'pass'
}
});
console.log('se crea transporte ');
var mailOptions = {
from: '[email protected]',
to: '[email protected]',
subject: 'Prueba Lambda',
html: 'hello World'
};
console.log('se asignan las opciones de correo');
console.log('inicia envio de correo');
transporter.sendMail(mailOptions, function (error, info) {
if (error) {
callback(null, {
statusCode: 200,
body: JSON.stringify({
input: 'not send'
})
})
} else {
console.log('Email sent');
}
});
console.log('funcion finalizada');
};
And these are the log answer results:

Just in case anyone gets stuck with 'nodemailer not working in Lambda' issue:
The code in your post works in local server because:
In your local environment, there is a running server to schedule all call stacks including synchronous and asynchronous tasks. Once you called transporter.sendMail() in local environment, it will be placed to the end of the current call stack and will be executed until the last execution in your call stack finished. In your case, the asynchronous function transporter.sendMail() will be scheduled to be called after console.log('funcion finalizada');
Why it is not working in Lambda:
Every time when you call the lambda function, it will execute the code and then kill the process after the execution finished, which means it won't be able to call the asynchronous transporter.sendMail() because after console.log('funcion finalizada'); the lambda function process will be terminated and the scheduled asynchronous tasks will be cleared before get executed.
To make it work in Lambda:
1) Change your function to an async function
module.exports.eviarCorreoPrueba = async (event, context) => { ... }
2) await your transporter.sendMail() to be called before continue
const response = await new Promise((rsv, rjt) => {
transporter.sendMail(mailOptions, function (error, info) {
if (error) {
return rjt(error)
}
rsv('Email sent');
});
});
return {
statusCode: 200,
body: JSON.stringify({
input: response
})
}
3) Last thing to make your nodemailer emailbot work: You need to turn Less secure app access on and Allow access to your Google Account because you are simply using username and password to connect your Gmail account.
*Note: If you want to use securer method to connect your Gmail (eg. OAuth 2.0), you can refer to my article: Create a Free Serverless Contact Form Using Gmail, Nodemailer, and AWS Lambda
Hope this helps anyone who gets stuck with this issue.
Cheers,
Your Lambda is timing out. See the last message in your Cloudwatch logs. You set your lambda timeout to 6 seconds I suppose which is not enough time for the lambda to send out the request (via transporter.sendMail) and get the response. Try increasing the lambda time. To about 30 seconds maybe?
The way I set timeouts for new lambdas I design is to run them several times till I get an average completion time. Then I add 20 seconds to that time.
Also, transporter.sendMail is asynchronous function. This means console.log('funcion finalizada') will probably run before your function completes (yet your function hasn't actually completed).
Read more on asynchronous javascript and callbacks: https://medium.com/codebuddies/getting-to-know-asynchronous-javascript-callbacks-promises-and-async-await-17e0673281ee
Also, If you want to write asynchronous code in a synchronous looking way use async/await
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