Djangoでsend_mailを使ってみた！！

## はじめに
　こんにちは。@toamoku-20220418と申します。現在Djangoを使用したアプリケーションの作成を目標に、勉強を進めております。
　今回はsend_mailを使用し、ユーザー認証にsend_mailを使用できるように、まずsend_mail単体で簡単なアプリケーションを作成したいと思います。
　ぜひ最後までご覧いただき、皆さんの参考になれば幸いです。
## 前提条件
　開発環境はmacを使用しております。またpythonやDjangoについての詳細の解説は省いております。今回の開発ではメールの内容をコンソールに表示する設定にしております。またディレクトリやファイルの作成に必要なLinux関係のコマンドも省いております。ご了承ください。
## 実現したいこと
1. send_mailを使用して、メールを送れるようになる
2. メール送信画面を作成し、そこで入力を行う。送信ボタンを押すとコンソールにメールが送られる
3. メール送信に関してメッセージが表示されるようにする
## Djangoでプロジェクトを作成
ホームディレクトリでprojectディレクトリを作成し、projectディレクトリへ移動。
```bash
myprojectディレクトリを作成
$ mkdir myproject
myprojectディレクトリへ移動
$ cd myproject
```
仮想環境を作成し、Djangoをインストール
```bash
 ※ virtualenvの場合
仮想環境を作成
$ virtualenv mailenv

仮想環境を有効化
$ source mailenv/bin/activate
```
Djangoのprojectディレクトリとアプリケーションの作成
```bash
※ 先にprojectディレクトリを作成しているので、最後にドットを付与
プロジェクトを作成
$ django-admin startproject mailproject . 

アプリケーションを作成
$ python manage.py startapp mailapp
```
settings.pyにmailappを追加
```python:mailproject/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'mailapp' # ここを追加
]
```
## ホーム画面の作成
最初にホーム画面を作成します。urls.pyにルーテングを設定します。
```python:mailproject/urls.py
from django.contrib import admin
from django.urls import path, include　# includeを追加

urlpatterns = [
    path('admin/', admin.site.urls),
    # admin/以外のPATHはmailappのurls.pyから行う
    path('', include('mailapp.urls'))
]
```
続いてmailappのurls.pyにルーティングを設定します。
```python:mailapp/urls.py
from django.urls import path
from . import views

urlpatterns = [
    path('', views.home, name='home')
]
```
ホーム画面を表示するviews.pyを作成します。
```python:mailapp/views.py
from django.shortcuts import render

def home(request):
  return render(request, 'home.html')
```
続いてHTMLファイルを格納するtemplatesディレクトリを作成します。
```bash
mkdir templates
```
home.htmlを作成します。
```html:templates/home.html
<h1>home<h1>
```
settings.pyにtemplatesを登録します。
```python:mailproject/settings.py
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR / 'templates'], # ここに追加
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]
```
ホーム画面が表示されるか、一旦確認
サーバーを起動
```bash
$ python manage.py runserver
```
その後ブラウザでlocalhost:8000にアクセスし「home」と表示されれば成功です。
## send_mailの作成
メールをコンソールに表示するため、settings.pyを編集します。
```python:mailproject/settings.py
# 下記を追加
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
```
メール用のモデルを作成します。
```python:mailapp/models.py
from django.db import models

class MailModel(models.Model):
    subject = models.CharField(max_length=50) # メールの件名
    message = models.TextField() # メール本文
    from_email = models.EmailField(max_length=254) # 送信元メールアドレス
    recipient_email = models.EmailField(max_length=255) # 宛先メールアドレス　
```
続いてforms.pyを作成
```python:mailapp/forms.py
from django import forms
from .models import MailModel

class MailForm(forms.ModelForm):
    subject = forms.CharField(label='件名') # メールの件名
    message = forms.CharField(label='本文', widget=forms.Textarea) # メール本文
    from_email = forms.EmailField(label='送信元メールアドレス') # 送信元メールアドレス
    recipient_email = forms.EmailField(label='宛先メールアドレス') # 宛先メールアドレス
    
    class Meta:
        model = MailModel
        fields = ('subject', 'message', 'from_email', 'recipient_email')
```
今度はviews.pyを作成します
```python:mailapp/views.py
from django.shortcuts import render, redirect # redirectを追加
from django.core.mail import send_mail
from .forms import MailForm
from django.contrib import messages

def home(request):
    return render(request, 'home.html')

def send_test_email(request):
    if request.method == 'POST':
        form = MailForm(request.POST)
        if form.is_valid():
            subject = form.cleaned_data['subject']
            message = form.cleaned_data['message']
            from_email = form.cleaned_data['from_email']
            recipient_email = form.cleaned_data['recipient_email']
            
            send_mail(subject, message, from_email, [recipient_email])
            messages.success(request, 'コンソールにメールを送信しました')
            
            return redirect('home') # メール送信後、ホーム画面へリダイレクト
        else:
            messages.error('入力に誤りがあります。')
    else:
        form = MailForm()
    return render(request, 'send_test_email.html', {'form': form})
```
send_test_mailのルーティングを設定します。
```python:mailapp/views.py
from django.urls import path
from . import views

urlpatterns = [
    path('', views.home, name='home'),
    path('send_email/', views.send_test_email, name='send_email'),
]
```
続いてメール送信画面のsend_test_mail.htmlを作成します。
```html:templates/send_test_email.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>メール送信</h1>
    <form method="POST">
        {% csrf_token %}
        {{ form.as_p }}
        <button type='submit'>送信</button>
    </form>
    <p><a href="{% url 'home' %}">ホームへ</a></p>
</body>
</html>
```
home.htmlにメール送信画面へのリンクとメッセージが表示されるように編集します。
```html:templates/home.html
<h1>home</h1>
<!-- ここから下を追加 -->
{% if messages %}
<ul>
    {% for message in messages %}
    <li>{{ message }}</li>
    {% endfor %}
</ul>    
{% endif %}
<p><a href="{% url 'send_email' %}">メール送信画面へ</a></p>
```
これで一旦動作確認を行います。
1. ブラウザを使用し、localhost:8000へアクセス
2. メール送信画面へ移動し、フォームの情報を入力
3. 送信ボタンをクリックし、ホーム画面へリダイレクト
4. ホーム画面に「コンソールにメールを送信しました」とメッセージが表示されれば成功
5. コンソールを確認し、件名や本文、送信元や宛先のアドレスなどが入力の通り表示されていればオッケー
:::note
件名の部分は日本で入力すると、私の場合は文字化けしました。英語で入力するとそのまま表示されるので、英語を使用するのがいいと思います。
:::
## 複数にメールを送るにはどうするのか
 最初に送り先が１件の場合で作成しましたが、複数に送る場合はどうすればいいのでしょうか。
 私が考えた結果、モデルをTextFieldで作成します。フォームはCharFieldで作成し、ウィジェットにTextareaを使用する方法です。入力はカンマ区切りでそれをリストに変換します。
 考えたコードはこのようになりました。
 最初にモデルを変更します
```python:mailapp/models.py
from django.db import models

class MailModel(models.Model):
    subject = models.CharField(max_length=50) # メールの件名
    message = models.TextField() # メール本文
    from_email = models.EmailField(max_length=254) # 送信元メールアドレス
    # recipient_email = models.EmailField(max_length=255) # 宛先メールアドレス　
    recipient_list = models.TextField() # 宛先メールアドレス(複数の場合)
```
続いてフォームを修正
```python:mailapp/forms.py
from django import forms
from .models import MailModel

class MailForm(forms.ModelForm):
    subject = forms.CharField(label='件名') # メールの件名
    message = forms.CharField(label='本文', widget=forms.Textarea) # メール本文
    from_email = forms.EmailField(label='送信元メールアドレス') # 送信元メールアドレス
    # recipient_email = forms.EmailField(label='送信先メールアドレス') # 1件用
    recipient_list = forms.CharField(
        label='宛先メールアドレス', widget=forms.Textarea, help_text='メールアドレスはカンマで区切って入力してください'
        ) # ここを追加
    
    class Meta:
        model = MailModel
        fields = ('subject', 'message', 'from_email', 'recipient_list') # recipient_listに変更
```
views.pyを修正
```python:mailapp/views.py
from django.shortcuts import render, redirect
from django.core.mail import send_mail
from .forms import MailForm
from django.contrib import messages

def home(request):
    return render(request, 'home.html')

def send_test_email(request):
    if request.method == 'POST':
        form = MailForm(request.POST)
        if form.is_valid():
            subject = form.cleaned_data['subject']
            message = form.cleaned_data['message']
            from_email = form.cleaned_data['from_email']
            # recipient_email = form.cleaned_data['recipient_email'] 1件用
            recipient_list = form.cleaned_data['recipient_list']

            send_mail(subject, message, from_email, [recipient_list]) # recipient_listに変更
            messages.success(request, 'コンソールにメールを送信しました')
            
            return redirect('home') # メール送信後、ホーム画面へリダイレクト
        else:
            messages.error('入力に誤りがあります。')
    else:
        form = MailForm()
    return render(request, 'send_test_email.html', {'form': form})
```
このようにすれば、宛先メールアドレス入力部分がテキストエリアになり、そこにカンマ区切りで複数の宛先にメールを送ることが可能になります。

:::note
この場合、フォームでのバリデーションがメールアドレスにならないため、文字列でも送ることが出来てしまいます。その場合、実環境ではエラーメールとなるので、そちらで確認するしかないかもしれません。
:::

## 最後に
 最後までご覧いただきありがとうございます。この記事が皆様に少しでもお役に立てることを祈っております。これからも色々な記事を投稿していきますので、お付き合いいただければと思います。これからもよろしくお願いします。