Django와 AWS SES를 연동하기

Django 1.8에서 이메일 전송 기능을 구현하는 방법을 정리한다. SMTP 서버는 AWS SES(Amazon Simple Service)을 이용하기로 한다.

좋지 않은 방법

django-ses

django-ses는 boto, 그러니까 AWS 공식 파이썬 라이브러리를 이용해 SMTP가 아닌 AWS가 제공하는 API로 이메일을 보낸다. 이론적으로는 SES 서비스와 연동하는 가장 훌륭한 방법이다. 하지만 함정이 있으니……

django-ses는 2년째 업데이트가 안 됐고 Python 3.x에서 제대로 작동하지 않는다. 그래서 이 프로젝트를 가져다 고친 사람이 많다. 대안이 있다 하더라도 제대로 관리되지 않는 라이브러리를 사용하기는 신경 쓰인다.

django-smtp-ssl

django-smtp-ssl을 사용하는 예제가 웹에는 많다. 하지만 이 라이브러리의 제일 큰 문제는 이 라이브러리를 굳이 쓸 이유가 없다는 것이다. django.core에 포함된 이메일 백엔드만으로도 AWS SES와 통신하는데 아무런 문제가 없기 때문이다.

제대로 된 방법

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'email-smtp.us-east-1.amazonaws.com'
EMAIL_PORT = 587
EMAIL_HOST_USER = 'your-user'
EMAIL_HOST_PASSWORD = 'your-password'
EMAIL_USE_TLS = True
DEFAULT_FROM_EMAIL = '[email protected]'

settings.py에는 대충 이렇게 설정하면 된다. django.core.mail.backends.smtp.EmailBackend면 SES를 SMTP 서버로 사용하는데 충분하다.

테스트하기

이제 단위 테스트를 작성해 이메일이 제대로 가는지 확인해보자.

def test_send_email(self):
  subject = 'subject'
  message = 'message'
  from_email = '[email protected]'

  self.user.email_user(subject=subject, message=message, from_email=from_email, fail_silently=False)

이렇게 짜고 테스트를 돌리면 이메일이 도착하지 않는다. 그 이유는 Django Testing Tools 문서 끝자락에 나온다. Django는 단위테스트를 돌릴 때 EMAIL_BACKEND의 값을 django.core.mail.backends.locmem.EmailBackend으로 바꿔놓는다. 그래서 settings.py의 설정을 제대로 해놓아도 SES와는 통신하지 않는다. 그 대신 mail.outbox라는 곳에 발송됐어야 할 이메일을 저장해놓는다. 이 값을 이용해 단위테스트를 짜면 다음과 같다.

def test_send_email(self):
  subject = 'subject'
  message = 'message'
  from_email = '[email protected]'

  self.user.email_user(subject=subject, message=message, from_email=from_email, fail_silently=False)

  # Test that one message has been sent.
  self.assertEqual(len(mail.outbox), 1)

  # Verify that the subject of the first message is correct.
  mail_sent = mail.outbox[0]
  self.assertEqual(mail_sent.subject, subject)
  self.assertEqual(mail_sent.body, message)
  self.assertEqual(mail_sent.from_email, from_email)
  self.assertTrue(self.user.email in mail_sent.to)

나쁘지 않지만 실제로 SES로 이메일을 보낼 때 아무런 문제가 없는지 확인할 수는 없다. 단위 테스트는 기본적으로 외 서비스에 의존하지 않아야 한다는 기본 요건을 생각하면 틀린 건 아니다. 이런 종류의 테스트는 통합 테스트로 따로 묶는 편이 좋다. 통합 테스트용 모듈을 따로 만들었다면 다음과 같이 코드를 짠다. 그러면 django.core.mail.backends.smtp.EmailBackend를 이용해 실제 이메일을 보낸다.

from django.test import TestCase
from django.core import mail
from django.test.utils import override_settings
from users.tests import utils


@override_settings(EMAIL_BACKEND='django.core.mail.backends.smtp.EmailBackend')
class SmtpTests(TestCase):
  def test_send_email(self):
    mail_sent_success = mail.send_mail('Subject here',
     'Here is the message.',
     '', [utils.developer_email],
     fail_silently=False)
    self.assertEquals(mail_sent_success, 1)

참고 자료

최 재훈

블로그, 페이스북, 트위터 고성능 서버 엔진, 데이터베이스, 지속적인 통합 등 다양한 주제에 관심이 많다.
Close Menu