mirror of https://github.com/scrapy/scrapy.git
ported MailSender class to use twisted non-blocking IO
--HG-- extra : convert_revision : svn%3Ab85faa78-f9eb-468e-a121-7cced6da292c%40708
This commit is contained in:
parent
b0e37dc36a
commit
d0046196d8
|
|
@ -7,13 +7,14 @@ Sending email
|
|||
.. module:: scrapy.mail
|
||||
:synopsis: Helpers to easily send e-mail.
|
||||
|
||||
Although Python makes sending e-mail relatively easy via the `smtplib library`_,
|
||||
Scrapy provides a couple of light wrappers over it, to make sending e-mail
|
||||
extra quick.
|
||||
Although Python makes sending e-mail relatively easy via the `smtplib`_
|
||||
library, Scrapy provides its own class for sending emails which is very easy to
|
||||
use and it's implemented using `Twisted non-blocking IO`_, to avoid affecting
|
||||
the crawling performance.
|
||||
|
||||
The code lives in a single module: ``scrapy.mail``.
|
||||
.. _smtplib: http://docs.python.org/library/smtplib.html
|
||||
|
||||
.. _smtplib library: http://docs.python.org/library/smtplib.html
|
||||
It also has built-in support for sending attachments.
|
||||
|
||||
Quick example
|
||||
=============
|
||||
|
|
@ -25,14 +26,11 @@ Here's a quick example of how to send an email (without attachments)::
|
|||
mailer = MailSender()
|
||||
mailer.send(to=["someone@example.com"], "Some subject", "Some body", cc=["another@example.com"])
|
||||
|
||||
MailSender class
|
||||
================
|
||||
MailSender class reference
|
||||
==========================
|
||||
|
||||
MailSender is the class used to send emails from Scrapy. It's
|
||||
currently only a wrapper over the (IO blocking) `smtplib`_
|
||||
library but it's gonna be ported to Twisted soon.
|
||||
|
||||
.. _smtplib: http://docs.python.org/library/smtplib.html
|
||||
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.
|
||||
|
||||
.. class:: scrapy.mail.MailSender(smtphost, mailfrom)
|
||||
|
||||
|
|
@ -42,7 +40,7 @@ library but it's gonna be ported to Twisted soon.
|
|||
``mailfrom`` is a string with the email address to use for sending messages
|
||||
(in the ``From:`` header). If omitted, :setting:`MAIL_FROM` will be used.
|
||||
|
||||
.. method:: send(to, subject, body, cc=None, attachs=None)
|
||||
.. method:: send(to, subject, body, cc=None, attachs=())
|
||||
|
||||
Send mail to the given recipients
|
||||
|
||||
|
|
@ -59,3 +57,5 @@ library but it's gonna be ported to Twisted soon.
|
|||
``mimetype`` is the mimetype of the attachment
|
||||
``file_object`` is a readable file object
|
||||
|
||||
|
||||
.. _Twisted non-blocking IO: http://twistedmatrix.com/projects/core/documentation/howto/async.html
|
||||
|
|
|
|||
|
|
@ -3,14 +3,17 @@ Mail sending helpers
|
|||
|
||||
See documentation in docs/ref/email.rst
|
||||
"""
|
||||
import smtplib
|
||||
|
||||
from cStringIO import StringIO
|
||||
from email.MIMEMultipart import MIMEMultipart
|
||||
from email.MIMENonMultipart import MIMENonMultipart
|
||||
from email.MIMEBase import MIMEBase
|
||||
from email.MIMEText import MIMEText
|
||||
from email.Utils import COMMASPACE, formatdate
|
||||
from email import Encoders
|
||||
|
||||
from twisted.internet import defer, reactor
|
||||
from twisted.mail.smtp import SMTPSenderFactory
|
||||
|
||||
from scrapy import log
|
||||
from scrapy.core.exceptions import NotConfigured
|
||||
from scrapy.conf import settings
|
||||
|
|
@ -24,8 +27,11 @@ class MailSender(object):
|
|||
if not self.smtphost or not self.mailfrom:
|
||||
raise NotConfigured("MAIL_HOST and MAIL_FROM settings are required")
|
||||
|
||||
def send(self, to, subject, body, cc=None, attachs=None):
|
||||
msg = MIMEMultipart()
|
||||
def send(self, to, subject, body, cc=None, attachs=()):
|
||||
if attachs:
|
||||
msg = MIMEMultipart()
|
||||
else:
|
||||
msg = MIMENonMultipart('text', 'plain')
|
||||
msg['From'] = self.mailfrom
|
||||
msg['To'] = COMMASPACE.join(to)
|
||||
msg['Date'] = formatdate(localtime=True)
|
||||
|
|
@ -35,17 +41,36 @@ class MailSender(object):
|
|||
rcpts.extend(cc)
|
||||
msg['Cc'] = COMMASPACE.join(cc)
|
||||
|
||||
msg.attach(MIMEText(body))
|
||||
if attachs:
|
||||
msg.attach(MIMEText(body))
|
||||
for attach_name, mimetype, f in attachs:
|
||||
part = MIMEBase(*mimetype.split('/'))
|
||||
part.set_payload(f.read())
|
||||
Encoders.encode_base64(part)
|
||||
part.add_header('Content-Disposition', 'attachment; filename="%s"' % attach_name)
|
||||
msg.attach(part)
|
||||
else:
|
||||
msg.set_payload(body)
|
||||
|
||||
for attach_name, mimetype, f in (attachs or []):
|
||||
part = MIMEBase(*mimetype.split('/'))
|
||||
part.set_payload(f.read())
|
||||
Encoders.encode_base64(part)
|
||||
part.add_header('Content-Disposition', 'attachment; filename="%s"' % attach_name)
|
||||
msg.attach(part)
|
||||
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)],
|
||||
errbackArgs=[to, cc, subject, len(attachs)])
|
||||
|
||||
smtp = smtplib.SMTP(self.smtphost)
|
||||
smtp.sendmail(self.mailfrom, rcpts, msg.as_string())
|
||||
log.msg('Mail sent: To=%s Cc=%s Subject="%s"' % (to, cc, subject))
|
||||
smtp.close()
|
||||
def _sent_ok(self, result, to, cc, subject, nattachs):
|
||||
log.msg('Mail sent OK: To=%s Cc=%s Subject="%s" Attachs=%d' % (to, cc, subject, nattachs))
|
||||
|
||||
def _sent_failed(self, failure, to, cc, subject, nattachs):
|
||||
errstr = str(failure.value)
|
||||
log.msg('Unable to send mail: To=%s Cc=%s Subject="%s" Attachs=%d - %s' % (to, cc, subject, nattachs, errstr), level=log.ERROR)
|
||||
|
||||
def _sendmail(self, smtphost, from_addr, to_addrs, msg, port=25):
|
||||
""" This is based on twisted.mail.smtp.sendmail except that it
|
||||
instantiates a quiet (noisy=False) SMTPSenderFactory """
|
||||
msg = StringIO(msg)
|
||||
d = defer.Deferred()
|
||||
factory = SMTPSenderFactory(from_addr, to_addrs, msg, d)
|
||||
factory.noisy = False
|
||||
reactor.connectTCP(smtphost, port, factory)
|
||||
return d
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue