電子メールの送信

revision-up-to:11321 (1.1) unfinished

Python の smtplib ライブラリ を使えば、比較的簡単に電子メールを送信でき ますが、 Django ではこのライブラリへの軽量ラッパを二つ用意して、電子メール の送信を極めて素早くおこなえるようにしています。

コードは: django.core.mail にあります。

お手軽な例

二行だけです:

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_HOST および EMAIL_PORT 設定で指定した SMTP ホストを介してメールを送信します。 EMAIL_HOST_USER および EMAIL_HOST_PASSWORD を指定していれば、 SMTP サーバの認証に使い ます。また、SMTP サーバとの接続に TLS を使うかどうかを EMAIL_USE_TLS で設定できます。

ノート

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

send_mail()

電子メールを送信する最も簡単な方法は django.core.mail.send_mail() 関数です。この関数の定義は以下の通りです:

send_mail(subject, message, from_email, recipient_list, fail_silently=False, auth_user=None, auth_password=None)

subject, message, from_email および recipient_list は必須の パラメタです。

  • subject: 文字列です。
  • message: 文字列です。
  • from_email: 文字列です。
  • recipient_list: 文字列からなるリストで、各々が電子メールアドレス を表します。 recipient_list に入っているユーザは、お互いに他のユー ザをメールの "To:" フィールドで見られます。
  • fail_silently: ブール型の値です。 False なら send_mailsmtplib.SMTPException 例外を出すようになります。 送出されうる例外のリストは smtplib のドキュメント を参照してくださ い。いずれの例外も SMTPException のサブクラスです。
  • auth_user: オプションです。 SMTP サーバでの認証に使うユーザ名です。 この値を指定しなければ、 Django は EMAIL_HOST_USER 設定を使います。
  • auth_password: オプションです。 SMTP サーバでの認証に使うパスワー ドです。この値を指定しなければ、 Django は EMAIL_HOST_PASSWORD 設 定を使います。

send_mass_mail()

django.core.mail.send_mass_mail() は一括電子メール (mass e-mail) の送信 用の関数です。この関数の定義は以下の通りです:

send_mass_mail(datatuple, fail_silently=False, auth_user=None, auth_password=None)

datatuple はタプルで、各要素は以下の形式になっています:

(subject, message, from_email, recipient_list)

fail_silently, auth_user および auth_passwordsend_mail() と同じです。

datatuple の各要素ごとに個別の電子メールメッセージを作成して送信します。 send_mail() と同様、同じ recipient_list に入っている受信者は、他の 受信者を "To:" フィールドで見られます。

send_mass_mail() と send_mail()

send_mass_mail()send_mail() の大きな違いは、 send_mail() は実行の度にメールサーバに接続するのに対し、 send_mass_mail() は全ての メッセージの送信に一つの接続を使う点です。このため、 send_mass_mail() の方が少しだけ効率的です。

mail_admins()

django.core.mail.mail_admins()ADMINS に書かれたサイト管 理者への電子メール送信を行うためのショートカットです。関数の定義は以下の通 りです:

mail_admins(subject, message, fail_silently=False)

mail_admins() はサブジェクトの先頭に EMAIL_SUBJECT_PREFIX の 設定値を付加します。デフォルトは "[Django] " です。

電子メールの "From:" ヘッダには SERVER_EMAIL の設定値が入ります。

このメソッドは利便性と可読性のために用意されています。

mail_managers()

django.core.mail.mail_managers()mail_admins と同じですが、 電子メールを MANAGERS に書かれたサイトマネジャに送信します 関数は以下のように定義されています:

.. function:: mail_managers(subject, message, fail_silently=False)

以下の例は、単一の電子メールを john@example.comjane@example.com に送信 します。両方の宛先が "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 の電子メール機能では、ヘッダの値に改行を使えないよう にしてヘッダインジェクションを防御しています。 subject, from_email および recipient_list が (Unix, Windows または Mac 形式の) 改行を含む場 合、電子メール送信関数 (send_mail() など) は django.core.mail.BadHeaderError 例外 (ValueError のサブクラス) を送 出します。このため、電子メールは送信されません。電子メール送信関数に渡すデー タの検証はユーザに任されています。

message の文字列の先頭にヘッダが入っている場合、ヘッダは単に電子メッセー ジ本文の先頭部分として出力されます。

以下に示すのは、 subject, message および from_email をリクエス トの POST データから受け取り、メールを admin@example.com に送信し、終了した ら "/contact/thanks/" にリダイレクトする例です:

from django.core.mail import send_mail, BadHeaderError

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:
        # 実際にはフォームクラスを使って適切な検証エラーを
        # 取得するべきでしょう。
        return HttpResponse('Make sure all fields are entered and valid.')

EmailMessage および SMTPConnection クラス

Django 1.0 で新たに登場しました: Please, see the release notes

Django の send_mail() および send_mass_mail() 関数は、実際には django.core.mailEmailMessage クラスや SMTPConnection クラス に対して薄いラッパをかぶせたものにすぎません。 Django からメールを送信する 方法をカスタマイズしたければ、これらのクラスをサブクラス化してやりたいこと を実現できます。

ノート

send_mail() をはじめとしたラッパ関数から利用できる機能は、 EmailMessage クラスで提供している全ての機能をカバーしているわけでは ありません。BCC への宛先を指定やファイルの添付、マルチパート形式メール の送信を行いたい場合には、 EmailMessage インスタンスを直接生成する 必要があります。

send_mail() がこのようないささかややこしい仕様なのは、設計上の事情 によるものです。 send_mail() などの関数はもともと単なる Django 向け の単純なメールインタフェースでしかありませんでした。その後、 send_mail() に指定できるパラメタが少しづつふえてきたのです。今となっ ては、メールメッセージを扱うためのよりオブジェクト指向の設計に移行して、 send_mail() は互換性のためだけにおいておく方が有意義でしょう。

一般に、 EmailMessage はメールメッセージ自体の生成に関わります。 SMTPConnection はメール送信処理におけるネットワーク接続に関わっています。 このことは、同じ接続 (SMTPConnection インスタンス) を再利用すれば、複数 のメッセージを一括送信できることを示しています。

EmailMessage オブジェクト

class EmailMessage

EmailMessage クラスは以下のパラメタ (固定引数を使う場合には以下に示す順 番に指定します) で初期化します。パラメタは全て省略可能で、 send() メソッ ドを呼び出す前であればいつでも設定しなおせます。

  • subject: メールの題名です。
  • body: メール本文です。平文テキストのメッセージでなければなりませ ん。
  • from_email: 送信者のアドレスです。 fred@example.com 形式でも Fred <fred@example.com> 形式でもかまいません。省略すると、 DEFAULT_FROM_EMAIL の設定値を使います。
  • to: 受信者アドレスのリストまたはタプルです。
  • bcc: メールを送信する際に "Bcc" ヘッダに指定するアドレスのリスト またはタプルです。
  • connection: SMTPConnection のインスタンスです。一つの SMTP 接 続を使い回して複数のメッセージを送信したい場合に指定します。省略する と、 send() を呼び出す瞬間に新しい接続を生成します。
  • attachments: メールに添付するデータのリストです。リストの各要素は、 email.MIMEBase.MIMEBase のインスタンスか、 (filename, content, mimetype) からなるタプルです。
  • headers: メッセージに追加するヘッダの辞書です。ヘッダ名をキーに、 ヘッダ値を値にします。このパラメタを使うのなら、指定したヘッダがメー ルメッセージ中で正しいヘッダとして扱われるように気をつけねばなりませ ん。

例を示します:

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

EmailMessage クラスのインスタンスには以下のようなメソッドがあります:

  • send(fail_silently=False) メソッドを呼び出すと、 connection 属 性に指定した接続を使ってメッセージを送信します。接続がなければ、自動的 に新たな接続を生成して使います。 fail_silentlyTrue にすると、 メッセージ送信に失敗した場合に例外を送出します。

  • message()django.core.mail.SafeMIMEText クラス (Python の email.MIMEText.MIMEText クラスのサブクラス) または django.core.mail.SafeMIMEMultipart クラスのインスタンスを生成します。 このオブジェクトには送信するメッセージが入っています。 EmailMessage クラスを拡張する必要がある場合、おそらくこのメソッドを オーバライドして、所望の内容を MIME オブジェクト内に配置することになるで しょう。

  • recipients() はメッセージの全ての宛先からなるリストを返します。この 宛先リストは、 tobcc に指定した全ての宛先が入ります。 EmailMessage をサブクラス化する際、このメソッドもオーバライドする必 要があるかもしれません。というのも、 SMTP サーバはメッセージ送信時に全て の宛先を知る必要があり、全ての宛先はこのメソッドを介して返さねばならない からです。

  • attach() を呼び出すと、新たなファイル添付用パートを生成してメッセー ジに追加します。 attach() の呼び出しかたは 2 通りあります:

    • attach() に引数を一つだけ指定し、 email.MIMEBase.MIMEBase のインスタンスを渡します。このインスタンスの内容は最終的なメッセージ に直接挿入されます。

    • 別の方法として、 attach() に 3 つの引数、 filename, content および mimetype を渡します。 filename は添付する ファイルの名前で、これはメール中で表示される添付ファイルの名前になり ます。 content は添付パート中に入るデータで、 mimetype は添 付内容の MIME タイプです。 mimetype を省略すると、ファイル名を元 に推測を行います。

      例を示します:

      message.attach('design.png', img_data, 'image/png')
      
  • attach_file() を呼び出すと、ファイルシステム上のファイルから添付パー トを生成します。 attach_file() の引数には添付したいファイルのパスを 指定します。オプションとして、添付ファイルの MIME タイプも指定できます。 MIME タイプを省略すると、ファイル名をもとに推測を行います。簡単な使い方 を示すと、以下のようになります:

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

拡張コンテンツ形式のメールを送信する

メールの内容をいくつかのバージョンに分けて送信すると便利な場合があります。 古典的な例でいえば、テキスト形式と HTML 形式の両方でメールを送信するような 場合です。 複数バージョンのメールを同時に送るには、 EmailMultiAlternatives クラス を使います。このクラスは EmailMessage のサブクラスで、 attach_alternative() メソッドを使ってメールのメッセージ本文に別のバージョ ンの本文を追加できます。 attach_alternative() 以外は、(クラスをインスタ ンス化するときの初期化メソッドも含めて) 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()

デフォルトでは、 EmailMessagebody パラメタの MIME タイプは "text/plain" です。実践的には、このパラメタは変更せずにおいた方がよいで しょう。なぜなら、メールを受信した人が使っているメールクライアントソフトに 関係なくメッセージを読めるよう保証できるからです。とはいえ、メールの読み手 が拡張コンテンツ形式 (alternative content type) のメッセージを扱えると分かっ ている場合には、 EmailMessagecontent_subtype 属性を使って、主メッ セージのコンテンツタイプを変更できます。メールのメジャーコンテンツタイプは 常に "text" ですが、サブタイプは以下のように変更できます:

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

SMTPConnection オブジェクト

class SMTPConnection

SMTPConnection クラスの初期化は、SMTP サーバのホスト、ポート、SMTP 接続 を行うユーザ名、そしてパスワードを指定して初期化でき、それぞれのパラメタは host, port, username, password オプションで指定します。パラ メタを省略すると、設定ファイルから値を読み出します。

たくさんの数のメッセージを一度に送信したいなら、 SMTPConnection クラス の send_messages() メソッドが便利です。このクラスは EmailMessage ク ラス (またはサブクラス) のインスタンスのリストを引数にとり、一つの SMTP 接 続で一度に送信します。例えば、 get_notification_email() という関数があ り、この関数が定期的に送信されるメールの入った EmailMessage オブジェク トのリストを返すとしましょう。メッセージは以下のようにして一括送信できます:

connection = SMTPConnection()   # デフォルトの設定で接続を作成
messages = get_notification_email()
connection.send_messages(messages)

Testing e-mail sending

The are times when you do not want Django to send e-mails at all. For example, while developing a website, you probably don't want to send out thousands of e-mails -- but you may want to validate that e-mails will be sent to the right people under the right conditions, and that those e-mails will contain the correct content.

The easiest way to test your project's use of e-mail is to use a "dumb" e-mail server that receives the e-mails locally and displays them to the terminal, but does not actually send anything. Python has a built-in way to accomplish this with a single command:

python -m smtpd -n -c DebuggingServer localhost:1025

This command will start a simple SMTP server listening on port 1025 of localhost. This server simply prints to standard output all email headers and the email body. You then only need to set the EMAIL_HOST and EMAIL_PORT accordingly, and you are set.

For more entailed testing and processing of e-mails locally, see the Python documentation on the SMTP Server.