Mengirim Email Secara Asynchronous dengan Django

Beberapa waktu yang lalu, saya mendapat tugas untuk membuat subsistem notifikasi email ke manajemen bila ada user yang mem-posting pesan. Mail server tidak berada pada server yang sama, dan koneksi selalu membutuhkan waktu yang sangat lama, bahkan gagal. Kami memperkirakan bahwa latency disebabkan lokasi kedua server yang terlalu jauh.

Ketika troubleshooting, kami menemukan bahwa koneksi selalu menggunakan IPv6 (yang selalu gagal), dan setelah itu baru menggunakan IPv4.

Solusi untuk masalah pertama: fungsi wrapper untuk mengirim email secara asinkron. Ini saya dapatkan dari GitHub oleh Gilang, engineer dari User Inspired.

Pada file yang saya beri nama mail_async.py:

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()

Karena file di atas saya simpan sebagai bagian dari modul, maka dapat di-import seperti biasa:

try:
    from .mail_async import send_mail
except:
    from django.core.mail import send_mail

Cek dokumentasi django untuk menggunakan send_mail.

Untuk masalah yang kedua, saya menggunakan socket pada settings.py. Saya lampirkan contohnya bersama variabel email lainnya:

import socket
EMAIL_HOST = socket.gethostbyname('mail.example.com')
EMAIL_PORT = 465
EMAIL_HOST_USER = 'something@example.com'
EMAIL_HOST_PASSWORD = 'the_password'
EMAIL_USE_TLS = False
EMAIL_USE_SSL = True

Jika ada yang menggunakan cara ini, ada baiknya diperiksa dahulu mengapa koneksi IPv6 selalu gagal.