DjangoアプリケーションにCustomers Mail Cloudを使ってメール送信機能を実装する

DjangoはPython製のWebアプリケーションフレームワークになります。Python向けに、Customers Mail Cloudライブラリがあります(非公式、サポート対象外です)ので、今回はこれを使ってDjangoアプリケーションにお問い合わせフォーム機能を追加してみます。コードはDjangoでお問い合わせフォームを作成する. Django フォーム + Bootstrap 4… | by Koji Mochizuki | Mediumを参考にしています。

ファイル構成

ファイルは次のような構成になっています。作成は新規作成したファイルやフォルダ、編集はDjangoのプロジェクトを生成後、編集したファイルになります。

$ tree . -I "*.pyc"
.
├── db.sqlite3
├── manage.py
├── mysite
│   ├── __init__.py
│   ├── __pycache__
│   ├── asgi.py
│   ├── forms.py                   # 作成
│   ├── settings.py                # 編集
│   ├── urls.py                    # 編集
│   ├── views.py                   # 作成
│   └── wsgi.py
└── templates                      # 作成
    ├── base.html
    └── contact
        ├── contact_form.html
        └── contact_result.html

各ファイルについて

まずHTMLテンプレートです。

base.htmlについて

ここではBootstrapを読み込んで、HTMLの外枠を作成している程度です。

<!-- templates/base.html -->
{% load static %}
<html>
    <head>
        <title>Django Girls blog</title>
        <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
        <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css">
        <link href='//fonts.googleapis.com/css?family=Lobster&subset=latin,latin-ext' rel='stylesheet' type='text/css'>
    </head>
    <body>
        <div class="page-header">
            <h1><a href="/">Django Contact form</a></h1>
        </div>

        <div class="content container">
            <div class="row">
                <div class="col-md-8">
                  {% block content %}
                  {% endblock %}
                </div>
            </div>
        </div>
    </body>
</html>

contact/contact_form.htmlについて

f:id:moongift:20210916143231j:plain

お問い合わせフォームです。フォームの各要素はPythonで生成しています(後述)。

<!-- templates/contact/contact_form.html -->
{% extends "base.html" %}

{% block content %}
<div class="container">
  <div class="row">
    <div class="col-md-8">
      <h1>お問い合わせ</h1>
      <p>お問い合わせフォームです。</p>
      <form method="POST">{% csrf_token %}
        {{ form.as_p }}
        <button type="submit" class="btn btn-primary">送信</button>
      </form>
    </div>
  </div>
</div>
{% endblock %}

contact/contact_result.htmlについて

f:id:moongift:20210916143257j:plain

お問い合わせ完了画面です。

<!-- templates/contact/contact_result.html -->
{% extends "base.html" %}

{% block content %}
<div class="container">
  <div class="row">
    <div class="col-md-8">
      <h1>お問い合わせ</h1>
      <p>お問い合わせありがとうございます。返信をお待ちください。</p>
    </div>
  </div>
</div>
{% endblock %}

settings.pyについて

これはあらかじめ生成されているファイルを編集しています。内容としては、osのインポートに加えて、DIRSにテンプレートディレクトリのパスを指定しています。

# mysite/settings.py
import os
  :
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],

urls.pyについて

ルーティングを2つ追加しています。 /contact へアクセスした際に問い合わせフォームを表示するのと、 /contact/result/ がお問い合わせ完了画面への遷移になります。

# mysite/urls.py
from django.contrib import admin
from django.urls import path
from .views import ContactFormView, ContactResultView

urlpatterns = [
    path('admin/', admin.site.urls),
    # 追加
    path('contact/', ContactFormView.as_view(), name='contact_form'),
    # 追加
    path('contact/result/', ContactResultView.as_view(), name='contact_result'),
]

views.pyについて

views.pyは各ルーティングに対してViewを表示します。基本的にはテンプレートを読み込んで、そのまま表示しています。

# mysite/views.py
from django.urls import reverse_lazy
from django.views.generic import TemplateView
from django.views.generic.edit import FormView

from .forms import ContactForm


class ContactFormView(FormView):
    template_name = 'contact/contact_form.html'
    form_class = ContactForm
    success_url = reverse_lazy('contact_result')

    def form_valid(self, form):
        form.send_email()
        return super().form_valid(form)


class ContactResultView(TemplateView):
    template_name = 'contact/contact_result.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['success'] = "お問い合わせは正常に送信されました。"
        return context

forms.pyについて

forms.pyはお問い合わせフォームの内容を表示しています。ここでは、まず CustomersMailCloud を読み込んでいます。そのためのライブラリはpipでインストールできます。

pip3 install requests
pip3 install CustomersMailCloud

そしてライブラリを読み込みます。

# mysite/forms.py
from django import forms
from django.conf import settings
from django.core.mail import BadHeaderError, send_mail
from django.http import HttpResponse
from CustomersMailCloud.Client import CustomersMailCloud

ContactFormでは、まずフォームの内容を定義しています。そして、フォーム送信した際には send_email が呼ばれます。

# mysite/forms.py
class ContactForm(forms.Form):
    name = forms.CharField(
        label='',
        max_length=100,
        widget=forms.TextInput(attrs={
            'class': 'form-control',
            'placeholder': "お名前",
        }),
    )
    email = forms.EmailField(
        label='',
        widget=forms.EmailInput(attrs={
            'class': 'form-control',
            'placeholder': "メールアドレス",
        }),
    )
    message = forms.CharField(
        label='',
        widget=forms.Textarea(attrs={
            'class': 'form-control',
            'placeholder': "お問い合わせ内容",
        }),
    )

    def send_email(self):

send_email の内容です。 CustomersMailCloud ライブラリを使ってメール送信を行います。

def send_email(self):
    # Customers Mail CloudのAPIユーザとキーで初期化
    client = CustomersMailCloud('YOUR_APPLICATION_USER', 'YOUR_APPLICATION_KEY')
    client.trial() # 契約によって呼び出すメソッドが異なります
    # 宛先の追加
    client.addTo(self.cleaned_data['name'], self.cleaned_data['email'])
    # Fromの設定
    client.setFrom('FROM_NAME', 'FROM_ADDRESS')
    # 件名の設定
    client.subject = 'お問い合わせがありました'
    # 本文の設定
    client.text = self.cleaned_data['message']
    try:
        # メール送信
        client.send()
    except BadHeaderError:
        return HttpResponse(e)

テストする

お問い合わせフォームをテストして、メール送信できるか確認します。

f:id:moongift:20210916143341j:plain

まとめ

Customers Mail Cloudのpipライブラリを使うことで、Djangoアプリケーションの中にメール送信機能を簡単に実装できます。お問い合わせに限らず、ユーザアクションに対するレスポンスなど、色々な場面で利用してください。

クラウドからのメール送信を簡単に。確実に。| Customers Mail Cloud