Djangoでのメール送信のテスト[終了]


90

Djangoアプリケーションが正しい内容の電子メールを送信することをテストする必要があります。実際の電子メールサービスをテストしていないので、外部システム(アドホックGmailアカウントなど)に依存したくありません...

たぶん、メールを送信時にフォルダ内にローカルに保存したいと思います。それを達成する方法についてのヒントはありますか?


モデレーター:この質問をロックしてください。多くのスパムが回答に追加されており、外部サービスを宣伝するためだけに途方もなく複雑なソリューションを提案しています。
nemesisdesign 2018

回答:


43

電子メールの送信にファイルバックエンドを使用できます。これは、開発とテストに非常に便利なソリューションです。メールは送信されませんが、指定したフォルダに保存されます!


1
メールバックエンドの詳細:docs.djangoproject.com/en/dev/topics/email/#email-backends。時には簡単なコンソールバックエンドは十分..です
Jeewes

1
しかし、(自動化された)テスト中に生成された電子メールにアクセスする方法はありますか?
Overdrivr

182

Djangoテストフレームワークには、電子メールサービスのテストを支援するヘルパーが組み込まれています。

ドキュメントからの例(短いバージョン):

from django.core import mail
from django.test import TestCase

class EmailTest(TestCase):
    def test_send_email(self):
        mail.send_mail('Subject here', 'Here is the message.',
            'from@example.com', ['to@example.com'],
            fail_silently=False)
        self.assertEqual(len(mail.outbox), 1)
        self.assertEqual(mail.outbox[0].subject, 'Subject here')

3
+1良い答え。しかし、私はそれsend_mailが使用できない複雑なケースには役に立ちません。
santiagobasulto 2013

3
より正確には、ドキュメントはここにあります:docs.djangoproject.com/en/1.8/topics/email/#in-memory-backend
nimiq

2
send_mailを呼び出す関数をテストしているためにアクセスできない場合、これをどのように行いますmailか?
マットD

3
@MatthewDrillは、別の関数で呼び出されたmail.outboxときに引き続きアクセスできsend_mailます。
pymarco 2017年

2
@pymarcoコアからメールをインポートmail.outbox[0].bodyすると、send_mail他の場所で実行された場合でも送信されたメールが表示されます。
ロブ

17

ユニットテストに興味がある場合は、djangoが提供するインメモリバックエンドを使用するのが最善の解決策です。

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

py.testフィクスチャとして使用する場合を考えてみましょう

@pytest.fixture(autouse=True)
def email_backend_setup(self, settings):
    settings.EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'  

各テストで、mail.outboxはサーバーでリセットされるため、テスト間に副作用はありません。

from django.core import mail

def test_send(self):
    mail.send_mail('subject', 'body.', 'from@example.com', ['to@example.com'])
    assert len(mail.outbox) == 1

def test_send_again(self):
    mail.send_mail('subject', 'body.', 'from@example.com', ['to@example.com'])
    assert len(mail.outbox) == 1

8

MailHogを使用する

MailCatcherに触発され、インストールが簡単です。

Goで構築-MailHogは複数のプラットフォームにインストールせずに実行されます。


また、ジムと呼ばれるコンポーネントがありますであるMailHog Chaos Monkeyがあり、さまざまな問題が発生した状態で電子メールの送信をテストできます。

ジムは何ができますか?

  • 接続を拒否する
  • レート制限接続
  • 認証を拒否する
  • 送信者を拒否する
  • 受信者を拒否する

詳しくはこちらをご覧ください


絵文字を使用してメールを送信するときに失敗し、UTF-8でエンコードされた元のメールキャッチャーとは異なり、現在のリリースでは実際には修正されていませんでしたが、MailHogは正常に機能します。)


5

添付ファイルの送信を必要としないプロジェクトでは、django-mailerを使用します。これには、送信をトリガーするまですべての送信メールがキューに入れられ、送信された後でもログに記録されるという利点があります。これらはすべて管理者に表示されるため、メールで送信するコードがインターチューブに送信しようとしているものを簡単に確認できます。


さらに、django-mailerによって作成されたMessageオブジェクトは、単体テストでもそれらを生成(およびその内容を検査)できることを意味します(ダミーメールボックスのテストスイートでアウトバウンドメールボックスがサポートされていることは知っていますが、django-mailerを使用すると管理コマンドがメールを送信しない限り、メールを送信しないでください。つまり、そのメールボックスオブジェクトを使用することはできません)
Steve Jalim 2010

更新、私の元の回答からの経過github.com/SmileyChris/django-mailer-2は添付ファイルもサポートしています
Steve Jalim 2013年

4

Djangoにはメモリ内のメールバックエンドもあります。詳細については、メモリ内バックエンドのドキュメントをご覧ください。これはDjango1.6に存在し、それ以前の何かに存在するかどうかはわかりません。



1

ここでいくつかの要素を結び付けて、に基づいた簡単なセットアップを次に示しますfilebased.EmailBackend。これにより、ファイル名にタイムスタンプが付けられた個々のログファイルにリンクするリストビューが表示されます。リスト内のリンクをクリックすると、そのメッセージがブラウザに表示されます(生)。

設定

EMAIL_BACKEND = "django.core.mail.backends.filebased.EmailBackend"
EMAIL_FILE_PATH = f"{MEDIA_ROOT}/email_out"

見る

import os

from django.conf import settings
from django.shortcuts import render

def mailcheck(request):

    path = f"{settings.MEDIA_ROOT}/email_out"
    mail_list = os.listdir(path)

    return render(request, "mailcheck.html", context={"mail_list": mail_list})

テンプレート

{% if mail_list %}
  <ul>
  {% for msg in mail_list %}
    <li>
      <a href="{{ MEDIA_URL }}email_out/{{msg}}">{{ msg }}</a>
    </li>
  {% endfor %}
  </ul>
{% else %}
  No messages found.
{% endif %}

URL

path("mailcheck/", view=mailcheck, name="mailcheck"),

0

から継承してsmtpd.SMTPServer、独自の非常に単純なSMTPサーバーを起動してみませんかthreading.Thread

class TestingSMTPServer(smtpd.SMTPServer, threading.Thread):
    def __init__(self, port=25):
        smtpd.SMTPServer.__init__(
            self,
            ('localhost', port),
            ('localhost', port),
            decode_data=False
        )
        threading.Thread.__init__(self)

    def process_message(self, peer, mailfrom, rcpttos, data, **kwargs):
        self.received_peer = peer
        self.received_mailfrom = mailfrom
        self.received_rcpttos = rcpttos
        self.received_data = data

    def run(self):
        asyncore.loop()

process_messageは、SMTPサーバーがメール要求を受信するたびに呼び出され、そこで何でも実行できます。

テストコードで、次のようにします。

smtp_server = TestingSMTPServer()
smtp_server.start()
do_thing_that_would_send_a_mail()
smtp_server.close()
self.assertIn(b'hello', smtp_server.received_data)

ただに覚えて呼び出すことで(リスニングからサーバーを停止する)asyncoreループを終了します。close()asyncore.dispatchersmtp_server.close()


0

利用可能なTomCatサーバーまたは他のサーブレットエンジンがある場合、優れたアプローチは「Post Hoc」です。これは、SMTPサーバーとまったく同じようにアプリケーションに見える小さなサーバーですが、表示および表示できるユーザーインターフェイスが含まれています。送信された電子メールメッセージを調べます。オープンソースであり、無料で入手できます。

それを見つける:ポストホックGitHubサイト

ブログ投稿を参照してください: PostHoc:メールを送信するアプリのテスト

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.