February 7, 2021
←前回:Day 28 サイトマップを作成する
「Djangoを学びたい」とのことでありましたら[Day 1]Djangoの開発環境から読むことをおすすめします。
#はじめに
ウェブアプリケーションではメールの送信は良くあるアクションの1つですね。今回はDjangoの機能を用いてメール送信する処理を見ていこうと思います。
#メールバックエンドについて
メールの送信処理はメールバックエンドによって処理されます。メールバックエンドにはいくつか種類があり、目的に応じて使わけます。まず、開発時に試験的に(実際にメールを送信せず)送信テストをしたい場合はコンソールバックエンドの使用をオススメします。これはメールをコンソールに出力するのみで、送信しません。またファイルバックエンドもファイルに出力するのみで実際には送信しません。メールバックエンドは独自のものを使用することもできますが多くの場合はSMTPバックエンドを使用する機会が多いと思いますので、今回は開発環境ではコンソールバックエンド、送信用にはSMTPバックエンドを使用していきます。
#メールバックエンドの設定
まずはmysite/settings.pyにて設定を行います。
+ EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
まずは開発用にコンソールバックエンドを指定しました。ではトピックの追加された場合にメールを送信する処理を行いましょう。
+ from django.core.mail import send_mail, EmailMessage
class TopicCreateView(CreateView):
template_name = 'thread/create_topic.html'
form_class = TopicModelForm
model = Topic
success_url = reverse_lazy('base:top')
def form_valid(self, form):
ctx = {'form': form}
if self.request.POST.get('next', '') == 'confirm':
ctx['category'] = form.cleaned_data['category']
return render(self.request, 'thread/confirm_topic.html', ctx)
elif self.request.POST.get('next', '') == 'back':
return render(self.request, 'thread/create_topic.html', ctx)
elif self.request.POST.get('next', '') == 'create':
+ # メール送信処理
+ send_mail(
+ subject='トピック作成: ' + form.cleaned_data['title'],
+ message='トピックが生成されました。',
+ from_email='hogehoge@example.com',
+ recipient_list = [
+ 'admin@example.com',
+ ]
+ )
return super().form_valid(form)
else:
# 正常動作ではここは通らない。エラーページへの遷移でも良い
return redirect(reverse_lazy('base:top'))
ここで用いたsend_mail関数はEmailMessageのラッパーで、単順なメール送信では重宝します。タイトル、本文、送信アドレス、受診アドレスを設定します。ではトピック作成してメールがコンソールに出力されるか見てみましょう。
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
Subject:
=?utf-8?b?44OI44OU44OD44Kv5L2c5oiQOiDntKDmlbXjgarjg4vjg6Pjg7PjgrPjga7kuJY=?=
=?utf-8?b?55WM?=
From: hogehoge@example.com
To: admin@example.com
Date: Wed, 20 Mar 2019 07:58:17 -0000
Message-ID: <155306869746.10086.12768691481838639735@arch.localdomain>
トピックが生成されました。
-------------------------------------------------------------------------------
このように出力されます。
テンプレートを使う
多くのウェブサービスではメール用のテンプレートを用意しておいて変数化された部分のみ変更してメール送信する処理も多いと思います。直接のメール機能というわけではないですが、紹介しておきたいと思います。まずはテンプレートファイルを生成します。
以下のトピックが登録されました。
---------------------
タイトル: {{title}}
ユーザー名: {{user_name}}
本文:
{{message}}
+ from django.core.mail import send_mail, EmailMessage
+ from django.template.loader import get_template
class TopicCreateView(CreateView):
template_name = 'thread/create_topic.html'
form_class = TopicModelForm
model = Topic
success_url = reverse_lazy('base:top')
def form_valid(self, form):
ctx = {'form': form}
if self.request.POST.get('next', '') == 'confirm':
ctx['category'] = form.cleaned_data['category']
return render(self.request, 'thread/confirm_topic.html', ctx)
elif self.request.POST.get('next', '') == 'back':
return render(self.request, 'thread/create_topic.html', ctx)
elif self.request.POST.get('next', '') == 'create':
+ # メール送信処理
+ template = get_template('thread/mail/topic_mail.html')
+ mail_ctx={
+ 'title': form.cleaned_data['title'],
+ 'user_name': form.cleaned_data['user_name'],
+ 'message': form.cleaned_data['message'],
+ }
+ send_mail(
+ subject='トピック作成: ' + form.cleaned_data['title'],
+ message=template.render(mail_ctx),
+ from_email='hogehoge@example.com',
+ recipient_list = [
+ 'admin@example.com',
+ ]
+ )
return super().form_valid(form)
else:
# 正常動作ではここは通らない。エラーページへの遷移でも良い
return redirect(reverse_lazy('base:top'))
このようにテンプレートのレンダリングを用いることでコンテキストをテンプレートに渡してメール本文を作成することができます。
[出力例]
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
Subject:
=?utf-8?b?44OI44OU44OD44Kv5L2c5oiQOiDntKDmlbXjgarjg6/jg7PjgrPjga7kuJbnlYw=?=
From: hogehoge@example.com
To: admin@example.com
Date: Wed, 20 Mar 2019 08:09:26 -0000
Message-ID: <155306936665.10237.4864318700173116195@arch.localdomain>
以下のトピックが登録されました。
---------------------
タイトル: 素敵なワンコの世界
ユーザー名: 名無し
本文:
ようこそ。ワンコの世界へ
-------------------------------------------------------------------------------
#EmeilMessageオブジェクトを使用してメールを送信する
冒頭で書いた通りsend_mail関数はEmailMessageのラッパーです。CCやBCCを使う等の複雑な処理はEmailMessageオブジェクトを使用します。
+ from django.core.mail import send_mail, EmailMessage
class TopicCreateView(CreateView):
template_name = 'thread/create_topic.html'
form_class = TopicModelForm
model = Topic
success_url = reverse_lazy('base:top')
def form_valid(self, form):
ctx = {'form': form}
if self.request.POST.get('next', '') == 'confirm':
ctx['category'] = form.cleaned_data['category']
return render(self.request, 'thread/confirm_topic.html', ctx)
elif self.request.POST.get('next', '') == 'back':
return render(self.request, 'thread/create_topic.html', ctx)
elif self.request.POST.get('next', '') == 'create':
+ # メール送信処理
+ template = get_template('thread/mail/topic_mail.html')
+ mail_ctx={
+ 'title': form.cleaned_data['title'],
+ 'user_name': form.cleaned_data['user_name'],
+ 'message': form.cleaned_data['message'],
+ }
+ EmailMessage(
+ subject='トピック作成: ' + form.cleaned_data['title'],
+ body=template.render(mail_ctx),
+ from_email='hogehoge@example.com',
+ to=['admin@example.com'],
+ cc=['admin2@example.com'],
+ bcc=['admin3@example.com'],
+ ).send()
return super().form_valid(form)
else:
# 正常動作ではここは通らない。エラーページへの遷移でも良い
return redirect(reverse_lazy('base:top'))
トピックを追加してみましょう。
[出力例]
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
Subject:
=?utf-8?b?44OI44OU44OD44Kv5L2c5oiQOiDntKDmmbTjgonjgZfjgY1weXRob27jga7kuJY=?=
=?utf-8?b?55WM?=
From: hogehoge@example.com
To: admin@example.com
Cc: admin2@example.com
Date: Wed, 20 Mar 2019 08:29:19 -0000
Message-ID: <155307055904.10506.3851232136327226257@arch.localdomain>
以下のトピックが登録されました。
---------------------
タイトル: 素晴らしきpythonの世界
ユーザー名: 名無し
本文:
ようこそ。pythonの世界へ
-------------------------------------------------------------------------------
#SMTPバックエンドでメールを送信する
ここで本家では、MailCatcherを用いてメールを送信しています。
私は時間がなく、やるのをやめました(後で、戻ってきます)
今回はこれで終わりです。
#終わりに
勉強ってするだけ得ですよね。
私は学業の方は中の下かそれ以下なんですが、勉強自体は嫌いではありません。
Djangoだって勉強な訳ですし。
なので、私はまだ21なんですけど、若い人たちには「学校の勉強は嫌いになっても、勉強自体は嫌いにならないでください」と言いたい(AKBが好きな訳ではないです)
それではまたまた