File: mail.py

package info (click to toggle)
python-scrapy 0.8-3
  • links: PTS, VCS
  • area: main
  • in suites: squeeze
  • size: 2,904 kB
  • ctags: 2,981
  • sloc: python: 15,349; xml: 199; makefile: 68; sql: 64; sh: 34
file content (88 lines) | stat: -rw-r--r-- 3,585 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
"""
Mail sending helpers

See documentation in docs/topics/email.rst
"""
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

class MailSender(object):

    def __init__(self, smtphost=None, mailfrom=None):
        self.smtphost = smtphost if smtphost else settings['MAIL_HOST']
        self.mailfrom = mailfrom if mailfrom else settings['MAIL_FROM']

        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=()):
        if attachs:
            msg = MIMEMultipart()
        else:
            msg = MIMENonMultipart('text', 'plain')
        msg['From'] = self.mailfrom
        msg['To'] = COMMASPACE.join(to)
        msg['Date'] = formatdate(localtime=True)
        msg['Subject'] = subject
        rcpts = to[:]
        if cc:
            rcpts.extend(cc)
            msg['Cc'] = COMMASPACE.join(cc)

        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)

        # FIXME ---------------------------------------------------------------------
        # There seems to be a problem with sending emails using deferreds when
        # the last thing left to do is sending the mail, cause the engine stops
        # the reactor and the email don't get send. we need to fix this. until
        # then, we'll revert to use Python standard (IO-blocking) smtplib.

        #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)])
        import smtplib
        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