글 작성자: 개발섭

AWS SES는 메일발송을 쉽게 AWS에서 전송해주는 역할을 하고 있습니다. 그 중 일정한 형태는 고정되어있고 안의 내용만 변경 되야하는 템플릿 메일에 대해서 사용기와 경험담에 대해서 설명드리겠습니다.

TemplateMail은...

AWS에서는 일정형식의 HTML, 혹은 Text 형태의 템플릿 만들어서 그 형태에 어떤 값이 들어가는지만 알게되면 대치하는 방식을 통해 동일한 템플릿 사용자별로 다양한 메세지를 발송할 수 있습니다.
https://docs.aws.amazon.com/ko_kr/ses/latest/dg/send-personalized-email-api.html

메일 도메인이 처음 접하는 도메인이기도 했고, 어떤 방식으로 개발을 해야 효과적으로 개발 할 수 있는지에 대해서 잘 모르는 상황이라 좌충우돌이 많긴했으나 공유 드리면 좋을 것 같습니다.

1. 발송 오류는 SNS로 잡는게 좋다.

기본적으로 AWS SES 메일의 경우 메일의 발송 여부를 Event형태로 확인을 할 수 있습니다. 특히, SES 이벤트중 중요하게 생각하는 이벤트는 다음과 같습니다.
전송 및 배달

  • Rejects(거부) - Amazon SES가 이메일을 수락했으나 이메일에 바이러스가 포함된 것으로 판단되어 수신자의 메일 서버로 전송하려고 시도하지 않았습니다.
  • Deliveries(배달) – Amazon SES에서 이메일을 수신자의 메일 서버로 성공적으로 배달했습니다.
  • Hard bounces(하드 바운스) – 수신자의 메일 서버가 이메일을 영구적으로 거부했습니다. (_Soft bounces(소프트 바운스)_는 Amazon SES가 일정 시간 동안 재시도한 후 이메일을 배달하는 데 실패한 경우에만 포함됩니다.)
  • Complaints(수신 거부) - 이메일이 수신자의 메일 서버로 성공적으로 전송되었지만 수신자가 이를 스팸으로 표시했습니다.

메일 발송과 관련하여, 중요한 이벤트는 이 정도로 잡을 수 있는데, 템플릿 메일 발송시 간혹 메일이 무슨 이유에서인지 발송이 안된 케이스가 있어서 도대체 이것은 무엇인가... 왜 발송이 안되는것인지에 대해서 파악하지 못했는데...

SES에서는 이벤트로 하나 더 다음과 같은 이벤트를 캡쳐하고 있었습니다.

  • 렌더링 오류 – 템플릿 렌더링 문제로 인해 이메일이 전송되지 않았습니다. 이 이벤트 유형은 템플릿 데이터가 누락되었을 때 또는 템플릿 파라미터와 데이터 사이에 불일치가 있을 때 발생할 수 있습니다. (이 이벤트 유형은 SendTemplatedEmail 또는 SendBulkTemplatedEmail API 작업을 사용하는 이메일을 전송할 때만 발생합니다.)

즉, 렌더링 오류가 발생한 경우 템플릿에는 key가 존재하는데, 끼워넣어야하는 템플릿 데이터에는 해당하는 키가 없는 경우에 발생합니다. 이렇게 봐도 좋습니다.

템플릿에는 Key 존재 / 템플릿 데이터에는 해당하는 Key 값이 없음. → 랜더링 오류 ✅
템플릿에는 Key 미존재 / 템플릿 데이터에는 해당하는 Key 값이 있음 → 랜더링 오류 ❌

 

이렇게 이런 이벤트는 AWS SES의 구성세트(Configuration Set)로 선택해서 SES 발송시에 해당 구성세트를 포함해서 발송시키면, 위의 이벤트를 캡쳐해서 SNS를 통해 받아 처리할 수 있습니다.

2. 템플릿 메일은 Handlebars라는 템플릿 툴을 이용한다.

기본적으로 템플릿 메일에서 넣어질 데이터를 처리하는 방법은 {{key}} 형태로 구성됩니다. 문제는 반복적인 컨텐츠 즉, For문을 사용해서 List형태로 받아봐야하는 형태를 처리하는 방법이 어려웠다는점입니다.
그래서 초기에는 Table 형태의 파서를 제작해서 반복문이 나오면 그 형태로 테이블 자체를 붙혀주는 형태로 구축하려했으나, Table 형태의 파서는 여러 형태의 디자인에 즉각적인 대응도 힘들고, 각 케이스별로 메소드도 늘어나는 부담이 너무 커서 쉬운 방법이 없을까 고민했습니다.

AWS SES Template 메일은 Handlebars라는 라이브러리 툴을 이용하고 있고, 기본적으로 제공하는 Built-in Helper중에는 For문과 if/else문과 같은 가장 기초적인 구문은 제공하고 있어, 이 형태를 이용하면 좋습니다.
아래와 같은 형태의 반복문을 만들고, 다음처럼 템플릿 데이터를 구성하면 됩니다.

// 반목문 
{{#each subscription}} 
    <li>{{interest}}</li> 
{{/each}}


// 템플릿 데이터 형태
"subscription":[ { "interest":"Sports" }, { "interest":"Travel" }, { "interest":"Cooking" } ]

즉, 템플릿 데이터 형태는 제목안에 json 형태로 그 이름이 재대로 지정만되어있으면 잘 나옵니다.
또한 중첩인 케이스도 잘 처리할 수 있습니다.

//중첩문
"Subscription Preferences for {{contact.firstName}} {{contact.lastName}}",

//템플릿 데이터 
"contact":{ "firstName":"Anaya", "lastName":"Iyengar", "city":"Bengaluru", "country":"India", "postalCode":"560052" },

즉, 이러한 형태는 Map형식 혹은 DTO 형식에서 JacksonMapper를 통해 String 형태로 변환만 해준다면 쉽게 이용이 가능해지므로 Template 형태를 잡을 때 반복, if/else에 대한 케이스를 처리해서 수월하게 메일 템플릿을 만들면 좋습니다..

3. 국내 메일 엣지 케이스 대응

아무리 잘 디자인을 해도 메일에서 깨지는 경우가 종종 있습니다. 깨지는 경우 대응법이 명확하지 않아서 공유 드리면~~

  • 메일의 대부분 템플릿은 Table형태로 구성하는 게 좋습니다. 다른 컴포넌트를 통해 style 형태를 잡을 수 없기 때문입니다.
    • div 태그를 사용하지 않습니다.
  • margin을 사용할 수 없습니다
    • 단, 네이버는 예외입니다. 알 수 없는 이유로 align="center"가 적용되지 않지만 margin: 0 auto; 는 적용되어 가운데 정렬을 위해 해당 코드를 넣어두기
    • 마진이 먹지 않아 이경우 간혹 버튼이 왼쪽 정렬되는 경우가 왕왕 있었습니다
  • 메일 코드는 table 태그의 rowSpan, colSpan 기능은 지원하지 않습니다.
    • 중첩 테이블 형태로 이것을 한줄로 합치게 구현해야합니다. 아래 형태처럼
      <!-- 중첩 테이블을 사용하세요 -->
      <table border="0" cellpadding="0" cellspacing="0" style="width: 100%; border: 1px solid black; text-align: center; ">
      <tr style="border-bottom: 1px solid black;">
      <td>
      <!-- 중첩 테이블 -->
      <table border="0" cellpadding="0" cellspacing="0" style="width: 100%;">
        <tr style="width: 50%;">
          <td style="border-right: 1px solid black;">
            중첩
          </td>
          <td style="width: 50%;">
            테이블
          </td>
        </tr>
      </table>
      </td>
      </tr>
      <tr>
      <td>
      여기는 상대적으로 colspan="2"를 적용한 것처럼 보입니다.
      </td>
      </tr>
      </table>
  • 스타일링은 인라인 스타일링을 가지는게 좋습니다.
    • <td style="text-align: center; font-size: 14px;">
  • 참고를 위한 글 첨부 드립니다.
  • 스티비
  • 티스토리- 블로그

간단하게 알아본 AWS SES 템플릿 메일 발송시 유의점입니다. 차후 SES를 통한 메일 발송시 문제가 있는 경우 한번 체크해보면 좋겠습니다.