티스토리 뷰

Django

Django - 이메일 발송 구현하기

최정은 2021. 8. 29. 18:58

메일을 보내는 데는 SMTP라는 메일 발송 서버를 이용해야 하는데, 구글과 네이버 SMTP를 이용할 수 있습니다.

지금은 구글의 SMTP 서버를 이용할 예정이므로 구글 계정이 준비되어 있어야 합니다.


'django-admin startproject [프로젝트명]'으로 장고 프로젝트를 생성해주고, 'python manage.py startapp mail'으로 mail 앱을 만들어 주었습니다.

 

먼저 프로젝트 폴더의 urls.py에 다음과 같이 작성하여 각 앱별로 url 주소를 관리하도록 처리해줍니다.

path('mail/', include('mail.urls')),

 

mail 앱의 urls.py를 다음과 같이 작성합니다.

from django.urls import path, include
from .views import *

urlpatterns = [
    path('', index, name='index'), # 메일 폼 url
    path('send/', sendEmail),      # 메일 발송 처리 url
]

 

그러면 index와 sendEmail 함수가 views.py에 작성되지 않아 오류가 뜰 텐데 mail 앱의 views.py에서 각 함수를 작성해주어 해결합니다.

from django.shortcuts import render
from django.http import HttpResponse

# Create your views here.
def index(request):
    return render(request, 'index.html')

def sendEmail(request):
    return HttpResponse("sendEmail")
    # HttpResponse 함수는 단순히 문자열만 출력되도록 해줍니다.
    # 나중에 구체적인 내용을 추가할 예정입니다.

기본적인 틀만 잡고 세부적인 로직은 나중에 구현합니다.


이제 이메일을 보내기 위해 내용을 작성할 수 있는 페이지를 만듭니다.

 

먼저 사용자가 이메일 발송을 눌렀을 때 이를 처리하기 위한 경로로 가도록 설정해야 합니다.

(이것은 일단 mail 폴더에 templates 폴더를 만들고 index.html 파일을 만들어줍니다.)

다음은 수신자, 제목, 내용을 사용자가 입력할 수 있도록 하는 코드입니다.

 

<html>
<head>
    <script>
        function emailCheckForm(){
            var isCheckLessThanOne = true
            for(i = 1; i <= 6; i++){
                var idString = "check"+i
                var isChecked = $("#"+idString).is(':checked')
                console.log("check"+i,isChecked)
                if (isChecked){
                    isCheckLessThanOne = false
                    break
                }
            }
            console.log(isCheckLessThanOne)
            if($('#inputReceiver').val().length <= 0){
                alert("이메일 수신자를 1명 이상 입력해주세요.")
                $('#inputReceiver').focus()
                return false
            }else if($('#inputTitle').val().length <= 0){
                alert("이메일 제목을 입력해주세요.")
                $('#inputTitle').focus()
                return false
            }else{
                return true;
            }
        }
    </script>
</head>

<body>
    <div class="container">
        <div class="content">
            <div class="row">
            	<!-- 이메일 발송을 눌렀을 때 이를 처리하기 위한 경로로 가도록 설정하는 부분 -->
                <form action="./send/" method="POST" onsubmit="return emailCheckForm();">
                    {% csrf_token %}
                    <div class="emailDiv">
                        <div class="emailContentGroup">
                            <div class="emailContentHeader">
                                <h4>수신자 <span class="inputReceiverSub">콤마(,)로 구분해서 여러명에게 보낼 수 있습니다.</span></h4>
                                <input class="inputReceiver" name="inputReceiver" id="inputReceiver" type="text" placeholder="수신자를 적어주세요."/><br/>
                            </div>
                            <div class="emailContentHeader">
                                <h4>제목</h4>
                                <input class="inputTitle" name="inputTitle" id="inputTitle" type="text" placeholder="제목을 적어주세요."/><br/>
                            </div>
                            <div class="emailContent">
                                <h4>내용</h4>
                                <textarea class="inputContent" name="inputContent" id="inputContent" cols="50" rows="10" placeholder="내용을 적어주세요."></textarea>
                            </div>
                        </div>
                        <br>
                        <div>
                            <input type="submit" class="sendBtn btn btn-info" role="button" value="이메일 발송하기"/>
                        </div>
                    </div>
                </form>
            </div>
        </div>
    </div>
</body>
</html>

 

서버를 구동시키고 localhost/mail/ 로 url을 이동하면 index.html 파일이 연결되어서 띄워지는 것을 볼 수 있습니다.

그리고 수신자, 제목, 내용에 아무거나 작성하고 이메일 발송하기 버튼을 누르면

이러한 화면을 볼 수 있을 겁니다.

왜냐하면 index.html 파일에서 form 태그 부분의 action 값을 ./send로 채워주었기 때문입니다.


지금 views.py의 sendEmail 함수는 HttpResponse 함수를 통해 "sendEmail" 문자열을 출력하도록 되어있습니다.

이제 sendEmail 함수에 실제로 이메일을 발송하는 기능을 구현해야 합니다.

직접적인 기능 구현을 하기 전에 이메일을 발송한 후 메인 화면으로 돌아가는 처리를 먼저 진행합니다.

 

추가 설명

이것은 HttpResponseRedirect 함수와 reverse 함수를 이용하면 됩니다.

* 용어 설명
* reverse 함수를 통해 urls.py에 있는 네임스페이스를 통해 url을 찾습니다.
* HttpResponseRedirect 함수를 통해 해당 url로 이동합니다.
(예를 들어 urls.py에서 path('/name', views.name, name="namespace")

 

mail 앱의 views.py에 다음과 같이 sendEmail 함수를 수정합니다.

from django.shortcuts import render
from django.http import HttpResponse, HttpResponseRedirect
from django.urls import reverse

# Create your views here.
def index(request):
    return render(request, 'index.html')

def sendEmail(request):
    return HttpResponseRedirect(reverse('index'))
    # urls.py에서 namespace가 index인 url로 이동합니다.

 

이와 같이 함수를 구현하고 다시 이메일 발송하기 버튼을 클릭하면, 입력한 문자열이 사라지는 것 외에 아무 변화가 없는 것처럼 localhost/mail 부분의 화면이 보일 것입니다.


이제 django 프레임워크 자체적으로 제공하는 mail 관련 함수를 통해 메일 보내기 기능을 구현해보겠습니다.

(이메일 발송 기능을 구현하기 위해 smtplib라는 파이썬 라이브러리를 통해 이메일 발송 기능을 구현할 수도 있습니다.)

https://docs.djangoproject.com/en/2.2/topics/email/ 

 

Sending email | Django documentation | Django

Django The web framework for perfectionists with deadlines. Overview Download Documentation News Community Code Issues About ♥ Donate

docs.djangoproject.com

django 공식 홈페이지에서 확인하면 알 수 있듯이, django.core.mail이라는 것에서 send_mail 함수를 가져와 사용합니다.

여기서 주목할 것은 메일의 제목을 의미하는 subject, 메일의 본문을 의미하는 message, 발신자를 의미하는 from_email과 다수의 수신자를 입력할 수 있는 recipient_list입니다.

 

위의 사진에서 message에 대한 설명을 보면 '문자열'이라고 되어있습니다.

그런데 단순 문자열이 아니라 html 형식에 맞는 문자열로 메일 본문을 구성해야 합니다.

이를 해결하려면 django template에 있는 render_to_string이라는 함수를 사용해 html로 된 template를 문자열처럼 사용합니다.

 

sendEmail 함수를 다음과 같이 수정합니다.

from django.shortcuts import render
from django.http import HttpResponse, HttpResponseRedirect
from django.urls import reverse
from django.core.mail import send_mail, EmailMessage
from django.template.loader import render_to_string

# Create your views here.
def index(request):
    return render(request, 'index.html')

def sendEmail(request):
    # index.html에서 input 태그의 name 속성을 가져옵니다.
    inputReceiver = request.POST['inputReceiver']
    inputTitle = request.POST['inputTitle']
    inputContent = request.POST['inputContent']

    content = {'inputReceiver':inputReceiver, 'inputTitle':inputTitle, 'inputContent':inputContent}
    
    msg_html = render_to_string('email_format.html', content)

    msg = EmailMessage(subject=inputTitle, body=msg_html, from_email="djangoemailtester001@gmail.com", bcc=inputReceiver.split(','))
    msg.content_subtype = 'html'
    msg.send()
    return HttpResponseRedirect(reverse('index'))

필요한 함수를 위에서 import 해준 다음에 필요한 값들을 받아옵니다. (inputReceiver/inputTitle/inputContent)

html 파일에 해당 변수들을 사용할 수 있도록 content라는 딕셔너리형 변수에 담습니다.

그래서 render_to_string 함수에 html 파일과 같이 전달해줍니다.

 

이때 사용되는 html 파일을 mail 앱의 templates 폴더 안에 만들어주고, 해당 html 파일은 다음과 같이 구성해줍니다.

views.py의 sendEmail 함수에서 content 딕셔너리로 전달해 준 값들을 템플릿 태그를 사용하여 작성합니다.

(필요한 내용들만 표시되도록 간단하게 작성했습니다.)

# mail > templates > email_format.html
<html>
<head>
    <meta charset="UTF-8">
</head>
<body>
    <h1>{{inputTitle}}</h1>
    <p>{{inputContent}}</p>
</body>
</html>

 

다시 views.py의 sendEmail 함수 코드를 보면

msg = EmailMessage(subject=inputTitle, body=msg_html, from_email="djangoemailtester001@gmail.com", bcc=inputReceiver.split(','))

이 부분에서 EmailMessage 객체를 통해 메일의 제목이나 수신자, 발신자, 메일 본문을 구성하고, 이를 msg라는 변수로 받는 것을 확인할 수 있습니다.

이후 메일 본문이 html 인 것을 알려주려고 msg의 content_type을 html로 설정하고, send 함수를 호출한 뒤에 localhost/mail로 redirect 합니다.

 

이렇게 코드를 구성하고 메일 보내기를 시도하면 오류가 발생할 겁니다.

왜냐하면 메일을 보낼 때 사용하게 될 서버에 대해서 추가적인 설정이 없어서, django 서버에서는 자동으로 각자 컴퓨터 자체를 smtp 서버로 하여 메일을 발송하려 했을 것이기 때문입니다.

 

하지만 이에 대한 설정을 진행한 적이 없으므로 django가 메일을 발송하려고 할 때, 구글의 smtp 서버를 사용하도록 설정해주어야 합니다.

설정은 프로젝트 폴더 안에 있는 settings.py에서 진행합니다.

# Email settings
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_USE_TLS = True
EMAIL_PORT = 587
EMAIL_HOST_USER = '본인이메일입력@gmail.com'
EMAIL_HOST_PASSWORD = '이메일비번입력'

 

EMAIL_HOST_USER와 EMAIL_HOST_PASSWORD에는 개인 구글 계정과 비밀번호를 입력하면 됩니다.


하지만 이와 같이 코드를 구현하더라도 구글 측에서 외부 특정 계정에 접근하는 것에 대해 보안을 걸어 두었기 때문에 오류가 발생합니다.

이 오류는 계정 설정에서 해결이 가능합니다.

 

구글 로그인을 한 후에 우측 상단에 동그라미를 누르면 Google 계정 관리 버튼이 보일 겁니다.

 

들어가면 다음과 같은 목록이 보일 텐데 보안을 누르고 아래로 내리다 보면 보안 수준이 낮은 앱의 액세스 항목을 볼 수 있습니다.

여기서 이제 액세스 사용 설정(권장하지 않음)을 클릭하고 보안 수준이 낮은 앱 허용: 사용으로 되도록 합니다.

 

이렇게 설정되었으면 구글 계정에 대한 준비는 마무리되었고 다시 이메일 보내기를 시도하면 정상적으로 발송됩니다.

댓글