Prueba de envío de correo electrónico en Django [cerrado]

90

Necesito probar que mi aplicación Django envía correos electrónicos con el contenido correcto. No quiero depender de sistemas externos (como una cuenta de Gmail ad-hoc ), ya que no estoy probando el servicio de correo electrónico real ...

Me gustaría, tal vez, almacenar los correos electrónicos localmente, dentro de una carpeta a medida que se envían. ¿Algún consejo sobre cómo lograrlo?

RadiantHex
fuente
Moderadores: bloquee esta pregunta. Se está agregando mucho spam en las respuestas, proponiendo soluciones que son ridículamente complejas solo para promover servicios externos.
nemesisdesign

Respuestas:

43

Puede utilizar un backend de archivos para enviar correos electrónicos, que es una solución muy útil para el desarrollo y las pruebas; los correos electrónicos no se envían, sino que se almacenan en una carpeta que puede especificar.

Bernhard Vallant
fuente
1
Más información sobre backends de correo electrónico: docs.djangoproject.com/en/dev/topics/email/#email-backends . A veces, incluso un simple backend de consola es suficiente ..
Jeewes
1
Pero, ¿hay alguna forma de acceder al correo electrónico generado durante las pruebas (automatizadas)?
Overdrivr
182

El marco de prueba de Django tiene algunos ayudantes integrados para ayudarlo a probar el servicio de correo electrónico .

Ejemplo de documentos (versión corta):

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.',
            '[email protected]', ['[email protected]'],
            fail_silently=False)
        self.assertEqual(len(mail.outbox), 1)
        self.assertEqual(mail.outbox[0].subject, 'Subject here')
Davor Lucic
fuente
3
+1 Buena respuesta. Pero no es útil para casos complejos, cuando send_mailno se puede usar.
santiagobasulto
3
Más precisamente, el documento está aquí: docs.djangoproject.com/en/1.8/topics/email/#in-memory-backend
nimiq
2
¿Cómo haría esto si está probando una función que llama a send_mail y, por lo tanto, no puede acceder mail?
Matt D
3
@MatthewDrill todavía puede acceder mail.outboxcuando send_mailse llama en otra función.
pymarco
2
@pymarco Si importa correo desde el núcleo, mail.outbox[0].bodyle mostrará el correo electrónico enviado incluso si send_mailse realiza en otro lugar.
Rob
17

Si le gustan las pruebas unitarias, la mejor solución es usar el backend en memoria provisto por django.

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

Tome el caso de usarlo como un accesorio de py.test

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

En cada prueba, mail.outboxse reinicia con el servidor, por lo que no hay efectos secundarios entre pruebas.

from django.core import mail

def test_send(self):
    mail.send_mail('subject', 'body.', '[email protected]', ['[email protected]'])
    assert len(mail.outbox) == 1

def test_send_again(self):
    mail.send_mail('subject', 'body.', '[email protected]', ['[email protected]'])
    assert len(mail.outbox) == 1
Kiril
fuente
8

Usar MailHog

Inspirado en MailCatcher, más fácil de instalar.

Construido con Go - MailHog se ejecuta sin instalación en múltiples plataformas.


Además, tiene un componente llamado Jim , MailHog Chaos Monkey , que le permite probar el envío de correos electrónicos con varios problemas:

¿Qué puede hacer Jim?

  • Rechazar conexiones
  • Conexiones de límite de velocidad
  • Rechazar autenticación
  • Rechazar remitentes
  • Rechazar destinatarios

Lea más sobre esto aquí .


(A diferencia del mailcatcher original, que me falló al enviar correos electrónicos con emoji, codificado en UTF-8 y NO FUE realmente arreglado en la versión actual, MailHog simplemente funciona).

Greg Dubicki
fuente
5

Para cualquier proyecto que no requiera el envío de archivos adjuntos, uso django-mailer , que tiene la ventaja de que todos los correos electrónicos salientes terminan en una cola hasta que active su envío, e incluso después de que se hayan enviado, se registran. todo lo cual es visible en el Administrador, lo que facilita la verificación rápida de lo que el código de correo electrónico está tratando de enviar a los intertubos.

Steve Jalim
fuente
Además de eso, los objetos Message creados por django-mailer significan que también puede presionarlos (e inspeccionar su contenido) en pruebas unitarias (sé que hay soporte de buzón de correo saliente en el conjunto de pruebas para un buzón ficticio, pero usar django-mailer no no envíe correo a menos que el comando de administración lo envíe, lo que significa que no puede usar ese objeto de buzón)
Steve Jalim
Actualización, edades de mi respuesta original: github.com/SmileyChris/django-mailer-2 también admite archivos adjuntos
Steve Jalim
4

Django también tiene un backend de correo electrónico en memoria. Más detalles en los documentos en Backend en memoria . Esto está presente en Django 1.6, no estoy seguro de si está presente en algo anterior.

Josh K
fuente
1

Uniendo algunas de las piezas aquí juntas, aquí hay una configuración sencilla basada en filebased.EmailBackend. Esto genera una vista de lista que enlaza con los archivos de registro individuales, que tienen nombres de archivo convenientemente marcados con la hora. Al hacer clic en un enlace de la lista, se muestra ese mensaje en el navegador (sin formato):

Configuraciones

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

Ver

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

Modelo

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

urls

path("mailcheck/", view=mailcheck, name="mailcheck"),
coctelera
fuente
0

¿Por qué no iniciar su propio servidor SMTP realmente simple heredando de smtpd.SMTPServery 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()

Se llama a process_message cada vez que su servidor SMTP recibe una solicitud de correo, puede hacer lo que quiera allí.

En el código de prueba, haga algo como esto:

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

Sólo recuerde que close()el asyncore.dispatcherllamando smtp_server.close()a terminar el bucle asyncore (detener el servidor de la escucha).

codificador de rana
fuente
0

Si tiene un servidor TomCat disponible u otro motor de servlet, entonces un buen enfoque es "Post Hoc", que es un servidor pequeño que se ve en la aplicación exactamente como un servidor SMTP, pero incluye una interfaz de usuario que le permite ver y inspeccionar los mensajes de correo electrónico que se enviaron. Es de código abierto y está disponible gratuitamente.

Encuéntrelo en: Sitio Post Hoc GitHub

Vea la publicación del blog: PostHoc: Probar aplicaciones que envían correo electrónico

AgilePro
fuente