ほんじゃら堂

めんどくさい仕事をラクにする作業自動化レシピ集

フォームデータのメール送信をバッチで処理する

Webフォームから送信されたデータを保存後にメールでユーザーやら担当者やらに送信する処理が必要な事が多い。
メール送信処理は結構重いので、リクエスト中に送信するのではなく、後でバッチ処理で送信する処理を作ってみた。


送信するメールを保存するモデルはこんな感じ

# -*- coding: utf-8 -*-
from datetime import datetime
from django.db import models
from django.core.mail import send_mail
# Create your models here.
class SendMail(models.Model):
sender = models.CharField("送信元メールアドレス", max_length=255)
recipients = models.TextField("送信先メールアドレス", help_text="1行に1つメールアドレスを入力してください")
title = models.CharField("メールタイトル", max_length=255)
contents = models.TextField("メール内容")
is_sended = models.BooleanField("送信済み")
insert_date = models.DateTimeField("登録日", auto_now_add=True)
sended_date = models.DateTimeField("送信日", blank=True, null=True)
def get_recipient_list(self):
recipient_list = self.recipients.split("\n")
return recipient_list
def set_recipient_list(self, recipient_list):
self.recipients = "\n".join(recipient_list)
def send(self):
send_mail(self.title, self.contents, self.sender, self.get_recipient_list(), fail_silently=True)
self.is_sended = True
self.sended_date = datetime.now()
self.save()
class Meta:
verbose_name = "送信メール"
verbose_name_plural = "送信メール"
ordering = ["-insert_date"]
def __unicode__(self):
return self.title


メールを生成するユーティリティ関数も作っておく。
メールテンプレートからメールを生成するようにしてやる。
utils.pyとかで作る。

from django.conf import settings
from django.core.mail import send_mail
from django.template.loader import render_to_string
from batchmail.models import SendMail
def create_mail_from_template(subject, body_template_path="", body_values={}, recipients=[], sender=settings.DEFAULT_FROM_EMAIL):
message = render_to_string(body_template_path, body_values)
mail = SendMail()
mail.sender = sender
mail.set_recipient_list(recipients)
mail.title = subject
mail.contents = message
mail.is_sended = False
mail.save()
return mail


下記のような感じでフォーム内容の保存後にメールを保存する。

...
mail = create_mail_from_template(mail_title,
"mailform/mail_message.txt",
form_data,
[form_data["admin_mail"]])
...


メールの送信は、下記のようなスクリプトを作成して程良い間隔でcronで呼び出す。

# -*- coding: utf-8 -*-
# 送信待ちのメールを送信します
import sys
import socket
if socket.gethostname() == "xxxxxxxx.com":
HOME_PATH = "/path_to_server_project"
else:
HOME_PATH = "/path_to_local_project"
sys.path.append(HOME_PATH)
from django.core.management import setup_environ
from batchmail import settings
setup_environ(settings)
from batchmail.models import SendMail
def main():
waiting_mail_list = SendMail.objects.filter(is_sended=False)
for mail in waiting_mail_list:
mail.send()
if __name__ == "__main__":
main()


ちょっとしたメール送信処理ならこれでまかなえるかな。
フォームに依存しないので、複数のフォームからのメール送信もできそう。