Kaydet (Commit) d5fbe9b1 authored tarafından Pablo Aguiar's avatar Pablo Aguiar Kaydeden (comit) Pablo Galindo

bpo-34246: Use no mutable default args in smtplib (GH-8554)

Some methods of the SMTP class use mutable default arguments. Specially
`send_message` is affected as it mutates one of the args by appending items
to it, which has side effects on further calls.
üst 4e519377
...@@ -419,7 +419,7 @@ An :class:`SMTP` instance has the following methods: ...@@ -419,7 +419,7 @@ An :class:`SMTP` instance has the following methods:
:exc:`SMTPException`. :exc:`SMTPException`.
.. method:: SMTP.sendmail(from_addr, to_addrs, msg, mail_options=[], rcpt_options=[]) .. method:: SMTP.sendmail(from_addr, to_addrs, msg, mail_options=(), rcpt_options=())
Send mail. The required arguments are an :rfc:`822` from-address string, a list Send mail. The required arguments are an :rfc:`822` from-address string, a list
of :rfc:`822` to-address strings (a bare string will be treated as a list with 1 of :rfc:`822` to-address strings (a bare string will be treated as a list with 1
...@@ -491,7 +491,7 @@ An :class:`SMTP` instance has the following methods: ...@@ -491,7 +491,7 @@ An :class:`SMTP` instance has the following methods:
.. method:: SMTP.send_message(msg, from_addr=None, to_addrs=None, \ .. method:: SMTP.send_message(msg, from_addr=None, to_addrs=None, \
mail_options=[], rcpt_options=[]) mail_options=(), rcpt_options=())
This is a convenience method for calling :meth:`sendmail` with the message This is a convenience method for calling :meth:`sendmail` with the message
represented by an :class:`email.message.Message` object. The arguments have represented by an :class:`email.message.Message` object. The arguments have
......
...@@ -513,7 +513,7 @@ class SMTP: ...@@ -513,7 +513,7 @@ class SMTP:
"""SMTP 'noop' command -- doesn't do anything :>""" """SMTP 'noop' command -- doesn't do anything :>"""
return self.docmd("noop") return self.docmd("noop")
def mail(self, sender, options=[]): def mail(self, sender, options=()):
"""SMTP 'mail' command -- begins mail xfer session. """SMTP 'mail' command -- begins mail xfer session.
This method may raise the following exceptions: This method may raise the following exceptions:
...@@ -534,7 +534,7 @@ class SMTP: ...@@ -534,7 +534,7 @@ class SMTP:
self.putcmd("mail", "FROM:%s%s" % (quoteaddr(sender), optionlist)) self.putcmd("mail", "FROM:%s%s" % (quoteaddr(sender), optionlist))
return self.getreply() return self.getreply()
def rcpt(self, recip, options=[]): def rcpt(self, recip, options=()):
"""SMTP 'rcpt' command -- indicates 1 recipient for this mail.""" """SMTP 'rcpt' command -- indicates 1 recipient for this mail."""
optionlist = '' optionlist = ''
if options and self.does_esmtp: if options and self.does_esmtp:
...@@ -785,8 +785,8 @@ class SMTP: ...@@ -785,8 +785,8 @@ class SMTP:
raise SMTPResponseException(resp, reply) raise SMTPResponseException(resp, reply)
return (resp, reply) return (resp, reply)
def sendmail(self, from_addr, to_addrs, msg, mail_options=[], def sendmail(self, from_addr, to_addrs, msg, mail_options=(),
rcpt_options=[]): rcpt_options=()):
"""This command performs an entire mail transaction. """This command performs an entire mail transaction.
The arguments are: The arguments are:
...@@ -890,7 +890,7 @@ class SMTP: ...@@ -890,7 +890,7 @@ class SMTP:
return senderrs return senderrs
def send_message(self, msg, from_addr=None, to_addrs=None, def send_message(self, msg, from_addr=None, to_addrs=None,
mail_options=[], rcpt_options={}): mail_options=(), rcpt_options=()):
"""Converts message to a bytestring and passes it to sendmail. """Converts message to a bytestring and passes it to sendmail.
The arguments are as for sendmail, except that msg is an The arguments are as for sendmail, except that msg is an
...@@ -958,7 +958,7 @@ class SMTP: ...@@ -958,7 +958,7 @@ class SMTP:
if international: if international:
g = email.generator.BytesGenerator( g = email.generator.BytesGenerator(
bytesmsg, policy=msg.policy.clone(utf8=True)) bytesmsg, policy=msg.policy.clone(utf8=True))
mail_options += ['SMTPUTF8', 'BODY=8BITMIME'] mail_options = (*mail_options, 'SMTPUTF8', 'BODY=8BITMIME')
else: else:
g = email.generator.BytesGenerator(bytesmsg) g = email.generator.BytesGenerator(bytesmsg)
g.flatten(msg_copy, linesep='\r\n') g.flatten(msg_copy, linesep='\r\n')
......
...@@ -20,6 +20,7 @@ import threading ...@@ -20,6 +20,7 @@ import threading
import unittest import unittest
from test import support, mock_socket from test import support, mock_socket
from test.support import HOST, HOSTv4, HOSTv6 from test.support import HOST, HOSTv4, HOSTv6
from unittest.mock import Mock
if sys.platform == 'darwin': if sys.platform == 'darwin':
...@@ -578,6 +579,33 @@ class NonConnectingTests(unittest.TestCase): ...@@ -578,6 +579,33 @@ class NonConnectingTests(unittest.TestCase):
"localhost:bogus") "localhost:bogus")
class DefaultArgumentsTests(unittest.TestCase):
def setUp(self):
self.msg = EmailMessage()
self.msg['From'] = 'Páolo <főo@bar.com>'
self.smtp = smtplib.SMTP()
self.smtp.ehlo = Mock(return_value=(200, 'OK'))
self.smtp.has_extn, self.smtp.sendmail = Mock(), Mock()
def testSendMessage(self):
expected_mail_options = ('SMTPUTF8', 'BODY=8BITMIME')
self.smtp.send_message(self.msg)
self.smtp.send_message(self.msg)
self.assertEqual(self.smtp.sendmail.call_args_list[0][0][3],
expected_mail_options)
self.assertEqual(self.smtp.sendmail.call_args_list[1][0][3],
expected_mail_options)
def testSendMessageWithMailOptions(self):
mail_options = ['STARTTLS']
expected_mail_options = ('STARTTLS', 'SMTPUTF8', 'BODY=8BITMIME')
self.smtp.send_message(self.msg, None, None, mail_options)
self.assertEqual(mail_options, ['STARTTLS'])
self.assertEqual(self.smtp.sendmail.call_args_list[0][0][3],
expected_mail_options)
# test response of client to a non-successful HELO message # test response of client to a non-successful HELO message
class BadHELOServerTests(unittest.TestCase): class BadHELOServerTests(unittest.TestCase):
......
...@@ -22,6 +22,7 @@ Eitan Adler ...@@ -22,6 +22,7 @@ Eitan Adler
Anton Afanasyev Anton Afanasyev
Ali Afshar Ali Afshar
Nitika Agarwal Nitika Agarwal
Pablo S. Blum de Aguiar
Jim Ahlstrom Jim Ahlstrom
Farhan Ahmad Farhan Ahmad
Matthew Ahrens Matthew Ahrens
......
:meth:`smtplib.SMTP.send_message` no longer modifies the content of the
*mail_options* argument. Patch by Pablo S. Blum de Aguiar.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment