web/lib/django/core/mail/backends/smtp.py
author ymh <ymh.work@gmail.com>
Tue, 25 May 2010 02:43:45 +0200
changeset 29 cc9b7e14412b
permissions -rw-r--r--
update django and lucene
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
29
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
     1
"""SMTP email backend class."""
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
     2
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
     3
import smtplib
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
     4
import socket
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
     5
import threading
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
     6
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
     7
from django.conf import settings
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
     8
from django.core.mail.backends.base import BaseEmailBackend
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
     9
from django.core.mail.utils import DNS_NAME
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    10
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    11
class EmailBackend(BaseEmailBackend):
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    12
    """
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    13
    A wrapper that manages the SMTP network connection.
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    14
    """
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    15
    def __init__(self, host=None, port=None, username=None, password=None,
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    16
                 use_tls=None, fail_silently=False, **kwargs):
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    17
        super(EmailBackend, self).__init__(fail_silently=fail_silently)
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    18
        self.host = host or settings.EMAIL_HOST
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    19
        self.port = port or settings.EMAIL_PORT
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    20
        self.username = username or settings.EMAIL_HOST_USER
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    21
        self.password = password or settings.EMAIL_HOST_PASSWORD
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    22
        if use_tls is None:
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    23
            self.use_tls = settings.EMAIL_USE_TLS
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    24
        else:
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    25
            self.use_tls = use_tls
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    26
        self.connection = None
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    27
        self._lock = threading.RLock()
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    28
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    29
    def open(self):
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    30
        """
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    31
        Ensures we have a connection to the email server. Returns whether or
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    32
        not a new connection was required (True or False).
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    33
        """
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    34
        if self.connection:
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    35
            # Nothing to do if the connection is already open.
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    36
            return False
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    37
        try:
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    38
            # If local_hostname is not specified, socket.getfqdn() gets used.
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    39
            # For performance, we use the cached FQDN for local_hostname.
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    40
            self.connection = smtplib.SMTP(self.host, self.port,
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    41
                                           local_hostname=DNS_NAME.get_fqdn())
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    42
            if self.use_tls:
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    43
                self.connection.ehlo()
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    44
                self.connection.starttls()
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    45
                self.connection.ehlo()
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    46
            if self.username and self.password:
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    47
                self.connection.login(self.username, self.password)
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    48
            return True
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    49
        except:
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    50
            if not self.fail_silently:
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    51
                raise
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    52
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    53
    def close(self):
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    54
        """Closes the connection to the email server."""
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    55
        try:
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    56
            try:
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    57
                self.connection.quit()
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    58
            except socket.sslerror:
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    59
                # This happens when calling quit() on a TLS connection
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    60
                # sometimes.
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    61
                self.connection.close()
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    62
            except:
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    63
                if self.fail_silently:
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    64
                    return
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    65
                raise
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    66
        finally:
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    67
            self.connection = None
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    68
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    69
    def send_messages(self, email_messages):
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    70
        """
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    71
        Sends one or more EmailMessage objects and returns the number of email
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    72
        messages sent.
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    73
        """
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    74
        if not email_messages:
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    75
            return
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    76
        self._lock.acquire()
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    77
        try:
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    78
            new_conn_created = self.open()
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    79
            if not self.connection:
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    80
                # We failed silently on open().
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    81
                # Trying to send would be pointless.
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    82
                return
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    83
            num_sent = 0
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    84
            for message in email_messages:
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    85
                sent = self._send(message)
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    86
                if sent:
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    87
                    num_sent += 1
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    88
            if new_conn_created:
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    89
                self.close()
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    90
        finally:
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    91
            self._lock.release()
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    92
        return num_sent
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    93
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    94
    def _send(self, email_message):
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    95
        """A helper method that does the actual sending."""
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    96
        if not email_message.recipients():
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    97
            return False
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    98
        try:
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
    99
            self.connection.sendmail(email_message.from_email,
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
   100
                    email_message.recipients(),
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
   101
                    email_message.message().as_string())
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
   102
        except:
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
   103
            if not self.fail_silently:
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
   104
                raise
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
   105
            return False
cc9b7e14412b update django and lucene
ymh <ymh.work@gmail.com>
parents:
diff changeset
   106
        return True