| | 1 | # encoding: utf-8 |
| | 2 | |
| | 3 | """TurboMail extension API.""" |
| | 4 | |
| | 5 | import logging |
| | 6 | log = logging.getLogger("turbomail.provider") |
| | 7 | deliverylog = logging.getLogger("turbomail.delivery") |
| | 8 | |
| | 9 | import turbomail |
| | 10 | from turbomail import config |
| | 11 | from turbomail.api import ProviderFactory, Provider |
| | 12 | from turbomail.exceptions import MailConfigurationError, ProviderExhaustedException |
| | 13 | |
| | 14 | __all__ = ['load'] |
| | 15 | |
| | 16 | |
| | 17 | def load(): |
| | 18 | return SMTPProviderFactory() |
| | 19 | |
| | 20 | |
| | 21 | class SMTPProvider(Provider): |
| | 22 | def __init__(self): |
| | 23 | super(SMTPProvider, self).__init__() |
| | 24 | log.debug("Being created.") |
| | 25 | |
| | 26 | self.server = config.get("mail.smtp.server", "localhost") |
| | 27 | self.user = config.get("mail.smtp.user", None) |
| | 28 | self.password = config.get("mail.smtp.password", None) |
| | 29 | self.tls = config.get("mail.smtp.tls", None) |
| | 30 | self.debug = config.get("mail.smtp.debug", False) |
| | 31 | self.count = config.get("mail.smtp.count", 10) # The number of messages per connection. |
| | 32 | |
| | 33 | # Defaults to localhost -- if self.server is None: raise MailConfigurationError, "You must define mail.smtp.server in your configuration." |
| | 34 | |
| | 35 | self.connection = SMTP() |
| | 36 | self.connection.set_debuglevel(self.debug) |
| | 37 | |
| | 38 | log.info("Connecting to SMTP server %s." % self.server) |
| | 39 | self.connection.connect(self.server) |
| | 40 | |
| | 41 | if self.tls or self.tls is None: |
| | 42 | self.connection.ehlo() |
| | 43 | |
| | 44 | if self.connection.has_extn('STARTTLS') or self.tls: |
| | 45 | self.connection.starttls() |
| | 46 | self.connection.ehlo() |
| | 47 | log.info("TLS enabled on SMTP server.") |
| | 48 | self.tls = True |
| | 49 | |
| | 50 | else: |
| | 51 | log.warn("TLS unavailable. Messages will be delivered insecurely.") |
| | 52 | self.tls = False |
| | 53 | |
| | 54 | if self.username and self.password: |
| | 55 | log.info("Authenticating as %s." % self.username) |
| | 56 | self.connection.login(self.username, self.password) |
| | 57 | |
| | 58 | def __del__(self): |
| | 59 | log.debug("Closing SMTP connection.") |
| | 60 | |
| | 61 | if self.connected: |
| | 62 | self.connection.quit() |
| | 63 | |
| | 64 | super(SMTPProvider, self).__del__() |
| | 65 | |
| | 66 | connected = property(lambda self: getattr(self.connection, 'sock', None) is not None) |
| | 67 | |
| | 68 | def deliver(self, message): |
| | 69 | log.info("Attempting delivery of message %s." % message.id) |
| | 70 | deliverylog.info("%s DELIVER" % message.id) |
| | 71 | deliverylog.debug("%s SUBJECT \"%s\"" % (message.id, message.subject)) |
| | 72 | deliverylog.debug("%s SENDER \"%s\"" % (message.id, str(message.sender))) |
| | 73 | deliverylog.debug("%s RECIPIENTS %s" % (message.id, ", ".join(message.recipients))) |
| | 74 | |
| | 75 | try: |
| | 76 | self.count -= 1 |
| | 77 | self.connection.sendmail(str(message.sender), , pack['message']) |
| | 78 | |
| | 79 | except SMTPRecipientsRefused, ex: |
| | 80 | # One or more recipients were refused. Log which recipients. |
| | 81 | # This allows you to automatically parse your logs for bad e-mail addresses. |
| | 82 | deliverylog.warning("%s REFUSED %s %s" % (message.id, e.__class__.__name__, e.message)) |
| | 83 | raise |
| | 84 | |
| | 85 | except SMTPSenderRefused, e: |
| | 86 | # The envelope sender was refused. This is bad. |
| | 87 | deliverylog.error("%s REFUSED %s %s" % (message.id, e.__class__.__name__, e.message)) |
| | 88 | raise |
| | 89 | |
| | 90 | except Exception, e: |
| | 91 | deliverylog.debug("%s EXCEPTION %s %s" % (message.id, e.__class__.__name__, e.message), exc_info=True) |
| | 92 | |
| | 93 | if message.tries > 0: |
| | 94 | deliverylog.warning("%s DEFERRED %s %s" % (message.id, e.__class__.__name__, e.message)) |
| | 95 | message.tries -= 1 |
| | 96 | turbomail.manager.deliver(message) |
| | 97 | return |
| | 98 | else: |
| | 99 | deliverylog.error("%s REFUSED %s %s" % (message.id, e.__class__.__name__, e.message), exc_info=True) |
| | 100 | raise |
| | 101 | |
| | 102 | else: |
| | 103 | deliverylog.info("%s SENT" % message.id) |
| | 104 | |
| | 105 | if self.count < 0: |
| | 106 | raise ProviderExhaustedException |
| | 107 | |
| | 108 | |
| | 109 | class SMTPProviderFactory(ProviderFactory): |
| | 110 | provider = SMTPProvider |
| | 111 | |
| | 112 | def __init__(self): |
| | 113 | log.info("SMTP provider starting up.") |
| | 114 | |
| | 115 | super(SMTPProviderFactory, self).__init__() |