Some mail improvements and tests.

* Add mail_sent signal and use it in MailSender
* Add MAIL_DEBUG setting to not send mails when testing
* Add MailSender tests
This commit is contained in:
Ismael Carnales 2010-05-28 16:51:47 -03:00
parent dfa7b23959
commit a71dc295af
5 changed files with 132 additions and 1 deletions

View File

@ -47,7 +47,10 @@ uses `Twisted non-blocking IO`_, like the rest of the framework.
.. method:: send(to, subject, body, cc=None, attachs=())
Send email to the given recipients
Send email to the given recipients. Emits the :signal:`mail_sent` signal.
If :setting:`MAIL_DEBUG` is enabled the :signal:`mail_sent` signal will
be emmited and no actual email will be sent.
:param to: the e-mail recipients
:type to: list
@ -76,6 +79,37 @@ These settings define the default constructor values of the :class:`MailSender`
class, and can be used to configure e-mail notifications in your project without
writing any code (for those extensions that use the :class:`MailSender` class):
* :setting:`MAIL_DEBUG`
* :setting:`MAIL_FROM`
* :setting:`MAIL_HOST`
Mail signals
============
.. signal:: mail_sent
.. function:: mail_sent(to, subject, body, cc, attachs, msg)
Emitted by :meth:`MailSender.send` after an email has been sent.
:param to: the e-mail recipients
:type to: list
:param subject: the subject of the e-mail
:type subject: str
:param cc: the e-mails to CC
:type cc: list
:param body: the e-mail body
:type body: str
:param attachs: an iterable of tuples ``(attach_name, mimetype,
file_object)`` where ``attach_name`` is a string with the name that will
appear on the e-mail's attachment, ``mimetype`` is the mimetype of the
attachment and ``file_object`` is a readable file object with the
contents of the attachment
:type attachs: iterable
:param msg: the generated message
:type msg: ``MIMEMultipart`` or ``MIMENonMultipart``

View File

@ -620,6 +620,16 @@ If ``True``, all standard output (and error) of your process will be redirected
to the log. For example if you ``print 'hello'`` it will appear in the Scrapy
log.
.. setting:: MAIL_DEBUG
MAIL_DEBUG
----------
Default: ``False``
Whether to enable the debugging mode in the the :ref:`Scrapy e-mail sending
facility <topics-email>`.
.. setting:: MAIL_FROM
MAIL_FROM

View File

@ -141,6 +141,7 @@ LOG_STDOUT = False
LOG_LEVEL = 'DEBUG'
LOG_FILE = None
MAIL_DEBUG = False
MAIL_HOST = 'localhost'
MAIL_FROM = 'scrapy@localhost'

View File

@ -17,6 +17,13 @@ from twisted.mail.smtp import SMTPSenderFactory
from scrapy import log
from scrapy.core.exceptions import NotConfigured
from scrapy.conf import settings
from scrapy.utils.signal import send_catch_log
# signal sent when message is sent
# args: to, subject, body, cc, attach, msg
mail_sent = object()
class MailSender(object):
@ -53,6 +60,14 @@ class MailSender(object):
else:
msg.set_payload(body)
send_catch_log(signal=mail_sent, to=to, subject=subject, body=body,
cc=cc, attach=attachs, msg=msg)
if settings.getbool('MAIL_DEBUG'):
log.msg('Debug mail sent OK: To=%s Cc=%s Subject="%s" Attachs=%d' % \
(to, cc, subject, len(attachs)), level=log.DEBUG)
return
dfd = self._sendmail(self.smtphost, self.mailfrom, rcpts, msg.as_string())
dfd.addCallbacks(self._sent_ok, self._sent_failed,
callbackArgs=[to, cc, subject, len(attachs)],

71
scrapy/tests/test_mail.py Normal file
View File

@ -0,0 +1,71 @@
from cStringIO import StringIO
import unittest
from scrapy.xlib.pydispatch import dispatcher
from scrapy.conf import settings
from scrapy.mail import MailSender, mail_sent
class MailSenderTest(unittest.TestCase):
def setUp(self):
settings.disabled = False
settings.overrides['MAIL_DEBUG'] = True
self.catched_msg = None
dispatcher.connect(self._catch_mail_sent, signal=mail_sent)
def test_send(self):
mailsender = MailSender()
mailsender.send(to=['test@scrapy.org'], subject='subject', body='body')
assert self.catched_msg
self.assertEqual(self.catched_msg['to'], ['test@scrapy.org'])
self.assertEqual(self.catched_msg['subject'], 'subject')
self.assertEqual(self.catched_msg['body'], 'body')
msg = self.catched_msg['msg']
self.assertEqual(msg['to'], 'test@scrapy.org')
self.assertEqual(msg['subject'], 'subject')
self.assertEqual(msg.get_payload(), 'body')
def test_send_attach(self):
attach = StringIO()
attach.write('content')
attach.seek(0)
attachs = [('attachment', 'text/plain', attach)]
mailsender = MailSender()
mailsender.send(to=['test@scrapy.org'], subject='subject', body='body',
attachs=attachs)
assert self.catched_msg
self.assertEqual(self.catched_msg['to'], ['test@scrapy.org'])
self.assertEqual(self.catched_msg['subject'], 'subject')
self.assertEqual(self.catched_msg['body'], 'body')
msg = self.catched_msg['msg']
self.assertEqual(msg['to'], 'test@scrapy.org')
self.assertEqual(msg['subject'], 'subject')
payload = msg.get_payload()
assert isinstance(payload, list)
self.assertEqual(len(payload), 2)
text, attach = payload
self.assertEqual(text.get_payload(decode=True), 'body')
self.assertEqual(attach.get_payload(decode=True), 'content')
def tearDown(self):
del settings.overrides['MAIL_DEBUG']
settings.disabled = True
def _catch_mail_sent(self, **kwargs):
self.catched_msg = dict(**kwargs)
if __name__ == "__main__":
unittest.main()