Test de l'envoi d'e-mails dans Django [fermé]


90

Je dois tester que mon application Django envoie des e-mails avec un contenu correct. Je ne veux pas compter sur des systèmes externes (comme un compte Gmail ad hoc ), car je ne teste pas le service de messagerie réel ...

J'aimerais, peut-être, stocker les e-mails localement, dans un dossier au fur et à mesure de leur envoi. Une astuce pour y parvenir?


Modérateurs: veuillez verrouiller cette question. De nombreux spams sont ajoutés dans les réponses, proposant des solutions ridiculement complexes juste pour promouvoir des services externes.
nemesisdesign

Réponses:


43

Vous pouvez utiliser un serveur de fichiers pour envoyer des e-mails, ce qui est une solution très pratique pour le développement et les tests; les e-mails ne sont pas envoyés mais stockés dans un dossier que vous pouvez spécifier!


1
Plus d'informations sur les backends de messagerie: docs.djangoproject.com/en/dev/topics/email/#email-backends . Parfois, même un simple backend de console suffit.
Jeewes

1
Mais existe-t-il un moyen d'accéder au courrier électronique généré pendant les tests (automatisés)?
Overdrivr

182

Le framework de test Django a des helpers intégrés pour vous aider à tester le service de messagerie .

Exemple tiré de la documentation (version courte):

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 Bonne réponse. Mais je ce n'est pas utile pour les cas complexes, quand send_mailils ne peuvent pas être utilisés.
santiagobasulto

3
Plus précisément la documentation est ici: docs.djangoproject.com/en/1.8/topics/email/#in-memory-backend
nimiq

2
Comment feriez-vous cela si vous testiez une fonction qui appelle send_mail et que vous ne pouvez donc pas accéder mail?
Matt D

3
@MatthewDrill vous pouvez toujours accéder mail.outboxquand send_mailest appelé dans une autre fonction.
pymarco

2
@pymarco Si vous importez du courrier depuis le core, mail.outbox[0].bodyvous montrera l'e-mail envoyé même si le send_mailest effectué ailleurs.
Rob

17

Si vous êtes dans les tests unitaires, la meilleure solution est d'utiliser le backend en mémoire fourni par django.

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

Prenez le cas de l'utiliser comme appareil py.test

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

Dans chaque test, le mail.outboxest réinitialisé avec le serveur, il n'y a donc aucun effet secondaire entre les tests.

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

Utiliser MailHog

Inspiré de MailCatcher, plus facile à installer.

Construit avec Go - MailHog fonctionne sans installation sur plusieurs plates-formes.


En outre, il dispose d'un composant appelé Jim , le MailHog Chaos Monkey , qui vous permet de tester l'envoi d'e-mails avec divers problèmes:

Que peut faire Jim?

  • Rejeter les connexions
  • Connexions de limite de débit
  • Refuser l'authentification
  • Rejeter les expéditeurs
  • Rejeter les destinataires

En savoir plus ici .


(Contrairement au mailcatcher original, qui a échoué lors de l'envoi d'e-mails avec des emoji, encodés en UTF-8 et qui n'a PAS vraiment été corrigé dans la version actuelle, MailHog fonctionne simplement.)


5

Pour tout projet qui ne nécessite pas l'envoi de pièces jointes, j'utilise django-mailer , qui a l'avantage que tous les e-mails sortants se retrouvent dans une file d'attente jusqu'à ce que je déclenche leur envoi, et même après qu'ils ont été envoyés, ils sont ensuite enregistrés - tout cela est visible dans l'administrateur, ce qui permet de vérifier rapidement ce que le code d'envoi par e-mail tente de déclencher dans les intertubes.


De plus, les objets Message créés par django-mailer signifient que vous pouvez également les produire (et inspecter leur contenu) dans des tests unitaires (je sais qu'il existe un support de boîte aux lettres sortante dans la suite de tests pour une boîte aux lettres factice, mais utiliser django-mailer ne 'pas envoyer de courrier à moins que la commande de gestion ne l'envoie, ce qui signifie que vous ne pouvez pas utiliser cet objet de boîte aux lettres)
Steve Jalim

Mise à jour, très ancienne depuis ma réponse initiale: github.com/SmileyChris/django-mailer-2 prend également en charge les pièces jointes
Steve Jalim

4

Django dispose également d'un backend de messagerie en mémoire. Plus de détails dans la documentation sous Backend en mémoire . Ceci est présent dans Django 1.6, je ne sais pas s'il est présent dans quelque chose plus tôt.



1

Lier quelques-unes des pièces ici ensemble, voici une configuration simple basée sur filebased.EmailBackend. Cela rend une vue de liste reliant les fichiers journaux individuels, qui ont des noms de fichiers horodatés. Cliquez sur un lien dans la liste pour afficher ce message dans le navigateur (brut):

Réglages

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

Vue

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

Modèle

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

Pourquoi ne pas démarrer votre propre serveur SMTP très simple en héritant de smtpd.SMTPServeret 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 est appelé chaque fois que votre serveur SMTP reçoit une demande de courrier électronique, vous pouvez y faire ce que vous voulez.

Dans le code de test, faites quelque chose comme ceci:

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

Rappelez-vous simplement close()le asyncore.dispatcheren appelant smtp_server.close()pour terminer la boucle asyncore (arrêter le serveur d'écouter).


0

Si vous avez un serveur TomCat disponible, ou un autre moteur de servlet, alors une approche intéressante est "Post Hoc" qui est un petit serveur qui ressemble à l'application exactement comme un serveur SMTP, mais il comprend une interface utilisateur qui vous permet de visualiser et inspectez les e-mails envoyés. Il est open source et disponible gratuitement.

Trouvez-le sur: Site Post Hoc GitHub

Voir l'article de blog: PostHoc: Test des applications qui envoient des e-mails

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.