尽管 mail.outbox 为空,但 AnyMail 未在 Django 测试中发送电子邮件?
AnyMail not sending an email in a Django test, despite that mail.outbox is empty?
我想编写一个 Django 单元测试来测试电子邮件是否已发送但实际上没有发送(如 https://docs.djangoproject.com/en/2.0/topics/testing/tools/#email-services 中所述),但也可以配置为发送实际电子邮件(以检查它的格式等)。
现在,我只有一个 'ordinary' 测试:
from django.test import TestCase, override_settings
from django.core import mail
from lucy_web.test_factories import FamilyFactory, UserFactory
from lucy_web.views.app_invite import send_activation_email
# @override_settings(EMAIL_BACKEND="anymail.backends.mailgun.EmailBackend")
class SendActivationEmailTestCase(TestCase):
def test_send_activation_email(self):
user = UserFactory(email='kurt@startwithlucy.com')
family = FamilyFactory(employee_user=user)
send_activation_email(user=user)
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].recipients(), [user.email])
self.assertIn(
f"Your activation code is {family.activation_code}.",
mail.outbox[0].body)
(测试使用某些型号的 factory_boy
测试夹具)。这个测试通过了,但是如果我在 override_settings
装饰器中评论,我会得到一个错误:
(venv) Kurts-MacBook-Pro-2:lucy-web kurtpeek$ python manage.py test lucy_web.tests.test_app_invite
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
F
======================================================================
FAIL: test_send_activation_email (lucy_web.tests.test_app_invite.SendActivationEmailTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/lucy_web/tests/test_app_invite.py", line 15, in test_send_activation_email
self.assertEqual(len(mail.outbox), 1)
AssertionError: 0 != 1
----------------------------------------------------------------------
Ran 1 test in 0.787s
FAILED (failures=1)
Destroying test database for alias 'default'...
由于 mail.outbox
是空的,我希望我会收到一封真正的电子邮件,但我检查了我的收件箱,但没有收到任何东西。
为了完整起见,这是我正在测试的功能:
from django.conf import settings
from django.core.mail import EmailMultiAlternatives
from django.template.loader import render_to_string
def send_activation_email(user):
context = {
'activation_code': user.family.activation_code,
'page_title': 'Lucy Invitation',
'company': user.family.package.company,
'num_sessions': user.family.session_count,
'domain': settings.EMAIL_IMAGE_DOMAIN}
message_text = render_to_string('email/activation_code.txt', context)
message_html = render_to_string('email/activation_code.html', context)
email = EmailMultiAlternatives(
subject='LUCY Invitation',
body=message_text,
from_email=settings.DEFAULT_FROM_EMAIL,
to=[user.email],
reply_to=[settings.SUPPORT_EMAIL])
email.attach_alternative(message_html, "text/html")
email.send()
为了增加我的困惑,从 AnyMail 文档 (http://anymail.readthedocs.io/en/stable/tips/test_backend/#testing-your-app) 看来,AnyMail 似乎也在测试中捕获 outbox
中的电子邮件。
有人可以指出这里可能出了什么问题吗?为什么我既没有收到电子邮件,也没有在 mail.outbox
中看到任何内容?
Anymail 仅在您使用其 test EmailBackend:
时捕获发件箱中的邮件
@override_settings(EMAIL_BACKEND="anymail.backends.test.EmailBackend")
# ^^^^
class SendActivationEmailTestCase(TestCase):
...
这不适用于您的情况,因为您使用的是实时 Mailgun EmailBackend。这确实会尝试发送消息(假设您还正确设置了 MAILGUN_API_KEY,并且由于 email.send()
没有引发错误,您可能会引发错误)。
因此您需要调查为什么邮件看似已发送,但您似乎没有收到。开始诊断任何电子邮件发送问题的最佳位置是 Mailgun 的日志:https://app.mailgun.com/app/logs/。 (请确保从左侧菜单中 select 您的正确发送域。)
如果您在测试邮件中看到“已接受并已送达”事件,则问题出在接收端。 (检查您的垃圾邮件文件夹。)
如果您看到“接受”、“拒绝”或“失败”事件,则问题出在 Mailgun:Anymail 正在设法 post 您的电子邮件发送到 Mailgun,但 Mailgun 拒绝或无法投递它.检查日志事件以获取解释。 (可能的原因是 from_email 与经过验证的发件人域不匹配。)
如果您甚至没有在 Mailgun 的日志中看到已接受的事件,那么问题出在 Python 方面:邮件甚至没有到达 Mailgun。您可以通过检查 Anymail 在发送电子邮件时附加到电子邮件的 anymail_status 来了解更多信息:
def send_activation_email(user):
# ...
email.send()
print(email.anymail_status.status) # should be {'queued'}
print(email.anymail_status.esp_response.content) # raw Mailgun API response
如果 none 揭示了问题的根源,请更新您的问题以包括原始 Mailgun API 响应和 Mailgun 日志中的任何相关事件。
我想编写一个 Django 单元测试来测试电子邮件是否已发送但实际上没有发送(如 https://docs.djangoproject.com/en/2.0/topics/testing/tools/#email-services 中所述),但也可以配置为发送实际电子邮件(以检查它的格式等)。
现在,我只有一个 'ordinary' 测试:
from django.test import TestCase, override_settings
from django.core import mail
from lucy_web.test_factories import FamilyFactory, UserFactory
from lucy_web.views.app_invite import send_activation_email
# @override_settings(EMAIL_BACKEND="anymail.backends.mailgun.EmailBackend")
class SendActivationEmailTestCase(TestCase):
def test_send_activation_email(self):
user = UserFactory(email='kurt@startwithlucy.com')
family = FamilyFactory(employee_user=user)
send_activation_email(user=user)
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].recipients(), [user.email])
self.assertIn(
f"Your activation code is {family.activation_code}.",
mail.outbox[0].body)
(测试使用某些型号的 factory_boy
测试夹具)。这个测试通过了,但是如果我在 override_settings
装饰器中评论,我会得到一个错误:
(venv) Kurts-MacBook-Pro-2:lucy-web kurtpeek$ python manage.py test lucy_web.tests.test_app_invite
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
F
======================================================================
FAIL: test_send_activation_email (lucy_web.tests.test_app_invite.SendActivationEmailTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/kurtpeek/Documents/Dev/lucy2/lucy-web/lucy_web/tests/test_app_invite.py", line 15, in test_send_activation_email
self.assertEqual(len(mail.outbox), 1)
AssertionError: 0 != 1
----------------------------------------------------------------------
Ran 1 test in 0.787s
FAILED (failures=1)
Destroying test database for alias 'default'...
由于 mail.outbox
是空的,我希望我会收到一封真正的电子邮件,但我检查了我的收件箱,但没有收到任何东西。
为了完整起见,这是我正在测试的功能:
from django.conf import settings
from django.core.mail import EmailMultiAlternatives
from django.template.loader import render_to_string
def send_activation_email(user):
context = {
'activation_code': user.family.activation_code,
'page_title': 'Lucy Invitation',
'company': user.family.package.company,
'num_sessions': user.family.session_count,
'domain': settings.EMAIL_IMAGE_DOMAIN}
message_text = render_to_string('email/activation_code.txt', context)
message_html = render_to_string('email/activation_code.html', context)
email = EmailMultiAlternatives(
subject='LUCY Invitation',
body=message_text,
from_email=settings.DEFAULT_FROM_EMAIL,
to=[user.email],
reply_to=[settings.SUPPORT_EMAIL])
email.attach_alternative(message_html, "text/html")
email.send()
为了增加我的困惑,从 AnyMail 文档 (http://anymail.readthedocs.io/en/stable/tips/test_backend/#testing-your-app) 看来,AnyMail 似乎也在测试中捕获 outbox
中的电子邮件。
有人可以指出这里可能出了什么问题吗?为什么我既没有收到电子邮件,也没有在 mail.outbox
中看到任何内容?
Anymail 仅在您使用其 test EmailBackend:
时捕获发件箱中的邮件@override_settings(EMAIL_BACKEND="anymail.backends.test.EmailBackend")
# ^^^^
class SendActivationEmailTestCase(TestCase):
...
这不适用于您的情况,因为您使用的是实时 Mailgun EmailBackend。这确实会尝试发送消息(假设您还正确设置了 MAILGUN_API_KEY,并且由于 email.send()
没有引发错误,您可能会引发错误)。
因此您需要调查为什么邮件看似已发送,但您似乎没有收到。开始诊断任何电子邮件发送问题的最佳位置是 Mailgun 的日志:https://app.mailgun.com/app/logs/。 (请确保从左侧菜单中 select 您的正确发送域。)
如果您在测试邮件中看到“已接受并已送达”事件,则问题出在接收端。 (检查您的垃圾邮件文件夹。)
如果您看到“接受”、“拒绝”或“失败”事件,则问题出在 Mailgun:Anymail 正在设法 post 您的电子邮件发送到 Mailgun,但 Mailgun 拒绝或无法投递它.检查日志事件以获取解释。 (可能的原因是 from_email 与经过验证的发件人域不匹配。)
如果您甚至没有在 Mailgun 的日志中看到已接受的事件,那么问题出在 Python 方面:邮件甚至没有到达 Mailgun。您可以通过检查 Anymail 在发送电子邮件时附加到电子邮件的 anymail_status 来了解更多信息:
def send_activation_email(user): # ... email.send() print(email.anymail_status.status) # should be {'queued'} print(email.anymail_status.esp_response.content) # raw Mailgun API response
如果 none 揭示了问题的根源,请更新您的问题以包括原始 Mailgun API 响应和 Mailgun 日志中的任何相关事件。