I have a node server running in AWS ECS Fargate inside an isolated subnet. I have set up the task policy to allow sending emails
resource "aws_iam_role_policy" "ecs_task_ses_policy" {
name = "${var.environment}-ecs-task-ses-policy"
role = aws_iam_role.ecs_task_role.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"ses:*"
]
Resource = "*"
}
]
})
}
and I have allowed all outbound traffic on the task security group
resource "aws_security_group" "ecs_tasks" {
name = "${local.common_name}-ecs-tasks-sg"
description = "Security group for ECS tasks"
vpc_id = aws_vpc.this.id
ingress {
description = "Allow inbound from ALB"
from_port = 4000
to_port = 4000
protocol = "tcp"
security_groups = [aws_security_group.alb.id]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = local.common_tags
}
and I have a VPC endpoint set up for SES
resource "aws_vpc_endpoint" "ses" {
vpc_id = aws_vpc.this.id
service_name = "com.amazonaws.${var.aws_region}.email-smtp"
vpc_endpoint_type = "Interface"
subnet_ids = aws_subnet.private[*].id
security_group_ids = [aws_security_group.vpc_endpoints.id]
private_dns_enabled = true
tags = merge({
Name = "${local.common_name}-ses-endpoint"
}, local.common_tags)
}
But I can't send emails as the requests are timing out.
I am using nodemailer
and @aws-sdk/client-ses
import { createTransport, Transporter } from 'nodemailer';
import { SES, SendRawEmailCommand } from '@aws-sdk/client-ses';
...
this.transporter = createTransport({
SES: {
ses: new SES({ region }),
aws: { SendRawEmailCommand },
},
});
...
async sendMail(options: {
to: string | string[];
subject: string;
text?: string;
html?: string;
}) {
try {
await this.transporter.sendMail({
from: this.from,
...options,
});
this.logger.log(`Email sent successfully to ${options.to}`);
} catch (error) {
this.logger.error(`Failed to send email to ${options.to}:`, error);
throw error;
}
}
I have found in some resources that the AWS SDK SES client only uses HTTPS instead of SMTP.
What is the correct way to allow sending emails from my task but without creating the SES credentials manually since I want to use the assigned role for providing credentials?
AWS SES currently only supports VPC endpoints for the SMTP interface, not the AWS API interface. Your code is trying to use the AWS API to send an email via SES. The SMTP endpoint will not be used by the code you currently have.
You mentioned that you have a "private" VPC subnet. The typical terminology for subnet types is as follows:
If your subnet has a route to a NAT Gateway, then you shouldn't need any VPC endpoints configured at all, as the connection to the SES API will go through the NAT. If you actually have an "isolated" subnet, with no route to the AWS API at all, then unfortunately the only option you have is to switch to using an SMTP library in your code, instead of the AWS SDK, to send email to your VPC endpoint.