Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sending an eMail with Lambda, NodeJs and Nodemailer doesn't work

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:

enter image description here

like image 580
Liz Zarate Avatar asked Feb 12 '26 06:02

Liz Zarate


2 Answers

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,

like image 106
Neo Liu Avatar answered Feb 13 '26 19:02

Neo Liu


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

like image 36
Emmanuel N K Avatar answered Feb 13 '26 21:02

Emmanuel N K