본문 바로가기

Web/Django

[Django] 특정 시간에 자동으로 메일 보내기

매일 오전 7시에 메일을 보내줘야하는 기능을 구현하려 한다.

 

열심히 구글링을 한 결과 crontab을 사용해보려고 한다.

 

 

그런데 Windows에서는 crontab 사용이 불가능하다고 한다...

 

다시 구글링을 한 결과

 

APScheduler(Advanced Python Scheduler)라는 것을 찾아냈다.

 

일단 설치를 해줬다.

 

 

pip install apscheduler

 

 

잘 설치가 된 것 같다.

 

이제 settings.py 에 설정을 입력해준다.

 

 

#myproject/myproject/settings.py

INSTALLED_APP = [
	...
    'django_apscheduler',
    ...
]

APSCHEDULER_DATETIME_FORMAT = "N j, Y, f:s a"  # Default

SCHEDULER_DEFAULT = True

 

 

근데 노란줄이 쳐지면서 없는 모듈이라는 얘기를 한다.

 

또 다시 구글링을 한 결과

 

 

 

pip install django-apscheduler

 

 

위와 같이 설치를 해야한다. APScheduler 말고 다른 라이브러리도 같이 설치되는 것 같은데 뭔지는 잘 모르겠다.

 

설치를 하고나니 노란줄이 사라졌다.

 

이제 작동될 코드를 만들어 봐야겠다.

 

기본적으로 메일을 보낼 것이니 mail앱 내에, 즉 myproject/mail 아래에서 돌아가도록 만들 것이다.

 

 

 

# myproject/mail/views.py

...
from django.conf import settings
import datetime
...

def send_mail():
    #날짜 셋팅
    now = datetime.datetime.now()
    nowDate = now.strftime('%Y-%m-%d')
    date = nowDate.split('-')
    subject = '[자동]' + date[0] + '년 ' + date[1] + '월 ' + date[2] + '일 메일을 보냅니다.'
    all_post = Post.objects.all()
    todaylist = []

    for post in all_post:
        todaylist.append(post)
        if str(post.pub_date) < str(now - datetime.timedelta(1)):
            break
    
    for post in todaylist:
        writer = post.account
        to = [writer.email for writer in writer.subscribed.all()]
        context = post.content
        today_mail = EmailMessage(subject=subject, body=context, from_email = settings.DEFAULT_FROM_EMAIL, to=to)
        today_mail.send()

 

 

날짜 셋팅은 별로 의미는 없다.

 

보내는 시간 기준 24시간 전부터 지금까지의 글을 보내기 위해서 위와 같이 설정했다.

 

이제 send_mail이 실행되도록 operator.py를 만들어 줄 것이다.

 

 

 

# myproject/mail/operator.py

from datetime import datetime
from apscheduler.schedulers.background import BackgroundScheduler
from django.conf import settings
from apscheduler.executors.pool import ProcessPoolExecutor, ThreadPoolExecutor
from django_apscheduler.jobstores import register_events, DjangoJobStore
import time
from .views import send_mail


def start():
    scheduler=BackgroundScheduler()
    scheduler.add_jobstore(DjangoJobStore(), 'djangojobstore')
    register_events(scheduler)
    @scheduler.scheduled_job('cron', minute = '*/5', name = 'auto_mail')
    def auto_mail():
        send_mail()
    scheduler.start()

 

 

위 설정에서는 일단 잘 날아가는지 확인하기 위해서 'cron' 설정을 minute = '*/5'로 했다.

위와 같이 설정하면 5배수분에 작동한다.

 

그리고 마지막으로 apps.py에서 시작 설정을 해준다.

 

 

 

#myproject/mail/apps.py

from django.apps import AppConfig
from django.conf import settings

class MailConfig(AppConfig):
    name = 'mail'

    def ready(self):
        if settings.SCHEDULER_DEFAULT:
            from . import operator
            operator.start()

 

 

 

settings.py에서 SCHEDULER_DEFAULT = True로 해준 이유가 자동으로 시작하란 뜻이다.

False로 해놓으면 스케쥴러가 작동하지 않는다.

 

전부 설정한 듯 하다. 이제 잘 되는지 확인을 해본다.

 

 

 

python manage.py runserver

 

 

 

에러가 난다.

 

INSTALLED_APP에 MailConfig가 없다. 그냥 'mail'로 앱을 등록해놓았다.

 

 

 

#myproject/myproject/settings.py

INSTALLED_APP = [
	...
    'MailConfig',
    ...
]

 

 

 

다시 runserver를 해본다.

 

서버는 돌아간다.

 

근데 문제점이 생겼다.

 

메일이 엄청나게 많이온다. 똑같은 메일들이 수십통씩 온다. 이유를 알 수가 없다.

 

Scheduler를 수정해본다.

 

BackgroundScheduler를 BlockingScheduler로 바꿔보았다.

 

다시 runserver를 해보았다.

 

한통씩 날아오기 시작했다! 근데 서버가 켜지지 않고 메일만 날아온다! 이건 쓸 수가 없다.

 

BlockingScheduler는 단일 스케쥴러라고 한다.

 

다시 BackgroundScheduler로 바꿔주고 서버를 돌릴 때 다음과 같이 실행한다.

 

 

 

python manage.py runserver --noreload

 

 

차분하게 메일을 기다려보니 메일이 한통씩 온다.

 

뭔가 성공한 것 같은데 무작정 코드만 땡겨와서 성공시킨 것이라 되고 안되고의 이유를 전혀 모르겠다.

 

공부해봐야겠다.

'Web > Django' 카테고리의 다른 글

[Django] Riot API로 전적조회 사이트 만들기 - 1  (0) 2020.10.07