How to test send_mail in Django?
Asked Answered
F

1

11

Using Django 1.7 and Python 2.7.

I want to test if the mail was sent and if the content of the mail is correct.

I've tried using outbox from django.core.mail, but to no avail. Also could I just get the stdout (since I can see the mail in the console when I run my tests)?

models.py

class User(AbstractBaseUser, PermissionsMixin):
    USERNAME_FIELD = 'email'

    email = models.EmailField(max_length=255, unique=True)
    is_staff =  models.BooleanField(default=False)
    org = models.ForeignKey('Org', null=True, blank=True,
        on_delete=models.SET_NULL)

    def __unicode__(self):
        return self.email

    @staticmethod
    def send_password_token(email):
        user = get_object_or_404(User, email=email)
        token = Token.objects.get(user=user)
        message_body = 'Your password reset token:\n\n\t%s' % token.key
        send_mail('Password reset:', message_body,
            settings.FROM_EMAIL, [email], fail_silently=False)

tests.py

class UserModelTest(TestCase):
    def setUp(self):
        self.user = User.objects.create_user(email='[email protected]',
            password='0000')

    @override_settings(EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend')
    def test_send_password_token(self):
        """
        Sends a password reset mail with users authentication token.
        """
        token = Token.objects.get(user=self.user)
        User.send_password_token(self.user.email)
Fannyfanon answered 12/2, 2016 at 13:44 Comment(2)
Have you seen the example in the docs? You should remove the override_settings decorator. Then Django will automatically use the locmem email backend and put the email in the outbox for you to check.Makeyevka
When you use the console backend, mails will only be sent to stdout, and not be available from the django.core.mail mailbox. Use the locmem backend. docs.djangoproject.com/en/1.9/topics/email/#in-memory-backendImprovident
F
16

Thanks for @Alasdair for the solution. Turns out it was quite simple. Just remove override_settings and import outbox.

tests.py

from django.core.mail import outbox

class UserModelTest(TestCase):
    def setUp(self):
        self.user = User.objects.create_user(email='[email protected]',
            password='0000')

    def test_send_password_token(self):
        """
        Sends a password reset mail with users authentication token.
        """
        token = Token.objects.get(user=self.user)
        User.send_password_token(self.user.email)
        self.assertEqual(len(outbox), 1)
        self.assertEqual(outbox[0].subject, 'Password reset:')
        self.assertEqual(outbox[0].from_email, <insert_from_email>)
        self.assertEqual(outbox[0].to, [<insert_list_of_to_emails>])
        self.assertEqual(outbox[0].body,
            'Your password reset token:\n\n\t%s' % token.key)
Fannyfanon answered 12/2, 2016 at 14:33 Comment(1)
This may have changed in Django 2 -- now the import seems to be from django.core import mail and the outbox is inspected like mail.outboxGavelkind

© 2022 - 2024 — McMap. All rights reserved.