Django 이메일 비동기 전송


TODO

Django내에서 비동기로 메일을 전송

Why?

django는 기본적으로 send_mail() 함수를 제공하여 편리한 메일 전송 기능을 제공한다. 하지만 django의 기본 send_mail()함수는 synchrounous(동기) 작업이기에, 함수를 호출 할 경우 결과가 나와야 return이 된다.
메일 서버가 로컬에 있는 경우나 latency가 낮은 경우에는 큰 문제가 발생하지 않으나, 외부 메일 서버(zoho 등의 무료 메일 서버)를 사용 할 경우 상당히 큰 딜레이가 발생한다.
기존에 코드윙즈 서비스에서도 회원가입시 이메일 인증 전송코드를 메일로 전송하는데, 2~3초 가량 delay가 발생함을 알 수 있다. 우리는 안정적인 서비스 제공을 위해, 이메일 전송을 비동기작업으로 분리하도록 하자.

Solution

이런 latency가 긴 작업을 처리하는데는 주로 Celery를 많이 사용한다. Celery에 대한 문서는 http://docs.celeryproject.org/en/latest/index.html를 참조하면 된다.
또는, python의 자체의 threading을 이용해서 django의 send_mail을 비동기 작업으로 wrapping 하는 방법도 있다. 우리는 두번째 방법을 사용해보자.

class EmailThread(threading.Thread):
    def __init__(self, subject, body, from_email, recipient_list, fail_silently, html):
        self.subject = subject
        self.body = body
        self.recipient_list = recipient_list
        self.from_email = from_email
        self.fail_silently = fail_silently
        self.html = html
        threading.Thread.__init__(self)

    def run (self):
        msg = EmailMultiAlternatives(self.subject, self.body, self.from_email, self.recipient_list)
        if self.html:
            msg.attach_alternative(self.html, "text/html")
        msg.send(self.fail_silently)

def send_mail(subject, body, from_email, recipient_list, fail_silently=False, html=None, *args, **kwargs):
    EmailThread(subject, body, from_email, recipient_list, fail_silently, html).start()

위의 코드는 django의 send_mail()함수를 python threading을 이용하여 비동기적으로 작동하도록 wrapping하는 함수다. 해당 코드를 필요한 django 프로젝트내에 집어 넣은 후, 해당 모듈을 아래와 같이 import하여 사용하면 된다.

from 지정한_모듈_이름 import send_mail

출처 : https://github.com/ui/django_asynchronous_send_mail를 참조하여 작성하였습니다.

Back to blog