웹 문의 접수부터 API Gateway, Lambda, DynamoDB, 비동기 Worker, Amazon SES, 수신 결과로 이어지는 상태별 아키텍처

AWS API는 202 Accepted인데 이메일이 오지 않는 이유: Lambda·DynamoDB·SES 장애 진단

Posted by

웹사이트의 문의 폼에서 정상적으로 제출 버튼을 눌렀다.
화면에는 성공 메시지가 표시되었다.

그런데 관리자 메일함에는 문의가 도착하지 않았다면 어디부터 확인해야 할까?
202 Accepted가 반환되었다고 해서 이메일 전송까지 끝났다고 판단하는 것이 가장 흔한 오해 중 하나입니다.

DeepLink의 내부 문의 접수 시스템도 API Gateway, Lambda, DynamoDB와 Amazon SES를 이용합니다. 실제 운영 환경에서 문의가 저장되고 최종적으로 메일함에 도착하는 흐름을 확인한 경험이 있습니다. 이번 글에서는 내부 시스템에서 확인한 경계와 일반적인 장애 진단 방법을 구분해 살펴보고자 합니다.


HTTP 202는 ‘이메일 도착 완료’가 아니다

202 Accepted는 서버가 요청을 접수했지만 처리 결과가 최종적으로 확정되지 않았을 수 있음을 의미합니다. 비동기 업무 흐름에서는 정상적인 응답 코드지만, 문의가 저장된 것과 이메일이 발송된 것, 수신 메일 서버에 전달된 것은 서로 다른 사건이라고 봐야 합니다.

개념적인 처리 단계를 먼저 보면,

방문자 문의 폼

    ↓  POST /contact

API Gateway / Intake Lambda

    ↓  입력 검증 및 접수 ID 생성

DynamoDB — 접수 레코드 저장
    ├─→ 방문자에게 HTTP 202 + 접수 참조번호 반환
    └─→ 비동기 Email Worker

              ↓  SES API 전송 요청

Amazon SES — 발송 요청 수락

    ↓  별도 이벤트/메일함 확인

전달 성공 또는 Bounce/Complaint 등 확인

실제 구성에서는 데이터베이스 폴링, 이벤트 큐, 함수 비동기 호출 등 다양한 방식으로 Worker를 실행할 수 있습니다.

위 다이어그램은 모든 단계가 하나의 Lambda 요청 안에서 순서대로 실행된다는 뜻이 아니며, API 요청은 보통 저장이 완료되면 먼저 응답하고 이후 작업이 독립적으로 진행됩니다.


어디서 실패했는지 단계별로 나누자

단계성공을 판단할 증거대표적 장애
폼 → APIHTTP 상태와 요청 참조번호CAPTCHA, 필드 검증, CORS, 네트워크
Intake → DynamoDB실제 저장 레코드와 접수 상태IAM 권한, 쓰기 실패, 입력 스키마
Worker 처리작업 실행 기록과 처리 상태스케줄 지연, 재시도 고갈, 예외
Worker → SESSES API 응답 및 메시지 IDAccessDenied, 검증되지 않은 발신자, 제한 정책
SES → 수신 시스템SES 전달·반송 이벤트, 수신 메일함 확인Bounce, 정책 차단, 스팸 분류

예를 들어, Lambda가 SES SendEmail 호출에서 AccessDenied 오류를 만났다면, 먼저 정확한 실행 역할, SES 전송에 필요한 IAM 권한, 발신자 ID 및 리전을 확인해야 하며, 무작정 AdministratorAccess를 추가하는 방법은 적절하지 않습니다.

또한 SES에서 발송 요청이 받아들여졌다고 해서 수신자의 메일함에 반드시 표시되는 것도 아닙니다. SES는 설정에 따라 Send, Delivery, Bounce, Complaint 등 다양한 이벤트를 발행할 수 있습니다.


접수번호 하나로 추적할 수 있어야 한다

문제 해결 속도를 높이는 가장 실용적인 방법은 요청에서 생성한 참조번호를 각 처리 단계에 연결하는 것입니다. 예를 들어 하나의 reference_id를 기준으로 다음 정보를 조회할 수 있도록 설계해야 합니다.

  • 문의를 접수한 시각, HTTP 요청 결과
  • 저장 레코드가 생성된 시각
  • Worker 실행 횟수, 재시도 여부, 최근 오류 코드
  • SES 전송 API 수락 여부와 메시지 식별자
  • 별도로 수집 가능한 전달·반송 이벤트

권장 상태 예시는 PENDING → PROCESSING → SES_ACCEPTED → DELIVERED이며, 실패할 때는 RETRY 또는 FAILED 같은 별도 경로가 필요합니다. 이는 이해를 돕기 위한 상태 모델이며, 모든 서비스가 이 이름을 사용해야 하는 것도 아닙니다.

중요한 점은 SENT라는 하나의 표시만으로 ‘SES API 수락’과 ‘실제 수신’을 혼동하지 않는 것입니다. 수신 메일함에 들어왔는지까지 검증하려면 별도의 검증 증거가 필요합니다.


재시도할 때 중복 이메일을 막는 방법

Worker가 실패한 뒤 다시 실행되면 같은 문의를 중복 전송할 수 있습니다. 따라서 재시도 규칙뿐 아니라 같은 문의를 중복 처리했을 때의 부작용도 점검해야 합니다.

  • 접수 ID를 기준으로 처리 상태를 조회한다.
  • 이미 완료된 처리와 재시도가 필요한 처리를 구분한다.
  • 병렬 Worker가 동시에 같은 문의를 처리하지 못하도록 조건부 갱신이나 잠금 등을 검토한다.
  • SES 발송 성공 직후 상태 기록에 실패할 수 있으므로, 중복 메일 위험은 별도로 평가한다.
  • 실패한 문의를 무한히 재시도하지 않고 운영자가 확인할 수 있는 경로를 마련한다.

특히 이메일은 DB 업데이트와 SES 전송을 하나의 트랜잭션으로 묶기 어려우며, 어떤 시스템도 별도 설계와 증거 없이 정확히 한 번만 전달된다고 보장해서는 안 됩니다.


DeepLink의 자체 홈페이지 문의 흐름에서는 실제 폼 제출, 문의 저장 응답, 백엔드 메일 처리와 최종 메일함 수신을 확인했습니다.

관련된 기술적 검증 기준은 DeepLink Verification에서 확인할 수 있습니다.
AWS 문의 접수·전송 문제에 대한 범위 확인이 필요하시다면 아래 링크를 참고 하시면 됩니다.

실제 문제를 분석할 때는 성공 메시지 화면 하나가 아니라 접수 ID → DB 레코드 → Worker 실행 → SES 응답 → 전달 확인의 증거 체인을 확보해야 합니다. 이렇게 하면 재현할 수 없는 ‘이메일이 안 와요’를 단계별로 검증 가능한 장애로 바꿀 수 있습니다.


기술 범위 문의: Technical scope request — DeepLink

Leave a Reply

Your email address will not be published. Required fields are marked *