skip to Main Content

I have tried sending emails on my LightSail instance via AWS SES using the following Node.js JavaScript AWS SDK code, but it failed with the following error message. The email sending code works fine on my development computer. (The email sending code is from https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/ses-examples-sending-email.html.)

(code here)

import { readFile } from 'fs/promises';
import * as path from 'path';
import { SESClient } from "@aws-sdk/client-ses";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const awsConfigFileFullName = "aws_config.json";

let awsConfigFileFullPath = path.join(__dirname, awsConfigFileFullName);

const awsConfig = await readFile(awsConfigFileFullPath).then(json => JSON.parse(json)).catch(() => null);

aws_ses_client = new SESClient({ region: awsConfig.region, accessKeyId: awsConfig.accessKeyId, secretAccessKey: awsConfig.secretAccessKey });

const createSendEmailCommand = (toAddress, fromAddress, htmlContent, textContent, emailSubject) => {
  return new SendEmailCommand({
    Destination: {
      /* required */
      CcAddresses: [
        /* more items */
      ],
      ToAddresses: [
        toAddress,
        /* more To-email addresses */
      ],
    },
    Message: {
      /* required */
      Body: {
        /* required */
        Html: {
          Charset: "UTF-8",
          Data: htmlContent,
        },
        Text: {
          Charset: "UTF-8",
          Data: textContent,
        },
      },
      Subject: {
        Charset: "UTF-8",
        Data: emailSubject,
      },
    },
    Source: emailSenderName + '<' + fromAddress + '>',
    ReplyToAddresses: [
      /* more items */
    ],
  });
};

const sendEmailCommand = createSendEmailCommand(
recipientEmailAddress,
senderEmailAddress,
htmlEmailContent,
textEmailContent,
emailSubject
);

try {
await aws_ses_client.send(sendEmailCommand);
} catch (e) {
console.error("Failed to send email.", e);
}

(error here)

AccessDenied: User arn:aws:sts::(some number):assumed-role/AmazonLightsailInstanceRole/i-(some alphanumeric number)is not authorized to perform ses:SendEmail’ on resource
`arn:aws:ses:us-east-1:(some number):identity/(recipient email
address)’

After doing some search online on the issue, thinking that the error was caused by port 25 restriction on Lightsail instance restriction (https://aws.amazon.com/premiumsupport/knowledge-center/lightsail-port-25-throttle/), I sent a restriction removal request to AWS, but the request was declined, telling me to "consider looking into the Simple Email Service". I sent a reply asking if sending emails via AWS SES was possible on LightSail instance, but got a reply saying "we cannot grant your request"; I feel that the second reply was either automated or wasn’t even thoroughly read by the person who reviewed the email.

I have a multisite WordPress installed on my LightSail webserver, which can send emails via AWS SES with WP Mail SMTP plugin, with TLS encryption using SMTP port 587. I think this is a proof that emails can be sent on a LightSail instance via AWS SES. Emails do get sent by my WordPress on my LightSail webserver, everyday, using my AWS SES SMTP credentials; so, maybe the AWS SES SMTP server must be directly contacted in the LightSail instance email sending code to send emails, instead of using the authenticated SES client object in the code?

I’m thinking that maybe the assumed role AmazonLightsailInstanceRole doesn’t have AWS SES email sending allowed. I’ve checked my AWS IAM web console, and there was no role named AmazonLightsailInstanceRole; it doesn’t look like I can modify the policy on the assumed role AmazonLightsailInstanceRole.

Can AWS SES email-sending permission be granted to the assumed role AmazonLightsailInstanceRole? If so, how?

Is it possible to send emails via AWS SES on an AWS LightSail instance? If so, how can it be done in Node.js JavaScript AWS SDK code? Any verifications, references and/or directions would be very helpful.

2

Answers


  1. Chosen as BEST ANSWER

    UPDATE

    While testing my Node.js Express web app on an EC2 instance, to resolve the error I encountered, I came across the following: "Could not load credentials from any providers" while using dynamodb locally in Node.

    Because I was using @aws-sdk/ses-client (version 3), not version 2, I should've used the following:

    aws_s3_client = new S3Client({ region: awsConfig.region, credentials: {accessKeyId: awsConfig.accessKeyId, secretAccessKey: awsConfig.secretAccessKey }});
    aws_ses_client = new SESClient({ region: awsConfig.region, credentials: {accessKeyId: awsConfig.accessKeyId, secretAccessKey: awsConfig.secretAccessKey }});
    

    Using the above code enabled using both AWS SES and S3 from my web app running on a LightSail instance. So, the answer is, yes, it is possible to send emails via AWS SES on AWS LightSail instance.


  2. Sounds like an IAM issue – the instance role is the fallback option if you dont pass your own credentials. Lines 6..8 of the code is looking for a file (aws_config.json) which contains an API key and secret and a default region, then on line 9 its passing those values into SESClient. When you finally call aws_ses_client.send(sendEmailCommand) it will use the instance default credentails provided by lightsail which wont have access to resources in your aws account like SES. Check the following:

    • Does file aws_config.json exist?
    • Does it contain api key/secret/region for a valid user in your AWS account?
    • Does that user have a suitable IAM policy including ses:SendEmail and possibly other iam permissions?

    FYI catch(() => null) could be hiding an error – you should use console.log in your catch() statements to write an error (at least while your debugging).

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search