Nodemailer AWS SES not working in production

Is it possible to use Nodemailer AWS SES with netlify (built on Remix)? I’ve tried setting it up in a variety of flavors but nothing seems to take when it’s deployed to production. Currently using a netlify function (/netlify/functions folder) and everything looks like its going through and no errors are kicking back. Starting to believe that it’s just not possible so any help would be greatly appreciated.

ENV VARS for netlify since the default keys are reserved in netlify

SHARED_AWS_ACCESS_KEY_ID = “XXXXXXXXXXXXXXX”
SHARED_AWS_SECRET_ACCESS_KEY = “XXXXXXXXXXXXXXXXXXXXXXXXXXX”

sendEmail.js

const nodemailer = require('nodemailer');

// import { Handler, HandlerEvent, HandlerContext } from "@netlify/functions";

const { defaultProvider } =  require('@aws-sdk/credential-provider-node');
const { redirect } =  require('@remix-run/node');
const { SES, SendRawEmailCommand } =  require('@aws-sdk/client-ses');

const AWS_ACCESS_KEY_ID = process.env.SHARED_AWS_ACCESS_KEY_ID;
const AWS_SECRET_ACCESS_KEY = process.env.SHARED_AWS_SECRET_ACCESS_KEY;

exports.handler = async function (event, context) {
    console.log('send email');
  const env = process.env.NODE_ENV;
  const baseURL = env === 'development' ? 'http://localhost:3000' : 'https://fantastic-gelato-83d416.netlify.app';

  const email = event.queryStringParameters.userEmail;
  const token = event.queryStringParameters.token;
 
  const ses = new SES({
    apiVersion: "2010-12-01",
    region: "us-west-2",
    port: 587,
    defaultProvider,
    debug: true,
    credentials: {
      accessKeyId: AWS_ACCESS_KEY_ID,
      secretAccessKey: AWS_SECRET_ACCESS_KEY
    }
  });
  console.log(ses)
  const transporter = nodemailer.createTransport({
    SES: { 
      ses:ses, 
      aws: { SendRawEmailCommand } },
      aws_access_key_id: AWS_ACCESS_KEY_ID,
      aws_secret_access_key: AWS_SECRET_ACCESS_KEY,
  })
  try {
    console.log('sending email to:',email);
    // send some mail
    transporter.sendMail(
      {
        from: "[removedemail@domain.com]",
        to: email,
        subject: "Message",
        html: `<style>div, h2, p a {display:inline-block;} a:link, a:visited {color:#003CFF;} .reset-password:link, .reset-password:visited{color:#ffffff!important;}</style>
        <div style="width: calc(100% - 30px);background-color:#f6f6f6;margin:60px auto;padding: 90px 15px;">
          <div style="width: calc(100% - 60px); max-width: 500px;background-color:#ffffff;margin:60px auto;padding:30px;text-align:center;">
          <h2 style="margin-bottom: 30px;margin-top: 0px;color:#003CFF;width:100%;text-align:center;">Reset Password</h2>
          <p style="padding: 0px;width: 100%; max-width: 450px; margin-bottom: 30px;margin-top: 0px;">Use the link below to reset your password. If you didn't send this request please contact <a href="mailto:webmaster@altny.com">webmaster@altny.com</a></p>
          <a class="reset-password" href="${baseURL}/resetpassword?token=${token}" style="background-color:#003CFF;color:#FFFFFFimportant;text-decoration:none;padding:15px 20px;border-radius:10px">Reset Password</a>
        </div>`,
        // ses: {
        //   // optional extra arguments for SendRawEmail
        //   // Tags: [
        //   //   {
        //   //     Name: "tag_name",
        //   //     Value: "tag_value",
        //   //   },
        //   // ],
        // },
      },
      (err, info) => {
        if (err) {
          console.log('Error sending email:', err);
        } else {
          console.log('Email sent:', info);
        }
      }
    );
  } catch(error) {
    throw new Error(error);
  }
  
  return {
    statusCode: 200,
    body: JSON.stringify('success email req received'),
  }
};

answering my own question after digging around and going to leave this up in case anyone finds this helpful. Basically followed the answer in this post TMTP is not working properly when deployed to netlify and the key was to await the sendmail function and the transporter.sendmail({…}) function. Also stripped out a lot of what’s above (remove the try catch block) and remove the callback (err, info) => {} function.

Hi @Jared_Pereira i’m glad you found a solution to your problem. thanks for coming back and sharing this with the community!