Test dell'invio di email in Django [chiuso]


90

Devo verificare che la mia applicazione Django invii e-mail con il contenuto corretto. Non voglio fare affidamento su sistemi esterni (come un account gmail ad hoc ), poiché non sto testando il servizio di posta elettronica vero e proprio ...

Vorrei, forse, archiviare le e-mail in locale, all'interno di una cartella man mano che vengono inviate. Qualche consiglio su come ottenerlo?


Moderatori: bloccate questa domanda. Molto spam si aggiunge alle risposte, proponendo soluzioni assurdamente complesse solo per promuovere servizi esterni.
nemesisdesign

Risposte:


43

È possibile utilizzare un file backend per l'invio di e-mail che è una soluzione molto utile per lo sviluppo e il test; le email non vengono inviate ma memorizzate in una cartella che puoi specificare!


1
Maggiori informazioni sui backend e-mail: docs.djangoproject.com/en/dev/topics/email/#email-backends . A volte è sufficiente anche un semplice backend per console ..
Jeewes

1
Ma esiste un modo per accedere all'email generata durante i test (automatizzati)?
Overdrivr

182

Django test framework ha alcuni helper integrati per aiutarti con il test del servizio di posta elettronica .

Esempio da documenti (versione breve):

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 Buona risposta. Ma non è utile per casi complessi, quando send_mailnon può essere utilizzato.
santiagobasulto

3
Più precisamente il documento è qui: docs.djangoproject.com/en/1.8/topics/email/#in-memory-backend
nimiq

2
Come faresti se testassi una funzione che chiama send_mail e quindi non puoi accedervi mail?
Matt D

3
@MatthewDrill puoi ancora accedere mail.outboxquando send_mailviene chiamato in un'altra funzione.
pymarco

2
@pymarco Se importi la posta dal core, mail.outbox[0].bodyti mostrerà l'email inviata anche se send_maileseguita altrove.
Rob il

17

Se ti piacciono i test di unità, la soluzione migliore è utilizzare il backend In-memory fornito da django.

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

Prendi il caso di usarlo come un dispositivo py.test

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

In ogni test, mail.outboxviene ripristinato con il server, quindi non ci sono effetti collaterali tra i test.

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

Usa MailHog

Ispirato da MailCatcher, più facile da installare.

Built with Go - MailHog funziona senza installazione su più piattaforme.


Inoltre, ha un componente chiamato Jim , MailHog Chaos Monkey , che ti consente di testare l'invio di e-mail con vari problemi che si verificano:

Cosa può fare Jim?

  • Rifiuta connessioni
  • Collegamenti con limite di velocità
  • Rifiuta l'autenticazione
  • Rifiuta mittenti
  • Rifiuta destinatari

Per saperne di più qui .


(A differenza del mailcatcher originale, che non ha funzionato con me durante l'invio di e-mail con emoji, codificato in UTF-8 e NON E 'STATO davvero risolto nella versione corrente, MailHog funziona.)


5

Per qualsiasi progetto che non richiede l'invio di allegati, utilizzo django-mailer , che ha il vantaggio di tutte le email in uscita che finiscono in una coda finché non ne avvio l'invio e, anche dopo che sono state inviate, vengono quindi registrate - tutto ciò è visibile nell'amministratore, rendendo facile controllare rapidamente ciò che il codice di posta elettronica sta tentando di sparare negli intertubes.


Oltre a ciò, gli oggetti Message creati da django-mailer significano che puoi produrli (e ispezionarne il contenuto) anche in unit test (so che c'è il supporto della casella di posta in uscita nella suite di test per una casella di posta fittizia, ma l'uso di django-mailer non lo fa non inviare posta a meno che non venga inviata dal comando di gestione, il che significa che non è possibile utilizzare l'oggetto della cassetta postale)
Steve Jalim

Aggiornamento, anni dalla mia risposta originale: github.com/SmileyChris/django-mailer-2 supporta anche gli allegati
Steve Jalim

4

Django ha anche un backend di posta elettronica in memoria. Maggiori dettagli nella documentazione in Backend in memoria . Questo è presente in Django 1.6, non sono sicuro che sia presente in qualcosa di precedente.



1

Unendo alcuni dei pezzi qui insieme, ecco una configurazione semplice basata su filebased.EmailBackend. Questo rende una visualizzazione elenco che collega ai singoli file di registro, che hanno nomi di file con timestamp opportunamente. Facendo clic su un collegamento nell'elenco viene visualizzato quel messaggio nel browser (grezzo):

impostazioni

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

Visualizza

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

Modello

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

Perché non avviare il tuo server SMTP davvero semplice ereditando da smtpd.SMTPServere 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 viene chiamato ogni volta che il tuo server SMTP riceve una richiesta di posta, puoi fare quello che vuoi lì.

Nel codice di test, fai qualcosa del genere:

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

Basta ricordarsi close()della asyncore.dispatcherchiamando smtp_server.close()per terminare il ciclo asyncore (arrestare il server da ascolto).


0

Se hai a disposizione un server TomCat o un altro motore servlet, un buon approccio è "Post Hoc" che è un piccolo server che sembra all'applicazione esattamente come un server SMTP, ma include un'interfaccia utente che ti consente di visualizzare e ispezionare i messaggi di posta elettronica inviati. È open source e disponibile gratuitamente.

Trovalo su: Sito GitHub Post Hoc

Vedi il post del blog: PostHoc: Test di app che inviano email

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.