使用 Lambda、NodeJs 和 Nodemailer 发送电子邮件不起作用

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

我正在尝试使用之前经过 SES 身份验证的帐户从 Lambda 发送电子邮件; node.js 使用 Nodemailer。没有错误,但它也不发送。

这是我正在使用的流程:

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: 'test@email.com',
        to: 'test@email.com',
        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');    
};

这些是日志回答结果:

您的 Lambda 超时。查看 Cloudwatch 日志中的最后一条消息。您将 lambda 超时设置为 6 秒,我想这不足以让 lambda 发送请求(通过 transporter.sendMail)并获得响应。尝试增加 lambda 时间。大约 30 秒?

我为我设计的新 lambda 设置超时的方法是 运行 它们多次,直到我得到一个平均完成时间。然后我在那个时间上加 20 秒。

另外,transporter.sendMail是异步函数。这意味着 console.log('funcion finalizada') 可能会 运行 在您的函数完成之前(但您的函数实际上尚未完成)。

阅读有关异步 javascript 和回调的更多信息:https://medium.com/codebuddies/getting-to-know-asynchronous-javascript-callbacks-promises-and-async-await-17e0673281ee

此外,如果您想以同步方式编写异步代码,请使用 async/await

以防有人遇到 'nodemailer not working in Lambda' 问题:

您 post 中的代码在本地服务器中有效,因为:

在您的本地环境中,有一个 运行 服务器来调度所有调用堆栈,包括同步和异步任务。一旦你在本地环境中调用 transporter.sendMail() ,它将被放置到当前调用堆栈的末尾,并将一直执行到你的调用堆栈中的最后一次执行完成。在您的情况下,异步函数 transporter.sendMail() 将安排在 console.log('funcion finalizada');

之后调用

为什么它在 Lambda 中不起作用:

每次调用lambda函数时,它都会执行代码,执行完后kill进程,也就是说不能调用异步transporter.sendMail(),因为console.log('funcion finalizada'); lambda 函数进程将终止,并在执行之前清除计划的异步任务。

要使其在 Lambda 中运行:

1) 将函数更改为 async 函数

module.exports.eviarCorreoPrueba = async (event, context) => { ... }

2) 在继续

之前等待您的transporter.sendMail()被调用
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) 让你的 nodemailer emailbot 工作的最后一件事: 您需要转 Less secure app access on and Allow access to your Google Account 因为您只是使用用户名和密码来连接您的 Gmail 帐户。

*注意:如果您想使用更安全的方式连接您的Gmail(例如OAuth 2.0),您可以参考我的文章:Create a Free Serverless Contact Form Using Gmail, Nodemailer, and AWS Lambda

希望这对遇到此问题的任何人有所帮助。

干杯,