Preciso testar se meu aplicativo Django envia e-mails com o conteúdo correto. Não quero depender de sistemas externos (como uma conta ad-hoc do gmail ), já que não estou testando o serviço de e-mail real ...
Gostaria de, talvez, armazenar os e-mails localmente, dentro de uma pasta à medida que são enviados. Alguma dica de como conseguir isso?
Respostas:
Você pode usar um backend de arquivo para enviar e-mails, o que é uma solução muito útil para desenvolvimento e teste; e-mails não são enviados, mas armazenados em uma pasta que você pode especificar!
fonte
A estrutura de teste do Django possui alguns auxiliares integrados para ajudá-lo a testar o serviço de e-mail .
Exemplo de documentos (versão curta):
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')
fonte
send_mail
não pode ser usado.mail
?mail.outbox
quandosend_mail
é chamado em outra função.mail.outbox[0].body
mostrará o e-mail enviado mesmo quesend_mail
seja executado em outro lugar.Se você está em teste de unidade, a melhor solução é usar o back-end In-memory fornecido pelo django.
EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'
Considere o caso de usá-lo como um acessório py.test
@pytest.fixture(autouse=True) def email_backend_setup(self, settings): settings.EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'
Em cada teste, o
mail.outbox
é redefinido com o servidor, para que não haja efeitos colaterais entre os testes.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
fonte
Use MailHog
Além disso, possui um componente chamado Jim , o MailHog Chaos Monkey , que permite que você teste o envio de e-mails com vários problemas acontecendo:
Leia mais sobre isso aqui .
(Ao contrário do mailcatcher original, que falhou ao enviar e-mails com emoji, codificado em UTF-8 e NÃO FOI realmente corrigido na versão atual, o MailHog simplesmente funciona.)
fonte
Para qualquer projeto que não requeira o envio de anexos, eu uso o django-mailer , que tem a vantagem de todos os e-mails de saída terminarem em uma fila até que eu acione o envio, e mesmo após terem sido enviados, eles são então registrados - tudo isso é visível no Admin, tornando mais fácil verificar rapidamente o que seu código de e-mail está tentando disparar para os intertubos.
fonte
Django também possui um back-end de e-mail em memória. Mais detalhes nos documentos em Back -end In-memory . Isso está presente no Django 1.6 não tenho certeza se está presente em algo anterior.
fonte
Aplicar patches no SMTPLib para fins de teste pode ajudar a testar o envio de emails sem enviá-los.
fonte
Amarrando algumas das peças aqui juntas, aqui está uma configuração simples baseada em
filebased.EmailBackend
. Isso renderiza uma exibição de lista com links para os arquivos de log individuais, que têm nomes de arquivo com carimbo de data / hora convenientemente. Clicar em um link na lista exibe essa mensagem no navegador (bruta):Configurações
EMAIL_BACKEND = "django.core.mail.backends.filebased.EmailBackend" EMAIL_FILE_PATH = f"{MEDIA_ROOT}/email_out"
Visão
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"),
fonte
Por que não iniciar seu próprio servidor SMTP realmente simples herdando de
smtpd.SMTPServer
ethreading.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 é chamado sempre que seu servidor SMTP recebe uma solicitação de email, você pode fazer o que quiser lá.
No código de teste, faça algo assim:
smtp_server = TestingSMTPServer() smtp_server.start() do_thing_that_would_send_a_mail() smtp_server.close() self.assertIn(b'hello', smtp_server.received_data)
Apenas lembre-se
close()
oasyncore.dispatcher
chamandosmtp_server.close()
para terminar o loop asyncore (parar o servidor de escuta).fonte
Se você tiver um servidor TomCat disponível, ou outro mecanismo de servlet, uma boa abordagem é "Post Hoc", que é um pequeno servidor que parece para o aplicativo exatamente como um servidor SMTP, mas inclui uma interface de usuário que permite visualizar e inspecione as mensagens de email enviadas. É um código aberto e está disponível gratuitamente.
Encontre-o em: Post Hoc GitHub Site
Veja a postagem do blog: PostHoc: Testando aplicativos que enviam e-mail
fonte