8000 [1.7.x] Fixed #23063 -- Convert \n and \r to \r\n when using the SMTP… · alex-python/django@bc13a08 · GitHub
[go: up one dir, main page]

Skip to content

Commit bc13a08

Browse files
committed
[1.7.x] Fixed #23063 -- Convert \n and \r to \r\n when using the SMTP backend as per RFC.
Backport of 8d78944 from master.
1 parent d2a2af6 commit bc13a08

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
@@ -112,7 +112,7 @@ def _send(self, email_message):
112112
for addr in email_message.recipients()]
113113
message = email_message.message()
114114
try:
115-
self.connection.sendmail(from_email, recipients, message.as_bytes())
115+
self.connection.sendmail(from_email, recipients, message.as_bytes(linesep='\r\n'))
116116
except smtplib.SMTPException:
117117
if not self.fail_silently:
118118
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
@@ -114,3 +114,5 @@ Bugfixes
114114
(:ticket:`23609`).
115115

116116
* Fixed generic relations in ``ModelAdmin.list_filter`` (:ticket:`23616`).
117+
118+
* 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
@@ -984,3 +984,37 @@ def __init__(self, *args, **kwargs):
984984
self.assertEqual(myemailbackend.timeout, 42)
985985
self.assertEqual(myemailbackend.connection.timeout, 42)
986986
myemailbackend.close()
987+
988+
def test_email_msg_uses_crlf(self):
989+
"""#23063 -- Test that RFC-compliant messages are sent over SMTP."""
990+
send = SMTP.send
991+
try:
992+
smtp_messages = []
993+
994+
def mock_send(self, s):
995+
smtp_messages.append(s)
996+
return send(self, s)
997+
998+
SMTP.send = mock_send
999+
1000+
email = EmailMessage('Subject', 'Content', 'from@example.com', ['to@example.com'])
1001+
mail.get_connection().send_messages([email])
1002+
1003+
# Find the actual message
1004+
msg = None
1005+
for i, m in enumerate(smtp_messages):
1006+
if m[:4] == 'data':
1007+
msg = smtp_messages[i+1]
1008+
break
1009+
1010+
self.assertTrue(msg)
1011+
1012+
if PY3:
1013+
msg = msg.decode('utf-8')
1014+
# Ensure that the message only contains CRLF and not combinations of CRLF, LF, and CR.
1015+
msg = msg.replace('\r\n', '')
1016+
self.assertNotIn('\r', msg)
1017+
self.assertNotIn('\n', msg)
1018+
1019+
finally:
1020+
SMTP.send = send

0 commit comments

Comments
 (0)
0