提交 bd16d1cd 编写于 作者: P Pablo Hoffman

Added SMTP-AUTH support to scrapy.mail (closes #149)

上级 495f23de
...@@ -8,17 +8,15 @@ Sending e-mail ...@@ -8,17 +8,15 @@ Sending e-mail
:synopsis: Email sending facility :synopsis: Email sending facility
Although Python makes sending e-mails relatively easy via the `smtplib`_ Although Python makes sending e-mails relatively easy via the `smtplib`_
library, Scrapy provides its own facility for sending e-mails which is very easy library, Scrapy provides its own facility for sending e-mails which is very
to use and it's implemented using `Twisted non-blocking IO`_, to avoid easy to use and it's implemented using `Twisted non-blocking IO`_, to avoid
interfering with the non-blocking IO of the crawler. interfering with the non-blocking IO of the crawler. It also provides a
simple API for sending attachments and it's very easy to configure, with a few
It's also very easy to configure, having only a few settings. :ref:`settings <topics-email-settings`.
.. _smtplib: http://docs.python.org/library/smtplib.html .. _smtplib: http://docs.python.org/library/smtplib.html
.. _Twisted non-blocking IO: http://twistedmatrix.com/projects/core/documentation/howto/async.html .. _Twisted non-blocking IO: http://twistedmatrix.com/projects/core/documentation/howto/async.html
It also has built-in support for sending attachments.
Quick example Quick example
============= =============
...@@ -35,7 +33,7 @@ MailSender class reference ...@@ -35,7 +33,7 @@ MailSender class reference
MailSender is the preferred class to use for sending emails from Scrapy, as it MailSender is the preferred class to use for sending emails from Scrapy, as it
uses `Twisted non-blocking IO`_, like the rest of the framework. uses `Twisted non-blocking IO`_, like the rest of the framework.
.. class:: MailSender(smtphost, mailfrom) .. class:: MailSender(smtphost=None, mailfrom=None, smtpuser=None, smtppass=None, smtpport=None):
:param smtphost: the SMTP host to use for sending the emails. If omitted, the :param smtphost: the SMTP host to use for sending the emails. If omitted, the
:setting:`MAIL_HOST` setting will be used. :setting:`MAIL_HOST` setting will be used.
...@@ -45,6 +43,17 @@ uses `Twisted non-blocking IO`_, like the rest of the framework. ...@@ -45,6 +43,17 @@ uses `Twisted non-blocking IO`_, like the rest of the framework.
If omitted, the :setting:`MAIL_FROM` setting will be used. If omitted, the :setting:`MAIL_FROM` setting will be used.
:type mailfrom: str :type mailfrom: str
:param smtpuser: the SMTP user. If omitted, the :setting:`MAIL_USER`
setting will be used. If not given, no SMTP authentication will be
performed.
:type smtphost: str
:param smtppass: the SMTP pass for authetnication.
:type smtppass: str
:param smtpport: the SMTP port to connect to
:type smtpport: int
.. method:: send(to, subject, body, cc=None, attachs=()) .. method:: send(to, subject, body, cc=None, attachs=())
Send email to the given recipients. Emits the :signal:`mail_sent` signal. Send email to the given recipients. Emits the :signal:`mail_sent` signal.
...@@ -72,16 +81,69 @@ uses `Twisted non-blocking IO`_, like the rest of the framework. ...@@ -72,16 +81,69 @@ uses `Twisted non-blocking IO`_, like the rest of the framework.
:type attachs: iterable :type attachs: iterable
MailSender settings .. _topics-email-settings:
===================
Mail settings
=============
These settings define the default constructor values of the :class:`MailSender` 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 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): writing any code (for those extensions and code that uses :class:`MailSender`).
.. setting:: MAIL_FROM
MAIL_FROM
---------
Default: ``'scrapy@localhost'``
Sender email to use (``From:`` header) for sending emails.
.. setting:: MAIL_HOST
MAIL_HOST
---------
Default: ``'localhost'``
SMTP host to use for sending emails.
.. setting:: MAIL_PORT
MAIL_PORT
---------
Default: ``25``
SMTP port to use for sending emails.
.. setting:: MAIL_USER
MAIL_USER
---------
Default: ``None``
User to use for SMTP authentication. If disabled no SMTP authentication will be
performed.
.. setting:: MAIL_PASS
MAIL_PASS
---------
Default: ``None``
Password to use for SMTP authentication, along with :setting:`MAIL_USER`.
.. setting:: MAIL_DEBUG
MAIL_DEBUG
----------
Default: ``False``
* :setting:`MAIL_DEBUG` Whether to enable the debugging mode.
* :setting:`MAIL_FROM`
* :setting:`MAIL_HOST`
Mail signals Mail signals
......
...@@ -615,36 +615,6 @@ If ``True``, all standard output (and error) of your process will be redirected ...@@ -615,36 +615,6 @@ 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 to the log. For example if you ``print 'hello'`` it will appear in the Scrapy
log. 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
---------
Default: ``'scrapy@localhost'``
Email to use as sender address for sending emails using the :ref:`Scrapy e-mail
sending facility <topics-email>`.
.. setting:: MAIL_HOST
MAIL_HOST
---------
Default: ``'localhost'``
Host to use for sending emails using the :ref:`Scrapy e-mail sending facility
<topics-email>`.
.. setting:: MEMDEBUG_ENABLED .. setting:: MEMDEBUG_ENABLED
MEMDEBUG_ENABLED MEMDEBUG_ENABLED
......
...@@ -138,7 +138,10 @@ LOG_FILE = None ...@@ -138,7 +138,10 @@ LOG_FILE = None
MAIL_DEBUG = False MAIL_DEBUG = False
MAIL_HOST = 'localhost' MAIL_HOST = 'localhost'
MAIL_PORT = 25
MAIL_FROM = 'scrapy@localhost' MAIL_FROM = 'scrapy@localhost'
MAIL_PASS = None
MAIL_USER = None
MEMDEBUG_ENABLED = False # enable memory debugging MEMDEBUG_ENABLED = False # enable memory debugging
MEMDEBUG_NOTIFY = [] # send memory debugging report by mail at engine shutdown MEMDEBUG_NOTIFY = [] # send memory debugging report by mail at engine shutdown
......
...@@ -12,7 +12,7 @@ from email.Utils import COMMASPACE, formatdate ...@@ -12,7 +12,7 @@ from email.Utils import COMMASPACE, formatdate
from email import Encoders from email import Encoders
from twisted.internet import defer, reactor from twisted.internet import defer, reactor
from twisted.mail.smtp import SMTPSenderFactory from twisted.mail.smtp import ESMTPSenderFactory
from scrapy import log from scrapy import log
from scrapy.core.exceptions import NotConfigured from scrapy.core.exceptions import NotConfigured
...@@ -27,9 +27,13 @@ mail_sent = object() ...@@ -27,9 +27,13 @@ mail_sent = object()
class MailSender(object): class MailSender(object):
def __init__(self, smtphost=None, mailfrom=None): def __init__(self, smtphost=None, mailfrom=None, smtpuser=None, smtppass=None, \
self.smtphost = smtphost if smtphost else settings['MAIL_HOST'] smtpport=None):
self.mailfrom = mailfrom if mailfrom else settings['MAIL_FROM'] self.smtphost = smtphost or settings['MAIL_HOST']
self.smtpport = smtpport or settings.getint('MAIL_PORT')
self.smtpuser = smtpuser or settings['MAIL_USER']
self.smtppass = smtppass or settings['MAIL_PASS']
self.mailfrom = mailfrom or settings['MAIL_FROM']
if not self.smtphost or not self.mailfrom: if not self.smtphost or not self.mailfrom:
raise NotConfigured("MAIL_HOST and MAIL_FROM settings are required") raise NotConfigured("MAIL_HOST and MAIL_FROM settings are required")
...@@ -68,11 +72,12 @@ class MailSender(object): ...@@ -68,11 +72,12 @@ class MailSender(object):
(to, cc, subject, len(attachs)), level=log.DEBUG) (to, cc, subject, len(attachs)), level=log.DEBUG)
return return
dfd = self._sendmail(self.smtphost, self.mailfrom, rcpts, msg.as_string()) dfd = self._sendmail(rcpts, msg.as_string())
dfd.addCallbacks(self._sent_ok, self._sent_failed, dfd.addCallbacks(self._sent_ok, self._sent_failed,
callbackArgs=[to, cc, subject, len(attachs)], callbackArgs=[to, cc, subject, len(attachs)],
errbackArgs=[to, cc, subject, len(attachs)]) errbackArgs=[to, cc, subject, len(attachs)])
reactor.addSystemEventTrigger('before', 'shutdown', lambda: dfd) reactor.addSystemEventTrigger('before', 'shutdown', lambda: dfd)
return dfd
def _sent_ok(self, result, to, cc, subject, nattachs): def _sent_ok(self, result, to, cc, subject, nattachs):
log.msg('Mail sent OK: To=%s Cc=%s Subject="%s" Attachs=%d' % \ log.msg('Mail sent OK: To=%s Cc=%s Subject="%s" Attachs=%d' % \
...@@ -83,13 +88,12 @@ class MailSender(object): ...@@ -83,13 +88,12 @@ class MailSender(object):
log.msg('Unable to send mail: To=%s Cc=%s Subject="%s" Attachs=%d - %s' % \ log.msg('Unable to send mail: To=%s Cc=%s Subject="%s" Attachs=%d - %s' % \
(to, cc, subject, nattachs, errstr), level=log.ERROR) (to, cc, subject, nattachs, errstr), level=log.ERROR)
def _sendmail(self, smtphost, from_addr, to_addrs, msg, port=25): def _sendmail(self, to_addrs, msg):
""" This is based on twisted.mail.smtp.sendmail except that it
instantiates a quiet (noisy=False) SMTPSenderFactory """
msg = StringIO(msg) msg = StringIO(msg)
d = defer.Deferred() d = defer.Deferred()
factory = SMTPSenderFactory(from_addr, to_addrs, msg, d) factory = ESMTPSenderFactory(self.smtpuser, self.smtppass, self.mailfrom, \
to_addrs, msg, d, heloFallback=True, requireAuthentication=False, \
requireTransportSecurity=False)
factory.noisy = False factory.noisy = False
reactor.connectTCP(smtphost, port, factory) reactor.connectTCP(self.smtphost, self.smtpport, factory)
return d return d
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册