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

ported MailSender class to use twisted non-blocking IO

--HG--
extra : convert_revision : svn%3Ab85faa78-f9eb-468e-a121-7cced6da292c%40708
上级 b0e37dc3
......@@ -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 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.
MailSender class reference
==========================
.. _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)
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)])
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))
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)
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)
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 _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
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册