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)
참고 자료
- Testing email sending in Django
- Testing Django email backend
- Getting E-Mail right with Django and SES