Mailing: Add support for a from field

Add support to the mailing profiles for specifying a "from"
address. Closes GitLab issue #522.

This commit adds a new backend class property "class_fields"
which differs from the normal "fields" property. The "class_fields"
property specifies which of the backend fields will be used to
initialize a backend's driver class. This is to avoid passing
fields that the driver doesn't expect and getting an error.

When sending emails, the "send" method will attempt to get
a "from" key from the backend data and use that when sending
emails. If no "from" key is found a None is passes. Django's
behavior in this situation dictates that the "from" value will
then be taken from the DEFAULT_FROM_EMAIL setting.

Signed-off-by: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>
This commit is contained in:
Roberto Rosario
2018-11-28 02:59:12 -04:00
parent b6976210a5
commit 29b41a7638
9 changed files with 123 additions and 17 deletions

View File

@@ -64,6 +64,9 @@
* Use FilteredSelectionForm for IndexTemplateFilteredForm. * Use FilteredSelectionForm for IndexTemplateFilteredForm.
* Use FilteredSelectionForm for DocumentVersionSignatureCreateForm. * Use FilteredSelectionForm for DocumentVersionSignatureCreateForm.
* Improve document signatures tests. * Improve document signatures tests.
* Add docstrings to most models.
* Add support to the mailing profiles for specifying a from
address. Closes GitLab issue #522.
3.1.11 (2019-04-XX) 3.1.11 (2019-04-XX)
=================== ===================

View File

@@ -96,6 +96,9 @@ Other changes
* Use FilteredSelectionForm for IndexTemplateFilteredForm. * Use FilteredSelectionForm for IndexTemplateFilteredForm.
* Use FilteredSelectionForm for DocumentVersionSignatureCreateForm. * Use FilteredSelectionForm for DocumentVersionSignatureCreateForm.
* Improve document signatures tests. * Improve document signatures tests.
* Add docstrings to most models.
* Add support to the mailing profiles for specifying a from
address. Closes GitLab issue #522.
Removals Removals
-------- --------
@@ -166,6 +169,7 @@ Bugs fixed or issues closed
--------------------------- ---------------------------
* :gitlab-issue:`498` Can't scan subdirectories * :gitlab-issue:`498` Can't scan subdirectories
* :gitlab-issue:`522` Office 365 SMTP
* :gitlab-issue:`563` Recursive Watch Folder * :gitlab-issue:`563` Recursive Watch Folder
.. _PyPI: https://pypi.python.org/pypi/mayan-edms/ .. _PyPI: https://pypi.python.org/pypi/mayan-edms/

View File

@@ -48,6 +48,11 @@ class MailerBackendBase(object):
class_path = '' # Dot path to the actual class that will handle the mail class_path = '' # Dot path to the actual class that will handle the mail
fields = {} fields = {}
@classmethod
def get_class_fields(cls):
backend_field_list = getattr(cls, 'fields', {}).keys()
return getattr(cls, 'class_fields', backend_field_list)
class MailerBackend(six.with_metaclass(MailerBackendMetaclass, MailerBackendBase)): class MailerBackend(six.with_metaclass(MailerBackendMetaclass, MailerBackendBase)):
@classmethod @classmethod

View File

@@ -4,13 +4,31 @@ from django.utils.translation import ugettext_lazy as _
from .classes import MailerBackend from .classes import MailerBackend
__all__ = ('DjangoSMTP', 'DjangoFileBased') __all__ = ('DjangoFileBased', 'DjangoSMTP')
class DjangoSMTP(MailerBackend): class DjangoSMTP(MailerBackend):
"""
Backend that wraps Django's SMTP backend
"""
class_fields = (
'host', 'port', 'use_tls', 'use_ssl', 'user', 'password'
)
class_path = 'django.core.mail.backends.smtp.EmailBackend' class_path = 'django.core.mail.backends.smtp.EmailBackend'
field_order = (
'host', 'port', 'use_tls', 'use_ssl', 'user', 'password', 'from'
)
fields = { fields = {
'host': { 'from': {
'label': _('From'),
'class': 'django.forms.CharField', 'default': '',
'help_text': _(
'The sender\'s address. Some system will refuse to send '
'messages if this value is not set.'
), 'kwargs': {
'max_length': 48
}, 'required': False
}, 'host': {
'label': _('Host'), 'label': _('Host'),
'class': 'django.forms.CharField', 'default': 'localhost', 'class': 'django.forms.CharField', 'default': 'localhost',
'help_text': _('The host to use for sending email.'), 'help_text': _('The host to use for sending email.'),
@@ -64,7 +82,7 @@ class DjangoSMTP(MailerBackend):
}, 'required': False }, 'required': False
}, },
} }
field_order = ('host', 'port', 'use_tls', 'use_ssl', 'user', 'password') label = _('Django SMTP backend')
widgets = { widgets = {
'password': { 'password': {
'class': 'django.forms.widgets.PasswordInput', 'class': 'django.forms.widgets.PasswordInput',
@@ -73,17 +91,32 @@ class DjangoSMTP(MailerBackend):
} }
} }
} }
label = _('Django SMTP backend')
class DjangoFileBased(MailerBackend): class DjangoFileBased(MailerBackend):
"""
Mailing backend that wraps Django's file based email backend
"""
class_fields = ('file_path',)
class_path = 'django.core.mail.backends.filebased.EmailBackend' class_path = 'django.core.mail.backends.filebased.EmailBackend'
field_order = (
'file_path', 'from'
)
fields = { fields = {
'file_path': { 'file_path': {
'label': _('File path'), 'label': _('File path'),
'class': 'django.forms.CharField', 'kwargs': { 'class': 'django.forms.CharField', 'kwargs': {
'max_length': 48 'max_length': 48
} }
}, }, 'from': {
'label': _('From'),
'class': 'django.forms.CharField', 'default': '',
'help_text': _(
'The sender\'s address. Some system will refuse to send '
'messages if this value is not set.'
), 'kwargs': {
'max_length': 48
}, 'required': False
}
} }
label = _('Django file based backend') label = _('Django file based backend')

View File

@@ -69,21 +69,49 @@ class UserMailer(models.Model):
return self.label return self.label
def backend_label(self): def backend_label(self):
"""
Return the label that the backend itself provides. The backend is
loaded but not initialized. As such the label returned is a class
property.
"""
return self.get_backend().label return self.get_backend().label
def dumps(self, data): def dumps(self, data):
"""
Serialize the backend configuration data.
"""
self.backend_data = json.dumps(data) self.backend_data = json.dumps(data)
self.save() self.save()
def get_class_data(self):
"""
Return the actual mailing class initialization data
"""
backend = self.get_backend()
return {
key: value for key, value in self.loads().items() if key in backend.get_class_fields()
}
def get_backend(self): def get_backend(self):
"""
Retrieves the backend by importing the module and the class
"""
return import_string(self.backend_path) return import_string(self.backend_path)
def get_connection(self): def get_connection(self):
"""
Establishes a reusable connection to the server by loading the
backend, initializing it, and the using the backend instance to get
a connection.
"""
return mail.get_connection( return mail.get_connection(
backend=self.get_backend().class_path, **self.loads() backend=self.get_backend().class_path, **self.get_class_data()
) )
def loads(self): def loads(self):
"""
Deserialize the stored backend data.
"""
return json.loads(self.backend_data) return json.loads(self.backend_data)
def natural_key(self): def natural_key(self):
@@ -104,10 +132,12 @@ class UserMailer(models.Model):
filename, content, and mimetype. filename, content, and mimetype.
""" """
recipient_list = split_recipient_list(recipients=[to]) recipient_list = split_recipient_list(recipients=[to])
backend_data = self.loads()
with self.get_connection() as connection: with self.get_connection() as connection:
email_message = mail.EmailMultiAlternatives( email_message = mail.EmailMultiAlternatives(
body=strip_tags(body), connection=connection, subject=subject, body=strip_tags(body), connection=connection,
from_email=backend_data.get('from'), subject=subject,
to=recipient_list, to=recipient_list,
) )
@@ -152,13 +182,15 @@ class UserMailer(models.Model):
with document.open() as file_object: with document.open() as file_object:
attachments.append( attachments.append(
{ {
'filename': document.label, 'content': file_object.read(), 'content': file_object.read(),
'filename': document.label,
'mimetype': document.file_mimetype 'mimetype': document.file_mimetype
} }
) )
return self.send( return self.send(
subject=subject_text, body=body_html_content, to=to, attachments=attachments attachments=attachments, body=body_html_content,
subject=subject_text, to=to,
) )
def test(self, to): def test(self, to):

View File

@@ -2,6 +2,7 @@ from __future__ import unicode_literals
TEST_BODY_HTML = '<strong>test body</strong>' TEST_BODY_HTML = '<strong>test body</strong>'
TEST_EMAIL_ADDRESS = 'test@example.com' TEST_EMAIL_ADDRESS = 'test@example.com'
TEST_EMAIL_FROM_ADDRESS = 'from.test@example.com'
TEST_RECIPIENTS_MULTIPLE_COMMA = 'test@example.com,test2@example.com' TEST_RECIPIENTS_MULTIPLE_COMMA = 'test@example.com,test2@example.com'
TEST_RECIPIENTS_MULTIPLE_COMMA_RESULT = [ TEST_RECIPIENTS_MULTIPLE_COMMA_RESULT = [
'test@example.com', 'test2@example.com' 'test@example.com', 'test2@example.com'

View File

@@ -1,8 +1,13 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import json
from ..models import UserMailer from ..models import UserMailer
from .literals import TEST_USER_MAILER_BACKEND_PATH, TEST_USER_MAILER_LABEL from .literals import (
TEST_EMAIL_FROM_ADDRESS, TEST_USER_MAILER_BACKEND_PATH,
TEST_USER_MAILER_LABEL
)
class MailerTestMixin(object): class MailerTestMixin(object):
@@ -12,5 +17,9 @@ class MailerTestMixin(object):
enabled=True, enabled=True,
label=TEST_USER_MAILER_LABEL, label=TEST_USER_MAILER_LABEL,
backend_path=TEST_USER_MAILER_BACKEND_PATH, backend_path=TEST_USER_MAILER_BACKEND_PATH,
backend_data='{}' backend_data=json.dumps(
{
'from': TEST_EMAIL_FROM_ADDRESS
}
)
) )

View File

@@ -5,8 +5,9 @@ from django.core import mail
from mayan.apps.documents.tests.test_models import GenericDocumentTestCase from mayan.apps.documents.tests.test_models import GenericDocumentTestCase
from .literals import ( from .literals import (
TEST_BODY_HTML, TEST_EMAIL_ADDRESS, TEST_RECIPIENTS_MULTIPLE_COMMA, TEST_BODY_HTML, TEST_EMAIL_ADDRESS, TEST_EMAIL_FROM_ADDRESS,
TEST_RECIPIENTS_MULTIPLE_COMMA_RESULT, TEST_RECIPIENTS_MULTIPLE_SEMICOLON, TEST_RECIPIENTS_MULTIPLE_COMMA, TEST_RECIPIENTS_MULTIPLE_COMMA_RESULT,
TEST_RECIPIENTS_MULTIPLE_SEMICOLON,
TEST_RECIPIENTS_MULTIPLE_SEMICOLON_RESULT, TEST_RECIPIENTS_MULTIPLE_MIXED, TEST_RECIPIENTS_MULTIPLE_SEMICOLON_RESULT, TEST_RECIPIENTS_MULTIPLE_MIXED,
TEST_RECIPIENTS_MULTIPLE_MIXED_RESULT, TEST_RECIPIENTS_MULTIPLE_MIXED_RESULT,
) )
@@ -19,6 +20,7 @@ class ModelTestCase(MailerTestMixin, GenericDocumentTestCase):
self.user_mailer.send(to=TEST_EMAIL_ADDRESS) self.user_mailer.send(to=TEST_EMAIL_ADDRESS)
self.assertEqual(len(mail.outbox), 1) self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].from_email, TEST_EMAIL_FROM_ADDRESS)
self.assertEqual(mail.outbox[0].to, [TEST_EMAIL_ADDRESS]) self.assertEqual(mail.outbox[0].to, [TEST_EMAIL_ADDRESS])
def test_send_simple_with_html(self): def test_send_simple_with_html(self):
@@ -26,6 +28,7 @@ class ModelTestCase(MailerTestMixin, GenericDocumentTestCase):
self.user_mailer.send(to=TEST_EMAIL_ADDRESS, body=TEST_BODY_HTML) self.user_mailer.send(to=TEST_EMAIL_ADDRESS, body=TEST_BODY_HTML)
self.assertEqual(len(mail.outbox), 1) self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].from_email, TEST_EMAIL_FROM_ADDRESS)
self.assertEqual(mail.outbox[0].to, [TEST_EMAIL_ADDRESS]) self.assertEqual(mail.outbox[0].to, [TEST_EMAIL_ADDRESS])
self.assertEqual(mail.outbox[0].alternatives[0][0], TEST_BODY_HTML) self.assertEqual(mail.outbox[0].alternatives[0][0], TEST_BODY_HTML)
@@ -36,6 +39,7 @@ class ModelTestCase(MailerTestMixin, GenericDocumentTestCase):
) )
self.assertEqual(len(mail.outbox), 1) self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].from_email, TEST_EMAIL_FROM_ADDRESS)
self.assertEqual(mail.outbox[0].to, [TEST_EMAIL_ADDRESS]) self.assertEqual(mail.outbox[0].to, [TEST_EMAIL_ADDRESS])
with self.document.open() as file_object: with self.document.open() as file_object:
self.assertEqual( self.assertEqual(
@@ -50,6 +54,7 @@ class ModelTestCase(MailerTestMixin, GenericDocumentTestCase):
self.user_mailer.send(to=TEST_RECIPIENTS_MULTIPLE_COMMA) self.user_mailer.send(to=TEST_RECIPIENTS_MULTIPLE_COMMA)
self.assertEqual(len(mail.outbox), 1) self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].from_email, TEST_EMAIL_FROM_ADDRESS)
self.assertEqual( self.assertEqual(
mail.outbox[0].to, TEST_RECIPIENTS_MULTIPLE_COMMA_RESULT mail.outbox[0].to, TEST_RECIPIENTS_MULTIPLE_COMMA_RESULT
) )
@@ -59,6 +64,7 @@ class ModelTestCase(MailerTestMixin, GenericDocumentTestCase):
self.user_mailer.send(to=TEST_RECIPIENTS_MULTIPLE_SEMICOLON) self.user_mailer.send(to=TEST_RECIPIENTS_MULTIPLE_SEMICOLON)
self.assertEqual(len(mail.outbox), 1) self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].from_email, TEST_EMAIL_FROM_ADDRESS)
self.assertEqual( self.assertEqual(
mail.outbox[0].to, TEST_RECIPIENTS_MULTIPLE_SEMICOLON_RESULT mail.outbox[0].to, TEST_RECIPIENTS_MULTIPLE_SEMICOLON_RESULT
) )
@@ -68,6 +74,7 @@ class ModelTestCase(MailerTestMixin, GenericDocumentTestCase):
self.user_mailer.send(to=TEST_RECIPIENTS_MULTIPLE_MIXED) self.user_mailer.send(to=TEST_RECIPIENTS_MULTIPLE_MIXED)
self.assertEqual(len(mail.outbox), 1) self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].from_email, TEST_EMAIL_FROM_ADDRESS)
self.assertEqual( self.assertEqual(
mail.outbox[0].to, TEST_RECIPIENTS_MULTIPLE_MIXED_RESULT mail.outbox[0].to, TEST_RECIPIENTS_MULTIPLE_MIXED_RESULT
) )

View File

@@ -12,10 +12,10 @@ from ..permissions import (
) )
from .literals import ( from .literals import (
TEST_EMAIL_ADDRESS, TEST_USER_MAILER_BACKEND_PATH, TEST_USER_MAILER_LABEL, TEST_EMAIL_ADDRESS, TEST_EMAIL_FROM_ADDRESS, TEST_USER_MAILER_BACKEND_PATH,
TEST_RECIPIENTS_MULTIPLE_COMMA, TEST_RECIPIENTS_MULTIPLE_COMMA_RESULT, TEST_USER_MAILER_LABEL, TEST_RECIPIENTS_MULTIPLE_COMMA,
TEST_RECIPIENTS_MULTIPLE_MIXED, TEST_RECIPIENTS_MULTIPLE_MIXED_RESULT, TEST_RECIPIENTS_MULTIPLE_COMMA_RESULT, TEST_RECIPIENTS_MULTIPLE_MIXED,
TEST_RECIPIENTS_MULTIPLE_SEMICOLON, TEST_RECIPIENTS_MULTIPLE_MIXED_RESULT, TEST_RECIPIENTS_MULTIPLE_SEMICOLON,
TEST_RECIPIENTS_MULTIPLE_SEMICOLON_RESULT TEST_RECIPIENTS_MULTIPLE_SEMICOLON_RESULT
) )
from .mailers import TestBackend from .mailers import TestBackend
@@ -92,6 +92,7 @@ class MailerViewsTestCase(MailerTestMixin, GenericDocumentViewTestCase):
self._request_document_link_send() self._request_document_link_send()
self.assertEqual(len(mail.outbox), 1) self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].from_email, TEST_EMAIL_FROM_ADDRESS)
self.assertEqual(mail.outbox[0].to, [TEST_EMAIL_ADDRESS]) self.assertEqual(mail.outbox[0].to, [TEST_EMAIL_ADDRESS])
def test_mail_document_view_no_permissions(self): def test_mail_document_view_no_permissions(self):
@@ -111,6 +112,7 @@ class MailerViewsTestCase(MailerTestMixin, GenericDocumentViewTestCase):
self._request_document_send() self._request_document_send()
self.assertEqual(len(mail.outbox), 1) self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].from_email, TEST_EMAIL_FROM_ADDRESS)
self.assertEqual(mail.outbox[0].to, [TEST_EMAIL_ADDRESS]) self.assertEqual(mail.outbox[0].to, [TEST_EMAIL_ADDRESS])
def test_user_mailer_create_view_no_permissions(self): def test_user_mailer_create_view_no_permissions(self):
@@ -198,6 +200,7 @@ class MailerViewsTestCase(MailerTestMixin, GenericDocumentViewTestCase):
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertEqual(len(mail.outbox), 1) self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].from_email, TEST_EMAIL_FROM_ADDRESS)
self.assertEqual(mail.outbox[0].to, [TEST_EMAIL_ADDRESS]) self.assertEqual(mail.outbox[0].to, [TEST_EMAIL_ADDRESS])
def test_send_multiple_recipients_comma(self): def test_send_multiple_recipients_comma(self):
@@ -211,6 +214,7 @@ class MailerViewsTestCase(MailerTestMixin, GenericDocumentViewTestCase):
response = self._request_user_mailer_test() response = self._request_user_mailer_test()
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertEqual(len(mail.outbox), 1) self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].from_email, TEST_EMAIL_FROM_ADDRESS)
self.assertEqual( self.assertEqual(
mail.outbox[0].to, TEST_RECIPIENTS_MULTIPLE_COMMA_RESULT mail.outbox[0].to, TEST_RECIPIENTS_MULTIPLE_COMMA_RESULT
) )
@@ -226,6 +230,7 @@ class MailerViewsTestCase(MailerTestMixin, GenericDocumentViewTestCase):
response = self._request_user_mailer_test() response = self._request_user_mailer_test()
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertEqual(len(mail.outbox), 1) self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].from_email, TEST_EMAIL_FROM_ADDRESS)
self.assertEqual( self.assertEqual(
mail.outbox[0].to, TEST_RECIPIENTS_MULTIPLE_MIXED_RESULT mail.outbox[0].to, TEST_RECIPIENTS_MULTIPLE_MIXED_RESULT
) )
@@ -241,6 +246,7 @@ class MailerViewsTestCase(MailerTestMixin, GenericDocumentViewTestCase):
response = self._request_user_mailer_test() response = self._request_user_mailer_test()
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertEqual(len(mail.outbox), 1) self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].from_email, TEST_EMAIL_FROM_ADDRESS)
self.assertEqual( self.assertEqual(
mail.outbox[0].to, TEST_RECIPIENTS_MULTIPLE_SEMICOLON_RESULT mail.outbox[0].to, TEST_RECIPIENTS_MULTIPLE_SEMICOLON_RESULT
) )
@@ -255,6 +261,7 @@ class MailerViewsTestCase(MailerTestMixin, GenericDocumentViewTestCase):
self._request_document_link_send() self._request_document_link_send()
self.assertEqual(len(mail.outbox), 1) self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].from_email, TEST_EMAIL_FROM_ADDRESS)
self.assertEqual( self.assertEqual(
mail.outbox[0].to, TEST_RECIPIENTS_MULTIPLE_COMMA_RESULT mail.outbox[0].to, TEST_RECIPIENTS_MULTIPLE_COMMA_RESULT
) )
@@ -269,6 +276,7 @@ class MailerViewsTestCase(MailerTestMixin, GenericDocumentViewTestCase):
self._request_document_link_send() self._request_document_link_send()
self.assertEqual(len(mail.outbox), 1) self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].from_email, TEST_EMAIL_FROM_ADDRESS)
self.assertEqual( self.assertEqual(
mail.outbox[0].to, TEST_RECIPIENTS_MULTIPLE_MIXED_RESULT mail.outbox[0].to, TEST_RECIPIENTS_MULTIPLE_MIXED_RESULT
) )
@@ -283,6 +291,7 @@ class MailerViewsTestCase(MailerTestMixin, GenericDocumentViewTestCase):
self._request_document_link_send() self._request_document_link_send()
self.assertEqual(len(mail.outbox), 1) self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].from_email, TEST_EMAIL_FROM_ADDRESS)
self.assertEqual( self.assertEqual(
mail.outbox[0].to, TEST_RECIPIENTS_MULTIPLE_SEMICOLON_RESULT mail.outbox[0].to, TEST_RECIPIENTS_MULTIPLE_SEMICOLON_RESULT
) )
@@ -297,6 +306,7 @@ class MailerViewsTestCase(MailerTestMixin, GenericDocumentViewTestCase):
self._request_document_send() self._request_document_send()
self.assertEqual(len(mail.outbox), 1) self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].from_email, TEST_EMAIL_FROM_ADDRESS)
self.assertEqual( self.assertEqual(
mail.outbox[0].to, TEST_RECIPIENTS_MULTIPLE_COMMA_RESULT mail.outbox[0].to, TEST_RECIPIENTS_MULTIPLE_COMMA_RESULT
) )
@@ -311,6 +321,7 @@ class MailerViewsTestCase(MailerTestMixin, GenericDocumentViewTestCase):
self._request_document_send() self._request_document_send()
self.assertEqual(len(mail.outbox), 1) self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].from_email, TEST_EMAIL_FROM_ADDRESS)
self.assertEqual( self.assertEqual(
mail.outbox[0].to, TEST_RECIPIENTS_MULTIPLE_MIXED_RESULT mail.outbox[0].to, TEST_RECIPIENTS_MULTIPLE_MIXED_RESULT
) )
@@ -325,6 +336,7 @@ class MailerViewsTestCase(MailerTestMixin, GenericDocumentViewTestCase):
self._request_document_send() self._request_document_send()
self.assertEqual(len(mail.outbox), 1) self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].from_email, TEST_EMAIL_FROM_ADDRESS)
self.assertEqual( self.assertEqual(
mail.outbox[0].to, TEST_RECIPIENTS_MULTIPLE_SEMICOLON_RESULT mail.outbox[0].to, TEST_RECIPIENTS_MULTIPLE_SEMICOLON_RESULT
) )