Fixed #23063 -- Convert \n and \r to \r\n when using the SMTP backend as per RFC.
This commit is contained in:
parent
6448dd8335
commit
8d789449c7
|
@ -120,7 +120,7 @@ class EmailBackend(BaseEmailBackend):
|
||||||
for addr in email_message.recipients()]
|
for addr in email_message.recipients()]
|
||||||
message = email_message.message()
|
message = email_message.message()
|
||||||
try:
|
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:
|
except smtplib.SMTPException:
|
||||||
if not self.fail_silently:
|
if not self.fail_silently:
|
||||||
raise
|
raise
|
||||||
|
|
|
@ -123,7 +123,7 @@ def sanitize_address(addr, encoding):
|
||||||
|
|
||||||
|
|
||||||
class MIMEMixin():
|
class MIMEMixin():
|
||||||
def as_string(self, unixfrom=False):
|
def as_string(self, unixfrom=False, linesep='\n'):
|
||||||
"""Return the entire formatted message as a string.
|
"""Return the entire formatted message as a string.
|
||||||
Optional `unixfrom' when True, means include the Unix From_ envelope
|
Optional `unixfrom' when True, means include the Unix From_ envelope
|
||||||
header.
|
header.
|
||||||
|
@ -133,13 +133,16 @@ class MIMEMixin():
|
||||||
"""
|
"""
|
||||||
fp = six.StringIO()
|
fp = six.StringIO()
|
||||||
g = generator.Generator(fp, mangle_from_=False)
|
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()
|
return fp.getvalue()
|
||||||
|
|
||||||
if six.PY2:
|
if six.PY2:
|
||||||
as_bytes = as_string
|
as_bytes = as_string
|
||||||
else:
|
else:
|
||||||
def as_bytes(self, unixfrom=False):
|
def as_bytes(self, unixfrom=False, linesep='\n'):
|
||||||
"""Return the entire formatted message as bytes.
|
"""Return the entire formatted message as bytes.
|
||||||
Optional `unixfrom' when True, means include the Unix From_ envelope
|
Optional `unixfrom' when True, means include the Unix From_ envelope
|
||||||
header.
|
header.
|
||||||
|
@ -149,7 +152,7 @@ class MIMEMixin():
|
||||||
"""
|
"""
|
||||||
fp = six.BytesIO()
|
fp = six.BytesIO()
|
||||||
g = generator.BytesGenerator(fp, mangle_from_=False)
|
g = generator.BytesGenerator(fp, mangle_from_=False)
|
||||||
g.flatten(self, unixfrom=unixfrom)
|
g.flatten(self, unixfrom=unixfrom, linesep=linesep)
|
||||||
return fp.getvalue()
|
return fp.getvalue()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -115,3 +115,5 @@ Bugfixes
|
||||||
(:ticket:`23609`).
|
(:ticket:`23609`).
|
||||||
|
|
||||||
* Fixed generic relations in ``ModelAdmin.list_filter`` (:ticket:`23616`).
|
* Fixed generic relations in ``ModelAdmin.list_filter`` (:ticket:`23616`).
|
||||||
|
|
||||||
|
* Restored RFC compliance for the SMTP backend on Python 3 (:ticket:`23063`).
|
||||||
|
|
|
@ -9,7 +9,7 @@ import smtpd
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
import threading
|
import threading
|
||||||
from smtplib import SMTPException
|
from smtplib import SMTPException, SMTP
|
||||||
from ssl import SSLError
|
from ssl import SSLError
|
||||||
|
|
||||||
from django.core import mail
|
from django.core import mail
|
||||||
|
@ -1038,3 +1038,37 @@ class SMTPBackendTests(BaseEmailBackendTests, SimpleTestCase):
|
||||||
def test_email_timeout_override_settings(self):
|
def test_email_timeout_override_settings(self):
|
||||||
backend = smtp.EmailBackend()
|
backend = smtp.EmailBackend()
|
||||||
self.assertEqual(backend.timeout, 10)
|
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
|
||||||
|
|
Loading…
Reference in New Issue