You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在私有子网的Elastic Beanstalk Spring Boot应用中使用AWS SES

AWS SES v2 SDK在私有子网中连接超时的问题解决

我有一个基于Spring Boot的应用,使用AWS SDK v2 for Java的software.amazon.awssdk.services.sesv2.SesV2Client执行添加联系人、发送邮件等操作,开发环境正常,但生产环境部署在私有子网(通过Elastic Beanstalk的EC2实例),依赖VPC端点和AWS服务通信。尝试为SES配置VPC端点时,发现只有com.amazonaws.us-east-1.email-smtp可用,无法支持SDK的调用,应用报错连接超时:

Jul 24 22:46:15 ip-10-0-2-126 web: 2022-07-24 22:46:15.999 DEBUG 1747 --- [nio-5000-exec-6] .m.m.a.ExceptionHandlerExceptionResolver : Using @ExceptionHandler com.oddsapi.odysseyapi.controllers.exceptionhandling.GlobalControllerExceptionHandler#defaultErrorHandler(HttpServletRequest, Exception)
Jul 24 22:46:16 ip-10-0-2-126 web: 2022-07-24 22:46:15.999 DEBUG 1747 --- [nio-5000-exec-6] o.s.web.servlet.DispatcherServlet : Failed to complete request: software.amazon.awssdk.core.exception.SdkClientException: Unable to execute HTTP request: Connect to email.us-east-1.amazonaws.com:443 [email.us-east-1.amazonaws.com/52.5.91.104, email.us-east-1.amazonaws.com/18.206.141.93, email.us-east-1.amazonaws.com/52.20.100.70, email.us-east-1.amazonaws.com/34.230.97.163, email.us-east-1.amazonaws.com/3.217.95.76, email.us-east-1.amazonaws.com/34.237.162.86, email.us-east-1.amazonaws.com/54.164.105.38, email.us-east-1.amazonaws.com/3.220.196.1] failed: connect timed out


假设验证

你的假设完全正确:私有子网内无公网访问权限,且缺少对应SES API的VPC端点,导致SDK无法连接email.us-east-1.amazonaws.com(SES v2 API的公网端点)而超时。当前AWS提供的SES VPC端点仅支持SMTP协议(端口587/465),不支持SES的REST API调用,这是核心问题。

可行替代方案

  • 方案1:配置NAT网关/实例
    给私有子网配置NAT网关(推荐)或NAT实例,让EC2实例通过NAT访问公网的SES API端点。无需修改代码,但会产生额外的NAT网关费用。

  • 方案2:切换到SES SMTP协议
    放弃SES v2 SDK,改用SMTP协议发送邮件,利用已有的email-smtp VPC端点。注意:SMTP仅支持发送邮件操作,无法实现添加联系人、管理邮件列表等API功能,若应用依赖这些功能则不适用。

  • 方案3:使用Lambda作为中间层
    在公有子网部署Lambda函数,由它调用SES v2 API完成所有操作;私有子网内的应用通过VPC端点调用Lambda(需配置Lambda的VPC端点)间接使用SES服务。既保留SES API全功能,又不需要私有子网访问公网。

  • 方案4:使用SNS转发邮件请求
    若仅需发送邮件,可将请求发送到SNS主题,配置SNS订阅触发SES发邮件。私有子网应用通过SNS的VPC端点访问SNS,间接实现邮件发送。同样不支持联系人管理等SES API操作。


代码/配置修改建议

方案2:切换到SMTP发送邮件

如果仅需发送邮件,修改如下:

  1. 添加JavaMail依赖:
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>
  1. 配置application.properties:
spring.mail.host=email-smtp.us-east-1.amazonaws.com
spring.mail.port=587
spring.mail.username=你的SES SMTP用户名(IAM Access Key)
spring.mail.password=你的SES SMTP密码(IAM Secret Key)
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
  1. 编写邮件发送服务:
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;

@Service
public class EmailService {
    private final JavaMailSender mailSender;

    public EmailService(JavaMailSender mailSender) {
        this.mailSender = mailSender;
    }

    public void sendEmail(String to, String subject, String text) {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setFrom("你的验证邮箱");
        message.setTo(to);
        message.setSubject(subject);
        message.setText(text);
        mailSender.send(message);
    }
}

方案3:使用Lambda中间层

  1. 创建Lambda函数调用SES v2 API:
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.sesv2.SesV2Client;
import software.amazon.awssdk.services.sesv2.model.SendEmailRequest;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;

public class SesLambdaHandler implements RequestHandler<EmailRequest, String> {
    private final SesV2Client sesClient = SesV2Client.builder()
            .region(Region.US_EAST_1)
            .build();

    @Override
    public String handleRequest(EmailRequest request, Context context) {
        SendEmailRequest sendEmailRequest = SendEmailRequest.builder()
                .fromEmailAddress(request.getFrom())
                .destination(d -> d.toAddresses(request.getTo()))
                .content(c -> c.simple(s -> s.subject(sub -> sub.data(request.getSubject()))
                        .body(b -> b.text(text -> text.data(request.getBody())))))
                .build();
        sesClient.sendEmail(sendEmailRequest);
        return "Email sent successfully";
    }

    public static class EmailRequest {
        private String from;
        private String to;
        private String subject;
        private String body;
        // 省略getter/setter
    }
}
  1. 给Lambda配置IAM权限,允许调用SES v2 API。
  2. 在Spring Boot应用中调用Lambda:
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.lambda.LambdaClient;
import software.amazon.awssdk.services.lambda.model.InvokeRequest;
import com.fasterxml.jackson.databind.ObjectMapper;
import software.amazon.awssdk.core.SdkBytes;

public class LambdaSesService {
    private final LambdaClient lambdaClient = LambdaClient.builder()
            .region(Region.US_EAST_1)
            .build();
    private final ObjectMapper objectMapper = new ObjectMapper();

    public void sendEmailViaLambda(String from, String to, String subject, String body) throws Exception {
        EmailRequest request = new EmailRequest(from, to, subject, body);
        String payload = objectMapper.writeValueAsString(request);
        InvokeRequest invokeRequest = InvokeRequest.builder()
                .functionName("你的Lambda函数名")
                .payload(SdkBytes.fromUtf8String(payload))
                .build();
        lambdaClient.invoke(invokeRequest);
    }

    private static class EmailRequest {
        private final String from;
        private final String to;
        private final String subject;
        private final String body;

        public EmailRequest(String from, String to, String subject, String body) {
            this.from = from;
            this.to = to;
            this.subject = subject;
            this.body = body;
        }
        // 省略getter
    }
}
  1. 确保VPC配置了Lambda的VPC端点(com.amazonaws.us-east-1.lambda),且Lambda安全组允许私有子网EC2实例访问。

补充说明

类似问题包括:Fargate容器在私有子网中无法通过SES端点发送邮件、Spring应用在Fargate中无法连接SES,核心原因均为SES VPC端点仅支持SMTP协议,不兼容API调用。官方文档也明确了这一点。

内容的提问来源于stack exchange,提问作者After_Sunset

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 20:48:22