10000 Fixed #23063 -- Convert \n and \r to \r\n when using the SMTP backend… · alex-python/django@8d78944 · GitHub
[go: up one dir, main page]

Skip to content

Commit 8d78944

Browse files
committed
Fixed #23063 -- Convert \n and \r to \r\n when using the SMTP backend as per RFC.
1 parent 6448dd8 commit 8d78944

File tree

4 files changed

+45
-6
lines changed

4 files changed

+45
-6
lines changed

django/core/mail/backends/smtp.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ def _send(self, email_message):
120120
for addr in email_message.recipients()]
121121
message = email_message.message()
122122
try:
123-
self.connection.sendmail(from_email, recipients, message.as_bytes())
123+
self.connection.sendmail(from_email, recipients, message.as_bytes(linesep='\r\n'))
124124
except smtplib.SMTPException:
125125
if not self.fail_silently:
126126
raise

django/core/mail/message.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ def sanitize_address(addr, encoding):
123123

124124

125125
class MIMEMixin():
126-
def as_string(self, unixfrom=False):
126+
def as_string(self, unixfrom=False, linesep='\n'):
127127
"""Return the entire formatted message as a string.
128128
Optional `unixfrom' when True, means include the Unix From_ envelope
129129
header.
@@ -133,13 +133,16 @@ def as_string(self, unixfrom=False):
133133
"""
134134
fp = six.StringIO()
135135
g = generator.Generator(fp, mangle_from_=False)
136-
g.flatten(self, unixfrom=unixfrom)
136+
if six.PY2:
137+
g.flatten(self, unixfrom=unixfrom)
138+
else:
139+
g.flatten(self, unixfrom=unixfrom, linesep=linesep)
137140
return fp.getvalue()
138141

139142
if six.PY2:
140143
as_bytes = as_string
141144
else:
142-
def as_bytes(self, unixfrom=False):
145+
def as_bytes(self, unixfrom=False, linesep='\n'):
143146
"""Return the entire formatted message as bytes.
144147
Optional `unixfrom' when True, means include the Unix From_ envelope
145148
header.
@@ -149,7 +152,7 @@ def as_bytes(self, unixfrom=False):
149152
"""
150153
fp = six.BytesIO()
151154
g = generator.BytesGenerator(fp, mangle_from_=False)
152-
g.flatten(self, unixfrom=unixfrom)
155+
g.flatten(self, unixfrom=unixfrom, linesep=linesep)
153156
return fp.getvalue()
154157

155158

docs/releases/1.7.1.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,3 +115,5 @@ Bugfixes
115115
(:ticket:`23609`).
116116

117117
* Fixed generic relations in ``ModelAdmin.list_filter`` (:ticket:`23616`).
118+
119+
* Restored RFC compliance for the SMTP backend on Python 3 (:ticket:`23063`).

tests/mail/tests.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import sys
1010
import tempfile
1111
import threading
12-
from smtplib import SMTPException
12+
from smtplib import SMTPException, SMTP
1313
from ssl import SSLError
1414

1515
from django.core import mail
@@ -1038,3 +1038,37 @@ def __init__(self, *args, **kwargs):
10381038
def test_email_timeout_override_settings(self):
10391039
backend = smtp.EmailBackend()
10401040
self.assertEqual(backend.timeout, 10)
1041+
1042+
def test_email_msg_uses_crlf(self):
1043+
"""#23063 -- Test that RFC-compliant messages are sent over SMTP."""
1044+
send = SMTP.send
1045+
try:
1046+
smtp_messages = []
1047+
1048+
def mock_send(self, s):
1049+
smtp_messages.append(s)
1050+
return send(self, s)
1051+
1052+
SMTP.send = mock_send
1053+
1054+
email = EmailMessage('Subject', 'Content', 'from@example.com', ['to@example.com'])
1055+
mail.get_connection().send_messages([email])
1056+
1057+
# Find the actual message
1058+
msg = None
1059+
for i, m in enumerate(smtp_messages):
1060+
if m[:4] == 'data':
1061+
msg = smtp_messages[i+1]
1062+
break
1063+
1064+
self.assertTrue(msg)
1065+
1066+
if PY3:
1067+
msg = msg.decode('utf-8')
1068+
# Ensure that the message only contains CRLF and not combinations of CRLF, LF, and CR.
1069+
msg = msg.replace('\r\n', '')
1070+
self.assertNotIn('\r', msg)
1071+
self.assertNotIn('\n', msg)
1072+
1073+
finally:
1074+
SMTP.send = send

0 commit comments

Comments
 (0)
0