メールを送信する

Although Python provides a mail sending interface via the smtplib module, Django provides a couple of light wrappers over it. These wrappers are provided to make sending email extra quick, to help test email sending during development, and to provide support for platforms that can't use SMTP.

コードは django.core.mail モジュールにあります。

簡単な例

次の 2 文を書くことで、

from django.core.mail import send_mail

send_mail(
    'Subject here',
    'Here is the message.',
    'from@example.com',
    ['to@example.com'],
    fail_silently=False,
)

設定内の EMAIL_HOSTEMAIL_PORT で指定された SMTP ホストとポートを使用して、メールが送信されます。EMAIL_HOST_USEREMAIL_HOST_PASSWORD が指定されている場合は、SMTP サーバーの認証に使われます。そして、EMAIL_USE_TLSEMAIL_USE_SSL 設定により、セキュアコネクションを使うかどうかをコントロールします。

注釈

django.core.mail で送信されるメールの文字セットは、DEFAULT_CHARSET 設定の値にセットされます。

send_mail()

send_mail(subject, message, from_email, recipient_list, fail_silently=False, auth_user=None, auth_password=None, connection=None, html_message=None)[ソース]

In most cases, you can send email using django.core.mail.send_mail().

subjectmessagefrom_emailrecipient_list の 4 つの引数は必須です。

  • subject: 文字列。
  • message: 文字列。
  • from_email: A string. If None, Django will use the value of the DEFAULT_FROM_EMAIL setting.
  • recipient_list: メールアドレスを表す文字列のリスト。recipient_list の各メンバーは、メールメッセージの "To:" フィールドで他の受信者を見ることができます。
  • fail_silently: A boolean. When it's False, send_mail() will raise an smtplib.SMTPException if an error occurs. See the smtplib docs for a list of possible exceptions, all of which are subclasses of SMTPException.
  • auth_user: SMTP サーバー認証のためのユーザー名で、省略可能。指定されなかった場合、Django EMAIL_HOST_USER 設定の値を使います。
  • auth_password: SMTP サーバー認証のためのパスワードで、省略可能。指定されなかった場合、Django は EMAIL_HOST_PASSWORD 設定の値を使います。
  • connection: メール送信のために使うバックエンドで、省略可能。指定しなかった場合、デフォルトのバックエンドのインスタンスが使われます。詳しくは メールのバックエンド を参照してください。
  • html_message: html_message が指定された場合、送信されるメールは multipart/alternative となり、text/plain コンテンツタイプを持つ messagetext/html コンテンツタイプを持つ html_message を合わせ持つものになります。

返り値は、送信に成功したメッセージの数です (送信されるメッセージが 1 つだけの場合もあるため、01 になることもあります)。

send_mass_mail()

send_mass_mail(datatuple, fail_silently=False, auth_user=None, auth_password=None, connection=None)[ソース]

django.core.mail.send_mass_mail() は、大量のメール送信を扱うために用意されています。

datatuple はメッセージの集合を表すタプルです。タプル内の各要素は、それぞれ1種類のメッセージを表すタプルであり、次の形式を持ちます。

(subject, message, from_email, recipient_list)

fail_silentlyauth_userauth_password の 3 つは、send_mail() と同じように機能します。

datatuple に含まれる各要素は、最終的には別々のメールメッセージとなります。send_mail() における挙動と同じく、recipient_list 内の受信者は、メールメッセージの "To:" フィールドに書かれている他の受信者のアドレスを見ることができます。

たとえば、次のコードは異なる 2 つのメッセージを 異なる 2 つの受信者のセットに送信します。しかし、メールサーバーへの接続は 1 つしか開かれません。

message1 = ('Subject here', 'Here is the message', 'from@example.com', ['first@example.com', 'other@example.com'])
message2 = ('Another Subject', 'Here is another message', 'from@example.com', ['second@test.com'])
send_mass_mail((message1, message2), fail_silently=False)

戻り値は、メッセージ送信に成功した数です。

send_mass_mail()send_mail() の比較

send_mass_mail()send_mail() 違いは、send_mail() が実行されるごとに毎回接続を開くのに対して、send_mass_mail() はすべてのメッセージに対して 1 つだけ接続を使います。これにより、send_mass_mail() の方が若干効率がよくなっています。

mail_admins()

mail_admins(subject, message, fail_silently=False, connection=None, html_message=None)[ソース]

django.core.mail.mail_admins() は、ADMINS 設定で定義されているサイト管理者 (admin) に対してメールを送信するためのショートカットです。

mail_admins() prefixes the subject with the value of the EMAIL_SUBJECT_PREFIX setting, which is "[Django] " by default.

The "From:" header of the email will be the value of the SERVER_EMAIL setting.

This method exists for convenience and readability.

If html_message is provided, the resulting email will be a multipart/alternative email with message as the text/plain content type and html_message as the text/html content type.

mail_managers()

mail_managers(subject, message, fail_silently=False, connection=None, html_message=None)[ソース]

django.core.mail.mail_managers() は、mail_admins() とほぼ同じで、MANAGERS 設定で定義されているサイト管理者 (manager) にメールを送信します。

以下の例は、john@example.comjane@example.com に1つのメールを送信します。2人とも "To:" 内に宛先が見られます。

send_mail(
    'Subject',
    'Message.',
    'from@example.com',
    ['john@example.com', 'jane@example.com'],
)

次の例は、john@example.comjane@example.com にメールを送信しますが、受信者はどちらも個別のメールを受け取ります。

datatuple = (
    ('Subject', 'Message.', 'from@example.com', ['john@example.com']),
    ('Subject', 'Message.', 'from@example.com', ['jane@example.com']),
)
send_mass_mail(datatuple)

ヘッダインジェクションを防止する

ヘッダインジェクション は、攻撃者が 、スクリプトで生成されたメールメッセージの "To:" と "From:" をコントロールするために、メールヘッダを挿入してしまうセキュリティ上の脆弱性です。

上述した Django のメール機能は、ヘッダー値の改行を禁止することによってヘッダインジェクションを防ぎます。 subjectfrom_emailrecipient_list のいずれかに 改行 (Unix、Windows ないし Mac のスタイル) が含まれている場合、email 関数 (例えば send_mail()) は django.core.mail.BadHeaderError (ValueError のサブクラス) 投げるため、メールは送信されません。メール送信を行う関数にデータを渡す前に、開発者は責任を持ってすべてのデータを検証しておく必要があります。

If a message contains headers at the start of the string, the headers will be printed as the first bit of the email message.

次の例は、リクエストの POST データから subjectmessagefrom_email を取得し、それを admin@example.com に送信し、完了したら "/contact/thanks/" にリダイレクトします。

from django.core.mail import BadHeaderError, send_mail
from django.http import HttpResponse, HttpResponseRedirect

def send_email(request):
    subject = request.POST.get('subject', '')
    message = request.POST.get('message', '')
    from_email = request.POST.get('from_email', '')
    if subject and message and from_email:
        try:
            send_mail(subject, message, from_email, ['admin@example.com'])
        except BadHeaderError:
            return HttpResponse('Invalid header found.')
        return HttpResponseRedirect('/contact/thanks/')
    else:
        # In reality we'd use a form class
        # to get proper validation errors.
        return HttpResponse('Make sure all fields are entered and valid.')

EmailMessage クラス

Django の send_mail()send_mass_mail() 関数は EmailMessage クラスを実際に使うための小さなラッパーです。

EmailMessage クラスの機能のすべてが send_mail() やその他のラッパーで使用可能というわけではありません。高度な機能を使いたい場合 (例えば BCC の利用、ファイル添付やマルチパートのメールなど) EmailMessage のインスタンスを直接作成する必要があります。

注釈

これは設計特性です。send_mail() およびその関連の関数は、元は Django が提供した唯一のインタフェースでした。しかし、受け入れるパラメータのリストが次第に肥大化してきてしまったので、よりオブジェクト指向的な設計に移行し、元の関数は後方互換性確保のためだけに残すことになりました。

EmailMessage はメールメッセージ本体を作成する役割を担っており、その後、メールのバックエンド がメールを送信する役目を果たします。

For convenience, EmailMessage provides a send() method for sending a single email. If you need to send multiple messages, the email backend API provides an alternative.

EmailMessage オブジェクト

class EmailMessage[ソース]

EmailMessage クラスは、以下のパラメータで (省略可能な引数が使われた場合、その順番で) 初期化されます。全てのパラメータは省略可能で、send() メソッドを呼ぶ前のタイミングでセットされます。

  • subject: メールの件名の行。
  • body: 本文のテキスト。プレーンテキストのメッセージでなければなりません。
  • from_email: The sender's address. Both fred@example.com and "Fred" <fred@example.com> forms are legal. If omitted, the DEFAULT_FROM_EMAIL setting is used.
  • to: 受信者のメールアドレスのリストまたはタプル。
  • bcc: メールを送信するときに "Bcc" ヘッダ内で使われるメールアドレスのリストまたはタプル。
  • connection: メールバックエンドのインスタンス。複数のメッセージに同一の接続を使いたいときに指定します。省略した場合、send() が呼ばれる時に新しい接続が生成されます。
  • attachments: A list of attachments to put on the message. These can be either MIMEBase instances, or (filename, content, mimetype) triples.
  • headers: メッセージに追加するヘッダーの辞書。キーはヘッダ名、値はヘッダ値です。メールメッセージに対して適切なヘッダ名と値にするのは、呼び出す側の責任です。対応する属性は extra_headers です。
  • メールを送信するときに "Cc" ヘッダ内で使われる、受信者のアドレスのリストまたはタプル。
  • reply_to: メールを送信するときに "Reply-To" ヘッダ内で使われる、受信者のアドレスのリストまたはタプル。

例:

from django.core.mail import EmailMessage

email = EmailMessage(
    'Hello',
    'Body goes here',
    'from@example.com',
    ['to1@example.com', 'to2@example.com'],
    ['bcc@example.com'],
    reply_to=['another@example.com'],
    headers={'Message-ID': 'foo'},
)

このクラスには以下のメソッドがあります。

  • send(fail_silently=False) sends the message. If a connection was specified when the email was constructed, that connection will be used. Otherwise, an instance of the default backend will be instantiated and used. If the keyword argument fail_silently is True, exceptions raised while sending the message will be quashed. An empty list of recipients will not raise an exception. It will return 1 if the message was sent successfully, otherwise 0.

  • message() constructs a django.core.mail.SafeMIMEText object (a subclass of Python's MIMEText class) or a django.core.mail.SafeMIMEMultipart object holding the message to be sent. If you ever need to extend the EmailMessage class, you'll probably want to override this method to put the content you want into the MIME object.

  • recipients() は、toccbcc のいずれかの属性に記録されている、メッセージの全ての受信者のリストを返します。サブクラス化するときには、メッセージの送信時に SMTP サーバが受信者の完全な一覧を必要とするため、このメソッドもオーバーライドする必要があります。クラス内で受信者を指定する別の方法を追加する場合は、このメソッドからも返される必要があります。

  • attach() は新しい添付ファイルを作成し、メッセージに追加します。attach() を呼ぶには2 つの方法があります。

    • You can pass it a single argument that is a MIMEBase instance. This will be inserted directly into the resulting message.

    • もしくは、attach() の 3 つの引数を引き渡します: filenamecontentmimetype です。filename は、メール内に表示される添付ファイルの名前です。content``は、添付ファイル内に含まれるデータです。``mimetype は添付ファイルに対する MIME タイプで、省略可能です。mimetype を省略した場合、MIME コンテンツタイプは添付ファイルのファイル名から推測されます。

      例:

      message.attach('design.png', img_data, 'image/png')
      

      If you specify a mimetype of message/rfc822, it will also accept django.core.mail.EmailMessage and email.message.Message.

      For a mimetype starting with text/, content is expected to be a string. Binary data will be decoded using UTF-8, and if that fails, the MIME type will be changed to application/octet-stream and the data will be attached unchanged.

      In addition, message/rfc822 attachments will no longer be base64-encoded in violation of RFC 2046#section-5.2.1, which can cause issues with displaying the attachments in Evolution and Thunderbird.

  • attach_file() creates a new attachment using a file from your filesystem. Call it with the path of the file to attach and, optionally, the MIME type to use for the attachment. If the MIME type is omitted, it will be guessed from the filename. You can use it like this:

    message.attach_file('/images/weather_map.png')
    

    For MIME types starting with text/, binary data is handled as in attach().

代替のコンテンツタイプを送信する

メール内にコンテンツの複数のバージョンを入れておくのが便利です; 古典的な手法では、メッセージをテキストと HTML の両方のバージョンで送信します。 Django のメールのライブラリで、EmailMultiAlternatives を使ってこれを実現できます。この EmailMessage のサブクラスには、attach_alternative() があり、E メール内のメッセージ本文の別バージョンを追加することができます。(クラスの初期化を含む) 他のメソッドは EmailMessage から直接継承されます。

テキストと HTML の組み合わせを送るには、以下のように書きます:

from django.core.mail import EmailMultiAlternatives

subject, from_email, to = 'hello', 'from@example.com', 'to@example.com'
text_content = 'This is an important message.'
html_content = '<p>This is an <strong>important</strong> message.</p>'
msg = EmailMultiAlternatives(subject, text_content, from_email, [to])
msg.attach_alternative(html_content, "text/html")
msg.send()

デフォルトでは、EmailMessage 内の body パラメータの MIME タイプは "text/plain" です。この設定だとメールクライアントにかかわらず全ての受信者がメールを読むことができるので、このままにしておくのが実用的です。しかし、受信者が代替のコンテンツタイプを扱えることが確かな場合には、EmailMessagecontent_subtype 属性を使ってメインのコンテンツタイプを変更することもできます。主なタイプは常に "text" ですが、サブタイプを変更することができます。例えば:

msg = EmailMessage(subject, html_content, from_email, [to])
msg.content_subtype = "html"  # Main content is now text/html
msg.send()

メールのバックエンド

実際のメール送信は、メールバックエンドによって処理されます。

メールバックエンドのクラスには以下のメソッドがあります:

  • open() は、長寿命のメール送信の接続をインスタンス化します。
  • close() は、現在のメール送信の接続を閉じます。
  • send_messages(email_messages) sends a list of EmailMessage objects. If the connection is not open, this call will implicitly open the connection, and close the connection afterward. If the connection is already open, it will be left open after mail has been sent.

コンテキストマネジャーとしても使うことができ、必要に応じて自動的に open()close() 呼びます:

from django.core import mail

with mail.get_connection() as connection:
    mail.EmailMessage(
        subject1, body1, from1, [to1],
        connection=connection,
    ).send()
    mail.EmailMessage(
        subject2, body2, from2, [to2],
        connection=connection,
    ).send()

メールバックエンドのインスタンスを取得する

django.core.mail 内の get_connection() 関数は、利用可能なメールバックエンドのインスタンスを返します。

get_connection(backend=None, fail_silently=False, *args, **kwargs)[ソース]

デフォルトでは、get_connection() を呼び出すと EMAIL_BACKEND 内で指定されたメールバックエンドのインスタンスを返します。backend 引数を指定した場合、そのバックエンドがインスタンス化されます。

fail_silently 引数は、バックエンドがエラーをどのように扱うかをコントロールします。fail_silently が True の場合、メール送信プロセスの間に発生した例外は何の通知もされずに無視されます。

他の全ての引数は、メールバックエンドのコンストラクタに直接引き渡されます。

Django には複数のメール送信バックエンドを付属しています。SMTP バックエンド (デフォルトです) を除いて、これらのバックエンドはテストと開発のみで役立ちます。特別なメール送信が必要な場合には、独自のメールバックエンドを記述する を参照してください。

SMTP バックエンド

class backends.smtp.EmailBackend(host=None, port=None, username=None, password=None, use_tls=None, fail_silently=False, use_ssl=None, timeout=None, ssl_keyfile=None, ssl_certfile=None, **kwargs)

デフォルトのバックエンド。メールは SMTP サーバを通して送信されます。

引数が None の場合、各引数に対する値は、以下のそれぞれの設定から取得されます。

SMTP バックエンドは、Django によって継承されるデフォルトの構成です。明示的に指定したい場合は、設定内で以下の通り記述してください:

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'

指定しなかった場合は、デフォルトの timeoutsocket.getdefaulttimeout() によって指定されたものになり、デフォルトは None (タイムアウトなし) になります。

コンソールバックエンド

実際のメールを送信する代わりに、コンソールバックエンドは単に標準出力に送信されるメールを書き込みます。 デフォルトでは、コンソールバックエンドは stdout に書き込みます。 接続を構築するときに stream キーワード引数を指定することで、別のストリーム的なオブジェクトを使用できます。

このバックエンドを指定するには、設定内に以下の通り記述してください:

EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

このバックエンドはプロダクトでの使用を想定していません -- 開発中の利便性のために提供されています。

ファイルバックエンド

ファイルバックエンドは、メールをファイルに書き込みます。新しいファイルは、このバックエンド上で開いたそれぞれの新しいセッションに対して作成されます。ファイルが書き込まれるディレクトリは、 get_connection() で 接続を生成したときに EMAIL_FILE_PATH 設定ないし file_path キーワードから取得されます。

このバックエンドを指定するには、設定内に以下の通り記述してください:

EMAIL_BACKEND = 'django.core.mail.backends.filebased.EmailBackend'
EMAIL_FILE_PATH = '/tmp/app-messages' # change this to a proper location

このバックエンドはプロダクトでの使用を想定していません -- 開発中の利便性のために提供されています。

インメモリーバックエンド

'locmem' バックエンドは、 django.core.mail モジュールの特別な属性内にメッセージを保持します。outbox 属性は最初のメッセージが送信されるときに生成されます。送信される書くメッセージに対する EmailMessage インスタンスのリストです。

このバックエンドを指定するには、設定内に以下の通り記述してください:

EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'

このバックエンドはプロダクトでの使用を想定していません -- 開発とテストにおける利便性のために提供されています。

Django's test runner automatically uses this backend for testing.

ダミーバックエンド

名前が示すように、ダミーバックエンドはメッセージに何もしません。このバックエンドを指定するには、設定内に以下の通り記述してください:

EMAIL_BACKEND = 'django.core.mail.backends.dummy.EmailBackend'

このバックエンドはプロダクトでの使用を想定していません -- 開発中の利便性のために提供されています。

独自のメールバックエンドを定義する

メール送信の方法を変更する必要がある場合、独自のメールバックエンドを記述することができます。設定ファイル内の EMAIL_BACKEND 設定が独自のバックエンドのクラスへの Python のインポートパスとなります。

独自のメールバックエンドは、django.core.mail.backends.base にある BaseEmailBackend をサブクラス化して作ります。独自のメールバックエンドには send_messages(email_messages) メソッドを実装する必要があります。このメソッドは EmailMessage インスタンスのリストを受け取り、送信に成功したメッセージの数を返します。バックエンドに持続瀬的なセッションや接続の概念がある場合は、open() メソッドと close() メソッドも実装する必要があります。実装のリファレンスについては smtp.EmailBackend を参照してください。

複数のメールを送信する

SMTP 接続 (またはその他のネットワーク接続) の確立とクローズは、負荷の高い処理です。 送信するメールがたくさんある場合は、メールを送信するたびに接続の生成と破棄を繰り返すのではなく、SMTP 接続を再利用する方が効率的です。

メールバックエンドに接続を再利用するよう通知するには、2 つの方法があります。

1つ目は、send_messages() メソッドを使う方法です。send_messages()EmailMessage インスタンス (ないしサブクラス) のリストを取得し、この全てを単一の接続を使って送信します。

例えば、定期的なメール送信を表す EmailMessage オブジェクトのリストを返す get_notification_email() と呼ばれる関数がある場合、send_messages を 1度呼び出すだけでこれらのメールを送信することができます:

from django.core import mail
connection = mail.get_connection()   # Use default email connection
messages = get_notification_email()
connection.send_messages(messages)

この例では、send_messages() を呼び出してバックエンドの接続を開き、メッセージのリストを送信した後、再び接続を閉じています。

2つ目のアプローチは、メールバックエンドの open() メソッドと close() メソッドを使って手動で接続をコントロールする方法です。send_messages() は、すでに接続が開いている場合、自動で接続を開いたり閉じたりはしません。手動で接続を開いた場合、閉じるタイミングを自分でコントロールできます。たとえば、次のように書くことができます。

from django.core import mail
connection = mail.get_connection()

# Manually open the connection
connection.open()

# Construct an email message that uses the connection
email1 = mail.EmailMessage(
    'Hello',
    'Body goes here',
    'from@example.com',
    ['to1@example.com'],
    connection=connection,
)
email1.send() # Send the email

# Construct two more messages
email2 = mail.EmailMessage(
    'Hello',
    'Body goes here',
    'from@example.com',
    ['to2@example.com'],
)
email3 = mail.EmailMessage(
    'Hello',
    'Body goes here',
    'from@example.com',
    ['to3@example.com'],
)

# Send the two emails in a single call -
connection.send_messages([email2, email3])
# The connection was already open so send_messages() doesn't close it.
# We need to manually close the connection.
connection.close()

開発用にメールを設定する

Django に電子メールをまったく送信させたくない場合もあるでしょう。たとえば、ウェブサイトの開発中に数千通のメールを送信したくはないでしょう。しかし、適切な条件で適切な人々にメールが送信され、これらのメールが正しい内容を含んでいるか検証したいことがあるかもしれません。

The easiest way to configure email for local development is to use the console email backend. This backend redirects all email to stdout, allowing you to inspect the content of mail.

ファイル メールバックエンドも開発に役立ちます -- このバックエンドは全ての SMTP 接続をファイルにダンプし、都合の良いときに調べられるようにします。

Another approach is to use a "dumb" SMTP server that receives the emails locally and displays them to the terminal, but does not actually send anything. The aiosmtpd package provides a way to accomplish this:

python -m pip install aiosmtpd

python -m aiosmtpd -n -l localhost:8025

This command will start a minimal SMTP server listening on port 8025 of localhost. This server prints to standard output all email headers and the email body. You then only need to set the EMAIL_HOST and EMAIL_PORT accordingly. For a more detailed discussion of SMTP server options, see the documentation of the aiosmtpd module.

アプリケーションでのメール送信のユニットテストについては、テストのドキュメントの Email services セクションを参照してください。