Repository: scrapy/scrapy

Issue:
Accept single values for "to" and "cc" arguments when sending mails
Follow up to https://github.com/scrapy/scrapy/pull/2271#issuecomment-248341246

> What about checking for strings and raising an error?
> Passing a string is an easy mistake to make.
> Or maybe we can support passing a single string.


Discussion:
Hey @redapple, I would like to work on this. Can you tell me if checking for `isinstance`  of `basestring` a good idea so I can cast the `to` argument into a `list` ?

hi @kirankoduru , thanks for stepping in!
keep in mind that `basestring` is not in Python 3.
You may want to look at something like [`arg_to_iter`](https://github.com/scrapy/scrapy/blob/b6375d3701b72ca1ce28c32fd90741b0864db05f/scrapy/utils/misc.py#L17) which does tests for single valued arguments in a Python2/Python3 compatible way.

@redapple that's exactly what I was looking for! I will create a PR soon. Thanks :)

Hey @kirankoduru are you still working on this?

hey @lfmattossch I was working last weekend. Some reasons my tests weren't passing. I was under the impression that `tox` was the command to run them. Is there any other way to run them? Also if you want to work on it please go ahead and start.

hi @kirankoduru, I'm with @lfmattossch. I'm already running the unit tests on a fix. Thanks for updating us.

@moisesguimaraes @lfmattossch great guys. Has the fix been pushed yet? I wonder how it was merged without passing tests.

not yet. I'm testing it locally.


Resolving patch:
diff --git a/scrapy/mail.py b/scrapy/mail.py
--- a/scrapy/mail.py
+++ b/scrapy/mail.py
@@ -21,6 +21,8 @@
 
 from twisted.internet import defer, reactor, ssl
 
+from .utils.misc import arg_to_iter
+
 logger = logging.getLogger(__name__)
 
 
@@ -48,6 +50,10 @@ def send(self, to, subject, body, cc=None, attachs=(), mimetype='text/plain', ch
             msg = MIMEMultipart()
         else:
             msg = MIMENonMultipart(*mimetype.split('/', 1))
+
+        to = list(arg_to_iter(to))
+        cc = list(arg_to_iter(cc))
+
         msg['From'] = self.mailfrom
         msg['To'] = COMMASPACE.join(to)
         msg['Date'] = formatdate(localtime=True)


Test patch:
diff --git a/tests/test_mail.py b/tests/test_mail.py
--- a/tests/test_mail.py
+++ b/tests/test_mail.py
@@ -10,7 +10,8 @@ class MailSenderTest(unittest.TestCase):
 
     def test_send(self):
         mailsender = MailSender(debug=True)
-        mailsender.send(to=['test@scrapy.org'], subject='subject', body='body', _callback=self._catch_mail_sent)
+        mailsender.send(to=['test@scrapy.org'], subject='subject', body='body',
+                        _callback=self._catch_mail_sent)
 
         assert self.catched_msg
 
@@ -24,9 +25,16 @@ def test_send(self):
         self.assertEqual(msg.get_payload(), 'body')
         self.assertEqual(msg.get('Content-Type'), 'text/plain')
 
+    def test_send_single_values_to_and_cc(self):
+        mailsender = MailSender(debug=True)
+        mailsender.send(to='test@scrapy.org', subject='subject', body='body',
+                        cc='test@scrapy.org', _callback=self._catch_mail_sent)
+
     def test_send_html(self):
         mailsender = MailSender(debug=True)
-        mailsender.send(to=['test@scrapy.org'], subject='subject', body='<p>body</p>', mimetype='text/html', _callback=self._catch_mail_sent)
+        mailsender.send(to=['test@scrapy.org'], subject='subject',
+                        body='<p>body</p>', mimetype='text/html',
+                        _callback=self._catch_mail_sent)
 
         msg = self.catched_msg['msg']
         self.assertEqual(msg.get_payload(), '<p>body</p>')
@@ -90,7 +98,8 @@ def test_send_attach_utf8(self):
 
         mailsender = MailSender(debug=True)
         mailsender.send(to=['test@scrapy.org'], subject=subject, body=body,
-                        attachs=attachs, charset='utf-8', _callback=self._catch_mail_sent)
+                        attachs=attachs, charset='utf-8',
+                        _callback=self._catch_mail_sent)
 
         assert self.catched_msg
         self.assertEqual(self.catched_msg['subject'], subject)
@@ -99,7 +108,8 @@ def test_send_attach_utf8(self):
         msg = self.catched_msg['msg']
         self.assertEqual(msg['subject'], subject)
         self.assertEqual(msg.get_charset(), Charset('utf-8'))
-        self.assertEqual(msg.get('Content-Type'), 'multipart/mixed; charset="utf-8"')
+        self.assertEqual(msg.get('Content-Type'),
+                         'multipart/mixed; charset="utf-8"')
 
         payload = msg.get_payload()
         assert isinstance(payload, list)