[Django] template을 pdf로 변환 후 메일전송, 결과까지!

Django template를 PDF형식으로 변환하고 이메일에 첨부하여 발송하고 그 결과를 저장하는 기능을 구현해보자..

weasyprint

python의 weasyprint 라이브러리를 이용해 template를 pdf로 변환을 해준다.

📂 WeasyPrint Document

def send_email(email, *args):
    requestDate = str(datetime.datetime.now())[:10]
    task = _send_email.delay(email, requestDate, *args)
    

@app.task
def _send_email(email, requestDate, *args):
    ctx = {
        "date": requestDate,
        "data": your_data
    }

    html_string = render_to_string(YOUR_EMAIL_TEMPLATE, ctx)
    html = HTML(string=html_string)
    buffer = io.BytesIO()
    html.write_pdf(target=buffer)
    pdf = buffer.getvalue()

    email_message = EmailMultiAlternatives(
        to=(email,),
        subject="메일 제목",
        body="""
        메일 내용
        """,
    )
    filename = 'pdf파일 제목.pdf'
    mimetype_pdf = 'application/pdf'
    email_message.attach(filename, pdf, mimetype_pdf)
    email_message.send(fail_silently=False)

메세지 전송결과 가져오기

방법 1) celery 결과 이용

아래와 같이 AsyncResult를 이용하면 celery의 결과를 가져올 수 있다. celery 결과에 대한 내용은 예전 블로그에서도 확인 할 수 있다!

📂 Celery results Document

from celery.result import AsyncResult


def send_email	
    task = _send_email.delay(email, tmpdata)
    response = AsyncResult(str(task))
    state = response.state
    

이렇게 진행하니 결과가 계속해서 PENDING으로만 뜨는 이슈가 발생해서 celery docs와 stackoverflow를 찾아봤지만 도움이 되지 못했다.
그 외에도 CELERY_ALWAYS_EAGER = True.delay().run()로 바꾸는 작업은 비동기를 사용하지 않는 방법이기 때문에 제외했다.

그래서 찾다가..

방법 2) django email 결과 이용

장고 문서에 보면

The return value will be the number of successfully delivered messages (which can be 0 or 1 since it can only send one message).

발송 성공한 메세지의 수를 반환함으로 성공하면 1, 실패하면 0을 반환한다는 내용을 발견할 수 있었다! 두둥탁! 그렇게 email_send의 response를 db에 저장해주는 것으로 마무리한다.

최종 코드

from weasyprint import HTML

from django.core.mail import EmailMultiAlternatives
from django.template.loader import render_to_string


def send_email(email, *args):
    requestDate = str(datetime.datetime.now())[:10]
    task = _send_email.delay(email, requestDate, *args)
    

@app.task
def _send_email(email, requestDate, *args):
    ctx = {
        "date": requestDate,
        "data": your_data
    }

    html_string = render_to_string(YOUR_EMAIL_TEMPLATE, ctx)
    html = HTML(string=html_string)
    buffer = io.BytesIO()
    html.write_pdf(target=buffer)
    pdf = buffer.getvalue()

    email_message = EmailMultiAlternatives(
        to=(email,),
        subject="메일 제목",
        body="""
        메일 내용
        """,
    )
    filename = 'pdf파일 제목.pdf'
    mimetype_pdf = 'application/pdf'
    email_message.attach(filename, pdf, mimetype_pdf)
    response = email_message.send(fail_silently=False)
    qs = Emailresult.objects.get(id=id)
    if response == 1:
        qs.send_status = "complete" 
        qs.completed = datetime.datetime.now()
    else:
        qs.send_status = "fail"
    qs.save()

이 과정에서 마주한 문제들..

pdf변환시 한글이 안뜸

아래처럼 Unicode 디코딩이 되지않아 한글이 뜨지 않는 문제가 발생됐다.

블로그를 찾아보니 weasyprint는 cairo(그래픽 라이브러리)와 pango(font 라이브러리)에 의존성을 가지고 있어 pango는 local에 있는 폰트를 사용하기 때문에 pc에 font를 설치해줘야 한다고 한다.


Worker container

메일을 비동기로 처리하다보니 worker를 이용하게되느데 여기서 worker docker container는 자동 반영이 아니다. 그래서 코드 수정사항 발생시 계속 컨테이너를 재 생성했어야하는데 그러지 않아서 코드가 잘못된줄알고 수정과 수정반복.. 그냥 처음부터 worker container를 재 생성해주면 됐다..

좋은 웹페이지 즐겨찾기