naritoブログ

このブログはPython/DjangoとBootstrap4で作成されました
Githubのソースコード

Djangoで、メール通知アプリを作る

約228日前 2017年12月31日16:22
プログラミング関連
Django Python
今回はちょっとしたメール通知アプリを作ります。

まず、管理画面でこのようにスケジュールを登録し...


以下のようなコマンドを入力すると、メールの送信が開始されます。
python manage.py mail



メールの送信が終わると、送信済みと表示されるようにしました。



今回は管理画面からのデータ追加と、Djangoのカスタムコマンドを作成するだけなので、ビューやテンプレートは作りません。
まず、models.py
from django.conf import settings
from django.db import models
from django.utils import timezone


class To(models.Model):
    """連絡先"""

    email = models.EmailField('メールアドレス')
    name = models.CharField('名前', max_length=255)
    created_at = models.DateTimeField('作成日', default=timezone.now)

    def __str__(self):
        return '{0}({1})'.format(self.name, self.email)


class Schedule(models.Model):
    """通知スケジュール"""

    datetime = models.DateTimeField('連絡日・時間')
    subject = models.CharField('題名', max_length=255)
    text = models.TextField('本文')
    mail_from = models.EmailField('From', default=settings.EMAIL_HOST_USER)
    mail_to = models.ManyToManyField(To, verbose_name='To')
    is_sended = models.BooleanField('送信済みフラグ', default=False)
    created_at = models.DateTimeField('作成日', default=timezone.now)

    def __str__(self):
        message = '{0} {1}'
        sended = '送信済み' if self.is_sended else '未送信'
        return message.format(self.subject, sended)





連絡先は、一度登録したら使いまわせるようにモデルにしました。Toモデルです。それをManyToManyで紐付けます。
Scheduleモデルは、連絡する日・時間と、メールの題名、本文、送信元、送信先、送信フラグ、といったフィールドをもたせます。

今回はappというアプリケーション名です。appフォルダ内に、「management」フォルダを作ります。その中に「commands」フォルダを作り...
そして、mail.pyを以下のように作ります。
import time
from django.core.management.base import BaseCommand
from django.core.mail import send_mail
from django.utils import timezone
from app.models import Schedule


def _send_mail(schedule):
    """メールの送信処理"""
    # 送信者達
    recipient_list = [to.email for to in schedule.mail_to.all()]

    # メールの送信
    send_mail(schedule.subject, schedule.text, schedule.mail_from, recipient_list)


class Command(BaseCommand):
    def handle(self, *args, **options):
        while True:
            now = timezone.now()
            schedule_list = Schedule.objects.filter(datetime__lte=now, is_sended=False)
            for schedule in schedule_list:
                    _send_mail(schedule)
                    schedule.is_sended = True
                    schedule.save()
            time.sleep(10)




コマンドの実行で、handleメソッドが呼ばれます。
handleメソッド内では、未送信で今現在を過ぎているScheduleを取得します。
それをfor文で順番に取り出し、メールを送信し、送信済みフラグをTrueにし、time.sleep(10)で10秒ほど待機します。
whileでの無限ループなので、10秒毎にこの処理を繰り返します。

cron等を使うのもよさそうですが、今回は無限ループの中で10秒毎に送信メールがあるかを確認する、という方法を使いました。
Gmailを使いましたが、この場合はsettings.pyに設定を記述します。
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_HOST_USER = 'toritoritorina@gmail.com'
EMAIL_HOST_PASSWORD = パスワードを入れる。2段階認証をしておかないと、弾かれることがあります
EMAIL_USE_TLS = True



メールの題名、本文はテンプレートを使って組み立てることもできます。
関連記事の「Djangoで、メール送信」に書いています。