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:03:01 +0200
commitbc13a08f89b4a9b7980588b013f358b2721c42a6 (patch)
treec6a48b1df3c2ea96beb1666e8071335cd68a4b8f
parentd2a2af67f7c2c41a831acd33cd8cba5875c216cf (diff)
[1.7.x] Fixed #23063 -- Convert \n and \r to \r\n when using the SMTP backend as per RFC.
Backport of 8d789449c7861b8cf8b10d244f26d9d354989aaf from master.
-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 dc6afb0a81..94e3aa1e88 100644
--- a/django/core/mail/backends/smtp.py
+++ b/django/core/mail/backends/smtp.py
@@ -112,7 +112,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 34caa37ffd..fb15a8c29f 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 dba3ec9f19..3bc15218af 100644
--- a/docs/releases/1.7.1.txt
+++ b/docs/releases/1.7.1.txt
@@ -114,3 +114,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 0ea819ffbd..169f9b8fbb 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
@@ -984,3 +984,37 @@ class SMTPBackendTests(BaseEmailBackendTests, SimpleTestCase):
self.assertEqual(myemailbackend.timeout, 42)
self.assertEqual(myemailbackend.connection.timeout, 42)
myemailbackend.close()
+
+ 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