Loading django/core/mail/message.py +13 −3 Original line number Diff line number Diff line Loading @@ -214,7 +214,8 @@ class EmailMessage(object): encoding = None # None => use settings default def __init__(self, subject='', body='', from_email=None, to=None, bcc=None, connection=None, attachments=None, headers=None, cc=None): connection=None, attachments=None, headers=None, cc=None, reply_to=None): """ Initialize a single email message (which can be sent to multiple recipients). Loading @@ -241,6 +242,12 @@ class EmailMessage(object): self.bcc = list(bcc) else: self.bcc = [] if reply_to: if isinstance(reply_to, six.string_types): raise TypeError('"reply_to" argument must be a list or tuple') self.reply_to = list(reply_to) else: self.reply_to = [] self.from_email = from_email or settings.DEFAULT_FROM_EMAIL self.subject = subject self.body = body Loading @@ -263,6 +270,8 @@ class EmailMessage(object): msg['To'] = self.extra_headers.get('To', ', '.join(self.to)) if self.cc: msg['Cc'] = ', '.join(self.cc) if self.reply_to: msg['Reply-To'] = self.extra_headers.get('Reply-To', ', '.join(self.reply_to)) # Email header names are case-insensitive (RFC 2045), so we have to # accommodate that when doing comparisons. Loading Loading @@ -395,7 +404,7 @@ class EmailMultiAlternatives(EmailMessage): def __init__(self, subject='', body='', from_email=None, to=None, bcc=None, connection=None, attachments=None, headers=None, alternatives=None, cc=None): cc=None, reply_to=None): """ Initialize a single email message (which can be sent to multiple recipients). Loading @@ -405,7 +414,8 @@ class EmailMultiAlternatives(EmailMessage): conversions. """ super(EmailMultiAlternatives, self).__init__( subject, body, from_email, to, bcc, connection, attachments, headers, cc subject, body, from_email, to, bcc, connection, attachments, headers, cc, reply_to, ) self.alternatives = alternatives or [] Loading docs/releases/1.8.txt +3 −0 Original line number Diff line number Diff line Loading @@ -210,6 +210,9 @@ Email * The SMTP :class:`~django.core.mail.backends.smtp.EmailBackend` now supports setting the ``timeout`` parameter with the :setting:`EMAIL_TIMEOUT` setting. * :class:`~django.core.mail.EmailMessage` and ``EmailMultiAlternatives`` now support the ``reply_to`` parameter. File Storage ^^^^^^^^^^^^ Loading docs/topics/email.txt +8 −1 Original line number Diff line number Diff line Loading @@ -278,11 +278,18 @@ All parameters are optional and can be set at any time prior to calling the * ``cc``: A list or tuple of recipient addresses used in the "Cc" header when sending the email. * ``reply_to``: A list or tuple of recipient addresses used in the "Reply-To" header when sending the email. .. versionchanged:: 1.8 The ``reply_to`` parameter was added. For example:: email = EmailMessage('Hello', 'Body goes here', 'from@example.com', ['to1@example.com', 'to2@example.com'], ['bcc@example.com'], headers = {'Reply-To': 'another@example.com'}) reply_to=['another@example.com'], headers={'Message-ID': 'foo'}) The class has the following methods: Loading tests/mail/tests.py +28 −0 Original line number Diff line number Diff line Loading @@ -89,6 +89,21 @@ class MailTests(HeadersCheckMixin, SimpleTestCase): self.assertEqual(message['Cc'], 'cc@example.com, cc.other@example.com') self.assertEqual(email.recipients(), ['to@example.com', 'other@example.com', 'cc@example.com', 'cc.other@example.com', 'bcc@example.com']) def test_reply_to(self): email = EmailMessage( 'Subject', 'Content', 'from@example.com', ['to@example.com'], reply_to=['reply_to@example.com'], ) message = email.message() self.assertEqual(message['Reply-To'], 'reply_to@example.com') email = EmailMessage( 'Subject', 'Content', 'from@example.com', ['to@example.com'], reply_to=['reply_to1@example.com', 'reply_to2@example.com'] ) message = email.message() self.assertEqual(message['Reply-To'], 'reply_to1@example.com, reply_to2@example.com') def test_recipients_as_tuple(self): email = EmailMessage('Subject', 'Content', 'from@example.com', ('to@example.com', 'other@example.com'), cc=('cc@example.com', 'cc.other@example.com'), bcc=('bcc@example.com',)) message = email.message() Loading @@ -102,6 +117,8 @@ class MailTests(HeadersCheckMixin, SimpleTestCase): EmailMessage(cc='foo@example.com') with self.assertRaisesMessage(TypeError, '"bcc" argument must be a list or tuple'): EmailMessage(bcc='foo@example.com') with self.assertRaisesMessage(TypeError, '"reply_to" argument must be a list or tuple'): EmailMessage(reply_to='reply_to@example.com') def test_header_injection(self): email = EmailMessage('Subject\nInjection Test', 'Content', 'from@example.com', ['to@example.com']) Loading Loading @@ -163,6 +180,17 @@ class MailTests(HeadersCheckMixin, SimpleTestCase): self.assertEqual(message['To'], 'list-subscriber@example.com, list-subscriber2@example.com') self.assertEqual(email.to, ['list-subscriber@example.com', 'list-subscriber2@example.com']) def test_reply_to_header(self): """ Specifying 'Reply-To' in headers should override reply_to. """ email = EmailMessage( 'Subject', 'Content', 'bounce@example.com', ['to@example.com'], reply_to=['foo@example.com'], headers={'Reply-To': 'override@example.com'}, ) message = email.message() self.assertEqual(message['Reply-To'], 'override@example.com') def test_multiple_message_call(self): """ Regression for #13259 - Make sure that headers are not changed when Loading Loading
django/core/mail/message.py +13 −3 Original line number Diff line number Diff line Loading @@ -214,7 +214,8 @@ class EmailMessage(object): encoding = None # None => use settings default def __init__(self, subject='', body='', from_email=None, to=None, bcc=None, connection=None, attachments=None, headers=None, cc=None): connection=None, attachments=None, headers=None, cc=None, reply_to=None): """ Initialize a single email message (which can be sent to multiple recipients). Loading @@ -241,6 +242,12 @@ class EmailMessage(object): self.bcc = list(bcc) else: self.bcc = [] if reply_to: if isinstance(reply_to, six.string_types): raise TypeError('"reply_to" argument must be a list or tuple') self.reply_to = list(reply_to) else: self.reply_to = [] self.from_email = from_email or settings.DEFAULT_FROM_EMAIL self.subject = subject self.body = body Loading @@ -263,6 +270,8 @@ class EmailMessage(object): msg['To'] = self.extra_headers.get('To', ', '.join(self.to)) if self.cc: msg['Cc'] = ', '.join(self.cc) if self.reply_to: msg['Reply-To'] = self.extra_headers.get('Reply-To', ', '.join(self.reply_to)) # Email header names are case-insensitive (RFC 2045), so we have to # accommodate that when doing comparisons. Loading Loading @@ -395,7 +404,7 @@ class EmailMultiAlternatives(EmailMessage): def __init__(self, subject='', body='', from_email=None, to=None, bcc=None, connection=None, attachments=None, headers=None, alternatives=None, cc=None): cc=None, reply_to=None): """ Initialize a single email message (which can be sent to multiple recipients). Loading @@ -405,7 +414,8 @@ class EmailMultiAlternatives(EmailMessage): conversions. """ super(EmailMultiAlternatives, self).__init__( subject, body, from_email, to, bcc, connection, attachments, headers, cc subject, body, from_email, to, bcc, connection, attachments, headers, cc, reply_to, ) self.alternatives = alternatives or [] Loading
docs/releases/1.8.txt +3 −0 Original line number Diff line number Diff line Loading @@ -210,6 +210,9 @@ Email * The SMTP :class:`~django.core.mail.backends.smtp.EmailBackend` now supports setting the ``timeout`` parameter with the :setting:`EMAIL_TIMEOUT` setting. * :class:`~django.core.mail.EmailMessage` and ``EmailMultiAlternatives`` now support the ``reply_to`` parameter. File Storage ^^^^^^^^^^^^ Loading
docs/topics/email.txt +8 −1 Original line number Diff line number Diff line Loading @@ -278,11 +278,18 @@ All parameters are optional and can be set at any time prior to calling the * ``cc``: A list or tuple of recipient addresses used in the "Cc" header when sending the email. * ``reply_to``: A list or tuple of recipient addresses used in the "Reply-To" header when sending the email. .. versionchanged:: 1.8 The ``reply_to`` parameter was added. For example:: email = EmailMessage('Hello', 'Body goes here', 'from@example.com', ['to1@example.com', 'to2@example.com'], ['bcc@example.com'], headers = {'Reply-To': 'another@example.com'}) reply_to=['another@example.com'], headers={'Message-ID': 'foo'}) The class has the following methods: Loading
tests/mail/tests.py +28 −0 Original line number Diff line number Diff line Loading @@ -89,6 +89,21 @@ class MailTests(HeadersCheckMixin, SimpleTestCase): self.assertEqual(message['Cc'], 'cc@example.com, cc.other@example.com') self.assertEqual(email.recipients(), ['to@example.com', 'other@example.com', 'cc@example.com', 'cc.other@example.com', 'bcc@example.com']) def test_reply_to(self): email = EmailMessage( 'Subject', 'Content', 'from@example.com', ['to@example.com'], reply_to=['reply_to@example.com'], ) message = email.message() self.assertEqual(message['Reply-To'], 'reply_to@example.com') email = EmailMessage( 'Subject', 'Content', 'from@example.com', ['to@example.com'], reply_to=['reply_to1@example.com', 'reply_to2@example.com'] ) message = email.message() self.assertEqual(message['Reply-To'], 'reply_to1@example.com, reply_to2@example.com') def test_recipients_as_tuple(self): email = EmailMessage('Subject', 'Content', 'from@example.com', ('to@example.com', 'other@example.com'), cc=('cc@example.com', 'cc.other@example.com'), bcc=('bcc@example.com',)) message = email.message() Loading @@ -102,6 +117,8 @@ class MailTests(HeadersCheckMixin, SimpleTestCase): EmailMessage(cc='foo@example.com') with self.assertRaisesMessage(TypeError, '"bcc" argument must be a list or tuple'): EmailMessage(bcc='foo@example.com') with self.assertRaisesMessage(TypeError, '"reply_to" argument must be a list or tuple'): EmailMessage(reply_to='reply_to@example.com') def test_header_injection(self): email = EmailMessage('Subject\nInjection Test', 'Content', 'from@example.com', ['to@example.com']) Loading Loading @@ -163,6 +180,17 @@ class MailTests(HeadersCheckMixin, SimpleTestCase): self.assertEqual(message['To'], 'list-subscriber@example.com, list-subscriber2@example.com') self.assertEqual(email.to, ['list-subscriber@example.com', 'list-subscriber2@example.com']) def test_reply_to_header(self): """ Specifying 'Reply-To' in headers should override reply_to. """ email = EmailMessage( 'Subject', 'Content', 'bounce@example.com', ['to@example.com'], reply_to=['foo@example.com'], headers={'Reply-To': 'override@example.com'}, ) message = email.message() self.assertEqual(message['Reply-To'], 'override@example.com') def test_multiple_message_call(self): """ Regression for #13259 - Make sure that headers are not changed when Loading