AWS Lambda, SES 를 이용한 이메일 발송처리

Heehong Moon
bgpworks
Published in
6 min readJul 30, 2021

박스히어로와 같은 B2B SaaS 서비스를 운영하면 이메일 발송할 건이 많다. 비밀번호 찾기, 회원가입 환영 메세지, 주간 리포트, 마케팅 이메일…등등.

박스히어로에서도 10종 이상의 이메일을 발송하고 있다.

이메일의 종류

보통 우리가 보내는 이메일은 크게 두가지 종류로 구분한다.

  • Transactional Email
  • Marketing Email

Transactional Email은 비밀번호 재설정, 회원가입 환영 메세지 등 단발성 메세지를 의미한다. Marketing Email은 그외 우리가 자주 접하는 마케팅성 이메일을 의미한다. 이 두가지 종류를 구분하는 가장 쉬운 방법은 “이메일 하단에 수신거부 처리를 넣어야 하는가?” 이다. 만약 수신거부 처리가 필요 없다면 Transactional Email 이다.

이메일 발송 서비스

시중에 이메일 발송 서비스는 꽤 많이 있는데 대표적으로 MailChimp, SendGrid와 같은 서비스가 있다. 이러한 서비스는 쉽게 이메일 템플릿을 만들수 있고 이메일 구독 해지 처리, 자동 Bounce 처리 등 편리한 기능을 제공한다. 이러한 서비스의 유일한 단점은 “비싸다” 인듯 하다. 😂

AWS에는 엄청나게 저렴한 가격에 이메일을 보내는 서비스 SES(Simple Email Service)가 있다. 하지만 SES는 MailChimp와 같은 서비스가 해주는 모든 기능을 아예 제공하지 않는다. SES는 SMTP 서버를 따로 운영할 필요 없이 이메일 보내기 기능만 제공하는 REST API라고 이해하면 된다.

  • To(받을 사람)
  • From(보내는 사람)
  • Title(제목)
  • Body(Text, HTML형식의 내용)

MailChimp와 같은 서비스를 이용하여 Marketing Email을 보내고, SES로Transactional Email을 보내면 가장 효율적으로 쓸수 있다. 하지만 위에 언급한것 처럼 SES의 경우 이메일 디자인 할수 있는 기능 자체를 제공하지 않는다.

박스히어로

우리의 경우에는 비용적인 문제도 있지만, 주간리포트 이메일의 경우 꽤 복잡한 조건식등이 필요하여 Transaction Email만 따로 빼서 SES로 보내기로 했다.

재고 분석 리포트 이메일 샘플

이메일 템플릿

디자인이 들어간 이메일의 내용(Body)부분은 HTML 형식으로 보내야 한다.

내용 HTML의 경우 요즘 모바일 사용자가 많아 반응형(Responsive)으로 디자인되어야 한다. 이메일 클라이언트마다 자체 브라우져를 내장하고 있는 경우가 있어, 최신 CSS를 이용할수 없고 table 태그로 디자인하는게 국룰이다. 🤮

다행히도 Mailjet에서 만든 mjml이라는 오픈소스 라이브러리가 있다. mjml이라는 마크업 언어로 작성하면 나름 깔끔하게 반응형 html을 생성할 수 있다.

mjml 자체적으로는 parameter 를 받아서 html렌더링 할수 있는 기능은 없는데, html 템플릿 라이브러리 중 가장 유명한 handlebars를 함께 이용했다. handlebars를 통해 parameter 데이터를 받아서 if, loop, formating 등 다양한 로직을 템플릿 안에 추가할 수 있었다.

handlebars template 예제

아키텍쳐

AWS의 세가지 서비스를 활용하여 구현했다.

  • SQS
  • Lambda
  • SES

아래와 같은 단계로 이메일이 발송된다.

  1. 박스히어로 웹서버에서 이메일 보낼 데이터(템플릿 id, 파라메터)를 SQS에 넣는다.
  2. Lambda 의 SQS Trigger를 활용하여 실행한다.
  3. Lambda에서 SES를 이용하여 이메일을 발송한다.

Lambda는 Request양에 따라 Scaling이 되기 때문에 갑자기 폭발적으로 이메일 발송건수가 많아져도 문제없이 서비스 될수 있다. 오히려 Throttling이 되는 부분은 SQS가 아니라, SES의 Sending Rate Limit이다. SES API의 경우 API call에 약 1–2초 정도의 latency가 발생한다. 따라서 불필요한 Latency를 없애는 비동기 발송하기 위해서는 SQS가 필수적이라고 볼수 있다.

박스히어로 사용자가 점점 많아져서 동시에 보내는 이메일 개수가 많아질 경우 SES Limit상향 조절만 아마존에 요청하면 된다.

구현상 팁

  • mjml의 렌더링 속도는 꽤 느려서(1–2초) 런타임에 쓸수 없다. lambda 함수 빌드/배포 타임에 mjml렌더링을 미리 해야만 한다.
  • Lambda 런타임에는 handlebars만 렌더링 한다. (handlebars의 렌더링 속도는 1ms 이하 🚀)
  • 이메일의 HTML body말고 Text body도 넣어주는게 좋은데(html을 지원하지 않는 이메일 클라이언트 지원), 별도로 내용을 쓰는게 아니라 html에 포함된 글자를 자동으로 뽑아서 넣는다. node-html-to-text 참고
  • 이메일의 제목은 mj-title 태그에서 추출한다. cheerio 참고

빠른 이메일 발송 처리에 대해 고민했고, 앞으로 계속 늘어날 이메일 템플릿을 쉽게 추가할수 있는 방법을 찾으려 노력했다. 그 결과 1초 이내로 이메일 발송이 되며, 이메일 템플릿은 mjml파일 하나만 만들어서 repo에 추가해주면 완료된다.

앞으로 더 발전해야 할 부분

SQS를 이용하여 비동기 처리를 했기 때문에 아래와 같은 상황에 대한 처리가 적절히 되어야 한다.

  • 잘못된 이메일을 입력한 경우
  • 잘못된 parameter를 넘겨 handlebars 렌더링에 실패한 경우
  • Bounce, Complaints 처리 및 로깅

참고 자료

--

--