summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Apolloner <florian@apolloner.eu>2014-10-09 14:18:31 +0200
committerFlorian Apolloner <florian@apolloner.eu>2014-10-12 22:01:24 +0200
commit8d789449c7861b8cf8b10d244f26d9d354989aaf (patch)
treef033271e7ca0e062fa85f345bd642aea06393b07
parent6448dd833524ac3fc503506b624841c9d642de8a (diff)
Fixed #23063 -- Convert \n and \r to \r\n when using the SMTP backend as per RFC.
-rw-r--r--django/core/mail/backends/smtp.py2
-rw-r--r--django/core/mail/message.py11
-rw-r--r--docs/releases/1.7.1.txt2
-rw-r--r--tests/mail/tests.py36
4 files changed, 45 insertions, 6 deletions
diff --git a/django/core/mail/backends/smtp.py b/django/core/mail/backends/smtp.py
index 4c41eb8bd6..620168eab2 100644
--- a/django/core/mail/backends/smtp.py
+++ b/django/core/mail/backends/smtp.py
@@ -120,7 +120,7 @@ class EmailBackend(BaseEmailBackend):
for addr in email_message.recipients()]
message = email_message.message()
try:
- self.connection.sendmail(from_email, recipients, message.as_bytes())
+ self.connection.sendmail(from_email, recipients, message.as_bytes(linesep='\r\n'))
except smtplib.SMTPException:
if not self.fail_silently:
raise
diff --git a/django/core/mail/message.py b/django/core/mail/message.py
index da9891fb2f..63b00144f5 100644
--- a/django/core/mail/message.py
+++ b/django/core/mail/message.py
@@ -123,7 +123,7 @@ def sanitize_address(addr, encoding):
class MIMEMixin():
- def as_string(self, unixfrom=False):
+ def as_string(self, unixfrom=False, linesep='\n'):
"""Return the entire formatted message as a string.
Optional `unixfrom' when True, means include the Unix From_ envelope
header.
@@ -133,13 +133,16 @@ class MIMEMixin():
"""
fp = six.StringIO()
g = generator.Generator(fp, mangle_from_=False)
- g.flatten(self, unixfrom=unixfrom)
+ if six.PY2:
+ g.flatten(self, unixfrom=unixfrom)
+ else:
+ g.flatten(self, unixfrom=unixfrom, linesep=linesep)
return fp.getvalue()
if six.PY2:
as_bytes = as_string
else:
- def as_bytes(self, unixfrom=False):
+ def as_bytes(self, unixfrom=False, linesep='\n'):
"""Return the entire formatted message as bytes.
Optional `unixfrom' when True, means include the Unix From_ envelope
header.
@@ -149,7 +152,7 @@ class MIMEMixin():
"""
fp = six.BytesIO()
g = generator.BytesGenerator(fp, mangle_from_=False)
- g.flatten(self, unixfrom=unixfrom)
+ g.flatten(self, unixfrom=unixfrom, linesep=linesep)
return fp.getvalue()
diff --git a/docs/releases/1.7.1.txt b/docs/releases/1.7.1.txt
index f8d3936719..b66e259679 100644
--- a/docs/releases/1.7.1.txt
+++ b/docs/releases/1.7.1.txt
@@ -115,3 +115,5 @@ Bugfixes
(:ticket:`23609`).
* Fixed generic relations in ``ModelAdmin.list_filter`` (:ticket:`23616`).
+
+* Restored RFC compliance for the SMTP backend on Python 3 (:ticket:`23063`).
diff --git a/tests/mail/tests.py b/tests/mail/tests.py
index df6daee5c8..ccfdc6c669 100644
--- a/tests/mail/tests.py
+++ b/tests/mail/tests.py
@@ -9,7 +9,7 @@ import smtpd
import sys
import tempfile
import threading
-from smtplib import SMTPException
+from smtplib import SMTPException, SMTP
from ssl import SSLError
from django.core import mail
@@ -1038,3 +1038,37 @@ class SMTPBackendTests(BaseEmailBackendTests, SimpleTestCase):
def test_email_timeout_override_settings(self):
backend = smtp.EmailBackend()
self.assertEqual(backend.timeout, 10)
+
+ def test_email_msg_uses_crlf(self):
+ """#23063 -- Test that RFC-compliant messages are sent over SMTP."""
+ send = SMTP.send
+ try:
+ smtp_messages = []
+
+ def mock_send(self, s):
+ smtp_messages.append(s)
+ return send(self, s)
+
+ SMTP.send = mock_send
+
+ email = EmailMessage('Subject', 'Content', 'from@example.com', ['to@example.com'])
+ mail.get_connection().send_messages([email])
+
+ # Find the actual message
+ msg = None
+ for i, m in enumerate(smtp_messages):
+ if m[:4] == 'data':
+ msg = smtp_messages[i+1]
+ break
+
+ self.assertTrue(msg)
+
+ if PY3:
+ msg = msg.decode('utf-8')
+ # Ensure that the message only contains CRLF and not combinations of CRLF, LF, and CR.
+ msg = msg.replace('\r\n', '')
+ self.assertNotIn('\r', msg)
+ self.assertNotIn('\n', msg)
+
+ finally:
+ SMTP.send = send