Djangoで件名や本文の違うメールを一括送信する

# これはなに
- Djangoでメールを一括送信する際に詰まったので自分用にメモを残しておきます
- 環境
    - Python 3.6.2
    - Django==2.1.3
    - django-mail-templated==2.6.5
    - djangorestframework==3.8.2

# 詰まったところ
- mail_templatedから宛先や文面の違うメールを生成して一括送信したかったので下のようなコードを書いたが、送信されたメールの件名や本文がすべて空になってしまっていた
- 同じ件名・本文のメールを複数件送る場合は`to=["user1@example.com", "user2@example.com"...]`と書けばよいです

```sample.py
from django.core.mail import get_connection
from mail_templated import EmailMessage
from app.models.user import User


class Sample():
    def sample_function(self):
        users = User.objects.exclude(email__isnull=True).annotate(
            fullname=Concat('user__last_name', 'user__first_name', output_field=CharField())).values(
                'email', 'fullname')
        user_list = list(users)

        connection = get_connection()
        connection.open()

        email_list = [EmailMessage(
            'email/example.tpl', {'fullname': user['fullname']},
            'from@example.com',
            to=[user['email']]
            ) for user in user_list]

        connection.send_messages(email_list)
        connection.close()
```
- ちなみにUserモデルとメールのテンプレートは以下のような感じです

```app/models.py
from django.db import model


class User(models.Model):
    class Meta:
        app_label = 'test'
        db_table = 'users'

    email = models.EmailField(blank=False, null=True, default='')
    first_name = models.CharField(max_length=32, blank=False, default='')
    last_name = models.CharField(max_length=32, blank=False, default='')
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

```

```app/templates/email/example.tpl
{% extends "mail_templated/base.tpl" %}

{% block subject %}
【例】サンプルメール
{% endblock %}

{% block body %}
{{ full_name }}様
…
…
…
{% endblock %}

{% block html %}
{% endblock %}
```

# どうやったか
- [ソース](https://github.com/artemrizhov/django-mail-templated)を読んだらわかった
    - [このへん](https://github.com/artemrizhov/django-mail-templated/blob/master/mail_templated/message.py#L224)を読んだら送る前に`render()`を呼び出す必要があるのがわかったので、以下のようにコードを修正したところ動いた

```sample.py
from django.core.mail import get_connection
from mail_templated import EmailMessage
from app.models.user import User


class Sample():
    def sample_function(self):
        users = User.objects.exclude(email__isnull=True).annotate(
            fullname=Concat('user__last_name', 'user__first_name', output_field=CharField())).values(
                'email', 'fullname')
        user_list = list(users)
        email_list = []

        connection = get_connection()
        connection.open()
        for user in user_list:
            email = EmailMessage(
                'email/example.tpl', {'fullname': user['fullname']},
                'from@example.com',
                to=[user['email']]
                )
            email.render()
            email_list.append(email)

        connection.send_messages(email_list)
        connection.close()
```

# 参考にしたもの
- [Sending email | Django documentation | Django](https://docs.djangoproject.com/en/2.1/topics/email/)（公式のドキュメント）
- [artemrizhov/django-mail-templated: Send emails using Django template system](https://github.com/artemrizhov/django-mail-templated)（使っているライブラリ）

# その他
- もっといいやり方/ライブラリがある、そもそもこのやり方ではパフォーマンス上意味がない等ございましたらご指摘ください