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