Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django does not Send Email on TestCase, but It Does on Shell

I have a strange issue. Whenever I try to send an email from a TestCase, I cannot receive it. However, I try the same approach on Django shell and it successfully send the email. Here is my TestCase:

class DefaultEmailTestCase(TestCase):
    def test_send(self):
        msg = EmailMessage(
            "Test Message",
            "This is a test message.",
            to=["[email protected]", "[email protected]"]
        )
        val = msg.send()
        self.assertEqual(val, 1)

It completes successfully, but I do not receive the email. And here is what I do on Django's shell:

from django.core.mail import EmailMessage

receivers = ["[email protected]", "[email protected]"]

msg = EmailMessage(
    "Test Message",
    "This is a test message."
    to=receivers
)

msg.send()

And I successfully receive the message.

Here is my settings in order (with dummy info):

EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'
EMAIL_HOST = "foo.bar.com"
EMAIL_PORT = 465 # This is the port that my email provider uses.
EMAIL_HOST_USER = "[email protected]"
EMAIL_HOST_PASSWORD = "123456"
# EMAIL_USE_TLS = True # Django raised an error saying that I cannot use both TLS and SSL. So I commented it out.
EMAIL_USE_SSL = True
DEFAULT_FROM_EMAIL = "Bar Testing Message <[email protected]>"

I have also used django.core.mail.backends.smtp.EmailBackend as EMAIL_BACKEND but no luck.

Both the test case and Django shell uses my development settings, so they are the same. I do not have any idea why this does not work.

Thanks in advance.


Environment

  • Python 3.6.5
  • Django 2.0.4
like image 303
Eray Erdin Avatar asked Mar 07 '23 00:03

Eray Erdin


1 Answers

This is from the Django documentation:

The 'locmem' backend stores messages in a special attribute of the django.core.mail module. The outbox attribute is created when the first message is sent. It’s a list with an EmailMessage instance for each message that would be sent.

Basically, when Django sets up the testing environment, it changes the email backend to the one in-memory (the one you specified in your case). So even if one would specified django.core.mail.backends.smtp.EmailBackend it would be overriden by Django.

If you need to override that behavior, here is a solution:

from django.test.utils import override_settings

@override_settings(EMAIL_BACKEND='django.core.mail.backends.smtp.EmailBackend')
class DefaultEmailTestCase(TestCase):
    ...

Note

This Django behavior is setup in order to avoid potentially sending hundreds of emails when running tests so please keep that in mind.

If you want to see the preferred implementation look at this.

TL;DR

from django.core import mail

# Test that one message has been sent.
self.assertEqual(len(mail.outbox), 1)

This will therefore test if an email would have been sent.

like image 182
scharette Avatar answered Mar 17 '23 14:03

scharette