Rust로 만든 공용 이메일 게이트웨이

여러 사내 제품의 이메일 발송과 전송량을 관리하기 위해 Amazon SES v2를 감싸서 만든 Rust API입니다.

내 역할: 단독 개발. 54개 커밋 중 53개를 제가 작성했습니다.

2024년 10월부터 2026년 4월까지

공용 서비스가 필요했던 이유

여러 제품이 같은 Amazon SES 계정으로 이메일을 보내야 합니다. SES의 초당 전송 속도와 최근 24시간 전송 한도는 각 애플리케이션이 아니라 계정 전체에 적용됩니다.

제품마다 SES를 따로 연동하면 다른 제품이 한도를 얼마나 썼는지 알 수 없습니다. 한 제품 때문에 계정 전체가 전송 제한을 받거나 정지될 수 있고, 그러면 나머지 제품의 이메일도 멈춥니다.

제가 만든 것

제품과 SES 사이에 놓이는 서비스를 Rocket과 Rust로 만들었습니다. 발송, 대량 발송, 로그 조회와 삭제, 한도 확인, 상태 확인을 위한 인증된 엔드포인트 6개가 있습니다. 다른 제품은 SES에 직접 접근하는 대신 이 API를 호출합니다.

대량 발송과 전송 한도

대량 발송 엔진은 실행 시점에 SES의 현재 최대 전송 속도를 조회하고, 수신자 목록을 그에 맞는 묶음으로 나눈 뒤 초당 한도에 맞춰 전송합니다. AWS가 계정의 전송 평판을 갱신하면 이 값이 바뀔 수 있어서, 설정에 고정해 두면 언젠가 틀리게 됩니다.

발송 전에는 남은 24시간 한도도 확인합니다. 요청이 너무 크면 가능한 만큼 보내고 건너뛴 수신자를 명확히 알려줍니다. 응답에는 HTTP 207 Multi-Status를 사용해 각 주소의 결과를 발송 성공, 실패, 건너뜀으로 구분합니다. 단일 200이나 500으로는 호출자가 어떤 이메일을 다시 보내야 하는지 알 수 없습니다.

발송을 지연시키지 않는 로그

모든 발송은 기록하지만, 로그 기록이 호출자와 SES 사이에 끼어 발송을 늦추는 것은 원하지 않았습니다. Tokio 백그라운드 작업으로 뮤텍스가 보호하는 링 버퍼에 기록하고, 페이지 단위로 조회할 수 있게 했습니다. 버퍼는 10,000개 항목으로 제한했습니다. 제한이 없다면 오래 실행된 서비스는 이전 로그만으로 결국 메모리를 모두 쓰게 됩니다.

실제 제공자를 상대로 테스트하기

단위 테스트와 함께 실제 SES를 호출하는 973줄의 통합 테스트를 작성했습니다. 모의 객체는 우리 코드 확인에는 유용하지만, 속도 제한, 한도 계산, 수신자별 결과가 실제 서비스에서도 같은 방식으로 동작하는지 확인해 주지는 않습니다. 잘못 발송하면 회사 계정이 정지될 수 있는 API이므로 이 부분이 특히 중요했습니다.

그 밖에 Rocket 요청 가드를 통한 Bearer 키 인증, MIME과 크기를 검증하는 base64 첨부 파일, thiserror로 정의한 타입별 오류도 포함했습니다.

수치로 보면

54개 커밋 중 53개를 제가 작성했습니다. 프로젝트에는 약 1,900줄의 서비스 코드와 1,350줄의 테스트 및 예제가 있고, 테스트는 약 40개입니다. 캠페인 제품과 유지보수 제품에서 사용 중입니다.

연락하기

원격 프리랜서 업무가 가능합니다. 이메일로 연락해 주시면 가장 빠르게 답변할 수 있습니다.