Django'da e-posta gönderimini test etme [kapalı]


92

Django uygulamamın doğru içeriğe sahip e-postalar gönderdiğini test etmem gerekiyor. Gerçek e-posta hizmetini test etmediğim için harici sistemlere (geçici bir gmail hesabı gibi) güvenmek istemiyorum ...

Belki e-postaları gönderildikleri gibi bir klasör içinde yerel olarak saklamak istiyorum. Nasıl başarılacağına dair herhangi bir ipucu?


Moderatörler: lütfen bu soruyu kilitleyin. Cevaplara çok sayıda spam ekleniyor ve sadece harici hizmetleri tanıtmak için gülünç derecede karmaşık çözümler öneriyor.
nemesisdesign

Yanıtlar:


42

Geliştirme ve test için çok kullanışlı bir çözüm olan e-postaları göndermek için bir dosya arka ucu kullanabilirsiniz ; e-postalar gönderilmez ancak belirleyebileceğiniz bir klasörde saklanır!


1
E-posta arka uçları hakkında daha fazla bilgi: docs.djangoproject.com/en/dev/topics/email/#email-backends . Bazen basit konsol arka ucu bile yeterlidir ..
Jeewes

1
Ancak (otomatikleştirilmiş) test sırasında oluşturulan e-postaya erişmenin bir yolu var mı?
Overdrivr

185

Django test çerçevesi, e-posta hizmetini test etmenize yardımcı olacak bazı yerleşik yardımcılara sahiptir .

Dokümanlardan örnek (kısa versiyon):

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 Güzel cevap. Ama send_mailkullanılamadığında , karmaşık durumlarda kullanışlı değil.
santiagobasulto


3
Send_mail'i çağıran ve bu nedenle erişemediğiniz bir işlevi test ediyorsanız bunu nasıl yaparsınız mail?
Matt D

3
@MatthewDrill Erişim yine de başka işlevde denir. mail.outboxsend_mail
pymarco

2
@pymarco Çekirdekten posta içe aktarırsanız , başka bir yerde gerçekleştirilse mail.outbox[0].bodybile gönderilen e-postayı size gösterir send_mail.
Rob

17

Birim testi yapıyorsanız, en iyi çözüm django tarafından sağlanan Bellek içi arka ucu kullanmaktır .

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

Bir py.test fikstürü olarak kullanma durumunu alın

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

Her testte, mail.outboxsunucu ile sıfırlanır, böylece testler arasında herhangi bir yan etki olmaz.

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 kullanın

MailCatcher'dan ilham aldı, kurulumu daha kolay.

Go ile oluşturuldu - MailHog, birden fazla platformda kurulum gerektirmeden çalışır.


Ayrıca, adlı bir bileşenine sahip Jim , MailHog Kaos Maymun çeşitli sorunlar oluyor ile e-postalar göndermek test etmenize olanak:

Jim ne yapabilir?

  • Bağlantıları reddet
  • Hız sınırı bağlantıları
  • Kimlik doğrulamayı reddet
  • Gönderenleri reddet
  • Alıcıları reddet

Bununla ilgili daha fazlasını buradan okuyun .


( Emoji ile e-posta gönderirken bende başarısız olan , UTF-8 ile kodlanmış ve mevcut sürümde gerçekten düzeltilmemiş olan orijinal posta yakalayıcının aksine , MailHog sadece çalışıyor.)


5

Eklerin gönderilmesini gerektirmeyen herhangi bir proje için, tüm giden e-postaların gönderilmesini tetikleyene kadar ve hatta gönderildikten sonra bile günlüğe kaydedilene kadar bir kuyruğa düşmesi avantajına sahip django-maililer kullanıyorum - bunların tümü Yönetici'de görülebilir, bu da e-posta kodunuzun intertubes'a ateş etmeye çalıştığını hızlı bir şekilde kontrol etmenizi kolaylaştırır.


Buna ek olarak, django-maililer tarafından oluşturulan Mesaj nesneleri, onları birim testlerinde de hazırlayabileceğiniz (ve içeriklerini inceleyebileceğiniz) anlamına gelir (test paketinde sahte bir posta kutusu için giden posta kutusu desteği olduğunu biliyorum, ancak django-mailler kullanmaz. yönetim komutu göndermedikçe posta göndermeyin, bu da posta kutusu nesnesini kullanamayacağınız anlamına gelir)
Steve Jalim

Güncelleme, orijinal cevabımdan yaşlanıyor : github.com/SmileyChris/django-mailer-2 de ekleri destekliyor
Steve Jalim

4

Django ayrıca bellek içi e-posta arka ucuna sahiptir. Bellek içi arka uç altındaki belgelerde daha fazla ayrıntı . Bu, Django 1.6'da mevcut olup, daha önceki herhangi bir şeyde mevcut olup olmadığından emin değil.



1

Buradaki parçalardan birkaçını bir araya getirerek, işte basit bir kurulum filebased.EmailBackend . Bu, uygun şekilde zaman damgalı dosya adlarına sahip olan ayrı günlük dosyalarına bağlanan bir liste görünümü oluşturur. Listedeki bir bağlantıya tıklamak, bu mesajı tarayıcıda görüntüler (ham):

Ayarlar

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

Görünüm

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})

Şablon

{% 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'ler

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

0

Neden devralır tarafından kendi gerçekten basit SMTP Sunucusu başlatılmaz smtpd.SMTPServerve 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 Sunucunuz bir posta isteği aldığında çağrılır, orada istediğinizi yapabilirsiniz.

Test kodunda şuna benzer bir şey yapın:

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

Sadece unutmayın arayarak asyncore döngü (dinleme noktasından sunucu durdurmak) sonuna kadar.close()asyncore.dispatchersmtp_server.close()


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.