如何基于Angular、Spring Boot与AWS SES实现联系表单发邮件功能
Angular + Spring Boot + AWS 实现联系表单发邮件完整方案
整体逻辑:前端仅负责表单校验、提交数据到后端,所有邮件发送逻辑放在Spring Boot后端完成,通过AWS SES(简单邮件服务)实现邮件投递,全程不会暴露服务凭证,稳定性远高于自建SMTP服务,个人站使用几乎无成本。
一、Angular 前端补全(你已完成响应式表单基础搭建,仅需补充以下逻辑)
注意:绝对不要在前端代码里写任何邮件服务的密钥、凭证,前端代码用户可直接查看,会导致凭证泄露、被恶意盗用产生账单
- 给表单补充基础校验规则:姓名、用户邮箱、留言内容设为必填项,邮箱字段加格式校验,提交前拦截非法输入,减少无效后端请求
- 编写表单提交方法:校验通过后通过
HttpClient向后端接口发POST请求,携带表单数据,同时加提交状态控制,示例代码:
// contact.component.ts submitForm() { if (this.contactForm.invalid) { this.contactForm.markAllAsTouched(); return; } this.isSubmitting = true; this.http.post('/api/contact/submit', this.contactForm.value) .subscribe({ next: () => { this.submitSuccessTip = '留言提交成功,我会尽快回复你'; this.contactForm.reset(); this.isSubmitting = false; }, error: () => { this.submitErrorTip = '提交失败,请稍后重试'; this.isSubmitting = false; } }) }
- 加交互反馈:提交过程中禁用提交按钮防止重复提交,成功、失败场景给用户明确文字提示
- 生产环境将后端接口地址配置到
environment环境变量中,不要硬写接口地址,本地开发可配代理解决跨域问题
二、Spring Boot 后端实现
- 引入所需依赖:如果用Maven,在
pom.xml中引入spring-boot-starter-web、spring-boot-starter-validation、aws-java-sdk-ses三个依赖;Gradle项目对应引入即可 - 配置基础参数:在
application.yml中添加AWS区域、发信邮箱配置,不要把IAM访问密钥硬写在配置文件里提交到代码仓库,示例配置:
aws: region: 你使用的AWS区域,例如ap-northeast-1 ses: receive-email: 你自己接收留言的个人邮箱
- 编写表单接收DTO,加参数校验注解,从入口拦截非法参数:
// ContactFormDTO.java public record ContactFormDTO( @NotBlank(message = "姓名不能为空") String name, @Email(message = "请输入正确的邮箱格式") @NotBlank(message = "邮箱不能为空") String replyEmail, @NotBlank(message = "留言内容不能为空") @Size(max = 2000, message = "留言长度不能超过2000字") String content ) {}
- 编写邮件发送Service层,注入SES客户端,拼接邮件内容后调用SES接口发信:
// ContactService.java @Service public class ContactService { private final AmazonSES sesClient; @Value("${aws.ses.receive-email}") private String receiveEmail; public ContactService(AmazonSES sesClient) { this.sesClient = sesClient; } public void sendContactMail(ContactFormDTO form) { // 拼接邮件正文,把用户提交的信息完整写入 String mailContent = String.format(""" 你网站收到新的用户留言: 提交人:%s 回复邮箱:%s 留言内容: %s """, form.name(), form.replyEmail(), form.content()); SendEmailRequest sendRequest = new SendEmailRequest() .withSource(receiveEmail) .withDestination(new Destination().withToAddresses(receiveEmail)) .withMessage(new Message() .withSubject(new Content("网站新留言 | 来自" + form.name())) .withBody(new Body().withText(new Content(mailContent))) ); sesClient.sendEmail(sendRequest); } }
- 编写对外接口,配置跨域规则(仅允许你的个人网站域名访问,不要开
*全通配),做异常捕获,加简单限流(同IP10分钟内最多提交3次,防止恶意刷留言):
// ContactController.java @RestController @RequestMapping("/api/contact") @CrossOrigin(origins = "你的个人网站正式域名") public class ContactController { private final ContactService contactService; // 简单内存限流计数,个人站足够用 private final LoadingCache<String, AtomicInteger> rateLimitCache = CacheBuilder.newBuilder() .expireAfterWrite(10, TimeUnit.MINUTES) .build(CacheLoader.from(() -> new AtomicInteger(0))); public ContactController(ContactService contactService) { this.contactService = contactService; } @PostMapping("/submit") public ResponseEntity<String> submit(@Valid @RequestBody ContactFormDTO form, HttpServletRequest request) { // 限流判断 String clientIp = request.getRemoteAddr(); int count = rateLimitCache.getUnchecked(clientIp).incrementAndGet(); if (count > 3) { return ResponseEntity.status(HttpStatus.TOO_MANY_REQUESTS).body("提交过于频繁,请稍后再试"); } try { contactService.sendContactMail(form); return ResponseEntity.ok("提交成功"); } catch (Exception e) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("服务异常,请稍后重试"); } } }
- 如果你的服务部署在AWS上(EC2/ECS/Lambda),直接给对应计算资源绑定拥有SES发信权限的IAM角色即可,不需要配置AK/SK;如果部署在非AWS服务器,创建仅拥有SES发信权限的IAM用户,将AK/SK通过环境变量注入服务即可。
三、AWS 侧配置
- 开通SES服务:进入SES控制台,找到「已验证身份」选项,添加你用来接收留言的个人邮箱,去邮箱里点验证链接完成验证即可。
注意:SES默认处于沙箱模式,仅可向已完成验证的邮箱发送邮件,你的场景是发信到自己的已验证邮箱,完全不需要申请移出沙箱,省去审核流程 - 权限配置:给后端服务使用的IAM角色/用户添加SES发信权限,个人站可以直接给
AmazonSESFullAccess权限,生产环境可以缩小权限范围到仅允许SendEmail操作。 - 可选配置:在SES中配置邮件发送失败通知,出现投递问题时会自动给你发提醒,方便排查问题。
四、避坑提示
- 不要尝试用前端直接调用SES接口发信,前端暴露的凭证会被恶意用户盗用发送垃圾邮件,产生高额账单
- 邮件内容尽量减少营销类敏感词、过多外链,避免被邮箱服务商判定为垃圾邮件
- 后端接口不要返回详细的服务报错信息,避免泄露服务架构细节
- 如果要加回复功能,直接给用户提交的邮箱发信即可,不需要额外配置
内容的提问来源于stack exchange,提问作者Murilo de Melo Reis
相关产品推荐
相关产品推荐

