在 Django 中测试电子邮件发送 [关闭]

Posted

技术标签:

【中文标题】在 Django 中测试电子邮件发送 [关闭]【英文标题】:Testing email sending in Django [closed] 【发布时间】:2011-04-13 07:31:41 【问题描述】:

我需要测试我的 Django 应用程序发送的电子邮件内容是否正确。我不想依赖外部系统(例如临时 gmail 帐户),因为我没有测试实际的电子邮件服务...

我想,也许,将电子邮件存储在本地的文件夹中,因为它们被发送。 关于如何实现它的任何提示?

【问题讨论】:

版主:请锁定这个问题。答案中添加了大量垃圾邮件,提出的解决方案非常复杂,只是为了推广外部服务。 现在都在文档中:docs.djangoproject.com/en/stable/topics/testing/tools/… 【参考方案1】:

将这里的一些部分联系在一起,这是一个基于filebased.EmailBackend 的简单设置。这会呈现一个链接到各个日志文件的列表视图,这些文件具有方便的时间戳文件名。单击列表中的链接会在浏览器中显示该消息(原始):

设置

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

查看

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)

模板

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

网址

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

【讨论】:

【参考方案2】:

对于任何不需要发送附件的项目,我使用django-mailer,它的好处是所有出站电子邮件都会排在队列中,直到我触发它们发送,即使在它们发送之后,它们也是然后登录 - 所有这些都在 Admin 中可见,从而可以轻松快速地检查您通过电子邮件发送的代码试图向 intertubes 发射的内容。

【讨论】:

此外,由 django-mailer 创建的 Message 对象意味着您也可以在单元测试中刺激它们(并检查它们的内容)(我知道测试套件中的出站邮箱支持虚拟邮箱,但是使用 django-mailer 不会发送邮件,除非管理命令发送它,这意味着你不能使用那个邮箱对象) 更新,从我原来的答案开始:github.com/SmileyChris/django-mailer-2 也支持附件【参考方案3】:

如果您有可用的 TomCat 服务器或其他 servlet 引擎,那么一个不错的方法是“Post Hoc”,它是一个小型服务器,看起来与 SMTP 服务器完全一样,但它包含一个用户界面,允许您查看和检查已发送的电子邮件。它是开源的并且免费提供。

找到它:Post Hoc GitHub Site

见博文:PostHoc: Testing Apps that Send Email

【讨论】:

【参考方案4】:

为什么不通过继承 smtpd.SMTPServerthreading.Thread 来启动您自己的非常简单的 SMTP 服务器:

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

只要您的 SMTP 服务器收到邮件请求,就会调用 process_message,您可以在那里做任何您想做的事情。

在测试代码中,执行如下操作:

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

只要记住 close() asyncore.dispatcher 通过调用 smtp_server.close() 来结束异步循环(停止服务器侦听)。

【讨论】:

【参考方案5】:

使用MailHog

受 MailCatcher 启发,更易于安装。

使用 Go 构建 - MailHog 无需安装即可在多个平台上运行。

此外,它还有一个名为 Jim 的组件,即 MailHog Chaos Monkey,它使您能够测试发送电子邮件时出现的各种问题:

吉姆能做什么?

拒绝连接 速率限制连接 拒绝身份验证 拒绝发件人 拒绝收件人

阅读更多关于它的信息here。

(与原来的 mailcatcher 不同,failed on me when sending emails with emoji, encoded in UTF-8 在当前版本中并没有真正修复它,MailHog 可以正常工作。)

【讨论】:

【参考方案6】:

Django 测试框架有一些内置的帮助器来帮助你测试e-mail service。

来自文档的示例(短版):

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

【讨论】:

+1 好答案。但我对复杂的情况没有用,当send_mail不能使用时。 更准确地说,文档在这里:docs.djangoproject.com/en/1.8/topics/email/#in-memory-backend 如果您测试一个调用 send_mail 的函数,因此您无法访问 mail,您会怎么做? @MatthewDrill 当在另一个函数中调用send_mail 时,您仍然可以访问mail.outbox @pymarco 如果您从核心导入邮件,mail.outbox[0].body 将向您显示发送的电子邮件,即使 send_mail 是在其他地方执行的。【参考方案7】:

如果您喜欢单元测试,最好的解决方案是使用 django 提供的In-memory backend。

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

以使用它作为py.test夹具的情况

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

在每次测试中,mail.outbox 都会随服务器重置,因此测试之间没有副作用。

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】:

Django 还有一个内存中的电子邮件后端。在In-memory backend 下的文档中有更多详细信息。这存在于 Django 1.6 中,不确定它是否存在于更早的版本中。

【讨论】:

【参考方案9】:

为测试目的修补 SMTPLib 可以帮助测试发送邮件而不发送邮件。

http://www.psychicorigami.com/2007/09/20/monkey-patching-pythons-smtp-lib-for-unit-testing/

【讨论】:

【参考方案10】:

您可以使用file backend for sending emails,这是一个非常方便的开发和测试解决方案;电子邮件不会发送,而是存储在您可以指定的文件夹中!

【讨论】:

有关电子邮件后端的更多信息:docs.djangoproject.com/en/dev/topics/email/#email-backends。有时即使是简单的控制台后端就足够了.. 但是有没有办法在(自动)测试期间访问生成的电子邮件?

以上是关于在 Django 中测试电子邮件发送 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

Django 发送的电子邮件中的部分和断行

ActionMailer在测试模式下发送真实的电子邮件! - 如何关闭?

如何配置 Django 通过 Postfix 发送邮件? [关闭]

Django 使用第三方服务发送电子邮件

在没有电子邮件服务器的情况下测试发送电子邮件

如何开发和测试一个发送电子邮件的应用程序(而不用测试数据填充某人的邮箱)? [关闭]