joshk132
joshk132

Reputation: 1113

Unable to send email using SES/Lambda but code works on a container

I have a lambda function that takes in a bunch of info and does some stuff then is to send an email using SES. I currently have the code that sends the email working in a container but I have decided that I want to use AWS step functions so am converting it to Lambda functions. In theory, there should be no major differences yet I can't get emails to send.

Requiring the function which sends the email:

const sendEmail = require('./utils/sendEmail');

The first line of the lambda function/ declaring the function:

module.exports.sendFirstAlert = async (event, context, callback) => {

Calling the sendEmail function:

await sendEmail(""Josh's Email" ${fromEmail}", toEmail, 'Alert!', message); Note for this the ` was swapped for " just for SO formatting but is working fine in the code

The utils/sendEmail:

const nodemailer = require('nodemailer');
const ses = require('nodemailer-ses-transport');
const aws = require('aws-sdk');

const accessKeyId = process.env.accessKeyId;
const secretAccessKey = process.env.secretAccessKey;

const transport = nodemailer.createTransport(
    ses({
        accessKeyId: accessKeyId,
        secretAccessKey: secretAccessKey
    })
);

module.exports = function sendEmail(from, to, subject, message) {
    const mailOptions = {
        from,
        to,
        subject,
        html: message
    };
    transport.sendMail(mailOptions, (error, info) => {
        console.log('1');
        if (error) {
            console.log(error);
        }
        if (info) {
            console.log(info);
        }
        console.log('2');
    });
    console.log('3');
};

So inside the send email function I have those 3 console.log statements. Only the third one gets called. The first/second is not being called. This exact code (minus the console.log) is working perfectly fine in a container.

I am using the node serverless framework to create my step/lambda function(s). I have set AWS SES permissions wide open for this (testing/resolving this issue, not prod).

The ENV variables I am trying to call is working perfectly fine. The function is getting all of the required parts (from, to subject, message) correctly and in the correct formats.

I also am using the same API keys as in the container so should be fine to send emails considering that the email I am sending to is the same in the lambda function as in the container.

Any ideas what might be wrong?

Upvotes: 1

Views: 1370

Answers (1)

thomasmichaelwallace
thomasmichaelwallace

Reputation: 8482

From what you've said, the problem looks like your sendMail function is not await able (i.e. it does not return a promise, or await transport.sendMail).

This is why the two console logs in the callback do not happen, because the lambda function finishes executing before the callback is called.

You should check nodemailer's documentation here (https://nodemailer.com/about/#example) for more information, but it looks like the following code should work fine:

module.exports = async function sendEmail(from, to, subject, message) {
  const mailOptions = { from, to, subject, html: message };
  try { 
    const info = await transport.sendMail(mailOptions);
    console.log(info);
    return true;
  } catch (error) {
    console.log(error);
    return false;
  }
};

n.b. I guess the reason it works locally is because you container isn't precisely the same as the remote lambda environment. In the remote lambda environment once your handler returns all code execution gets frozen, and so your callback does not have time to happen. But your local container continues to run in the background, which means your callbacks run even though your handler has finished.

Upvotes: 2

Related Questions