Django

Code

Changeset 5148

Show
Ignore:
Timestamp:
05/03/07 14:26:47 (1 year ago)
Author:
bouldersprinters
Message:

boulder-oracle-sprint: Merged to [5147]

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/branches/boulder-oracle-sprint/django/conf/global_settings.py

    r5079 r5148  
    120120EMAIL_HOST_USER = '' 
    121121EMAIL_HOST_PASSWORD = '' 
     122EMAIL_USE_TLS = False 
    122123 
    123124# List of strings representing installed apps. 
  • django/branches/boulder-oracle-sprint/django/core/mail.py

    r5047 r5148  
    1 # Use this module for e-mailing. 
     1""" 
     2Tools for sending email. 
     3""" 
    24 
    35from django.conf import settings 
     
    57from email.Header import Header 
    68from email.Utils import formatdate 
     9from email import Charset 
     10import os 
    711import smtplib 
    812import socket 
    913import time 
    1014import random 
     15 
     16# Don't BASE64-encode UTF-8 messages so that we avoid unwanted attention from 
     17# some spam filters. 
     18Charset.add_charset('utf-8', Charset.SHORTEST, Charset.QP, 'utf-8') 
    1119 
    1220# Cache the hostname, but do it lazily: socket.getfqdn() can take a couple of 
     
    2230 
    2331DNS_NAME = CachedDnsName() 
     32 
     33# Copied from Python standard library and modified to used the cached hostname 
     34# for performance. 
     35def make_msgid(idstring=None): 
     36    """Returns a string suitable for RFC 2822 compliant Message-ID, e.g: 
     37 
     38    <20020201195627.33539.96671@nightshade.la.mastaler.com> 
     39 
     40    Optional idstring if given is a string used to strengthen the 
     41    uniqueness of the message id. 
     42    """ 
     43    timeval = time.time() 
     44    utcdate = time.strftime('%Y%m%d%H%M%S', time.gmtime(timeval)) 
     45    pid = os.getpid() 
     46    randint = random.randrange(100000) 
     47    if idstring is None: 
     48        idstring = '' 
     49    else: 
     50        idstring = '.' + idstring 
     51    idhost = DNS_NAME 
     52    msgid = '<%s.%s.%s%s@%s>' % (utcdate, pid, randint, idstring, idhost) 
     53    return msgid 
    2454 
    2555class BadHeaderError(ValueError): 
     
    3565        MIMEText.__setitem__(self, name, val) 
    3666 
     67class SMTPConnection(object): 
     68    """ 
     69    A wrapper that manages the SMTP network connection. 
     70    """ 
     71 
     72    def __init__(self, host=None, port=None, username=None, password=None, 
     73            use_tls=None, fail_silently=False): 
     74        self.host = host or settings.EMAIL_HOST 
     75        self.port = port or settings.EMAIL_PORT 
     76        self.username = username or settings.EMAIL_HOST_USER 
     77        self.password = password or settings.EMAIL_HOST_PASSWORD 
     78        self.use_tls = (use_tls is not None) and use_tls or settings.EMAIL_USE_TLS 
     79        self.fail_silently = fail_silently 
     80        self.connection = None 
     81 
     82    def open(self): 
     83        """ 
     84        Ensure we have a connection to the email server. Returns whether or not 
     85        a new connection was required. 
     86        """ 
     87        if self.connection: 
     88            # Nothing to do if the connection is already open. 
     89            return False 
     90        try: 
     91            self.connection = smtplib.SMTP(self.host, self.port) 
     92            if self.use_tls: 
     93                self.connection.ehlo() 
     94                self.connection.starttls() 
     95                self.connection.ehlo() 
     96            if self.username and self.password: 
     97                self.connection.login(self.username, self.password) 
     98            return True 
     99        except: 
     100            if not self.fail_silently: 
     101                raise 
     102 
     103    def close(self): 
     104        """Close the connection to the email server.""" 
     105        try: 
     106            try: 
     107                self.connection.quit() 
     108            except socket.sslerror: 
     109                # This happens when calling quit() on a TLS connection 
     110                # sometimes. 
     111                self.connection.close() 
     112            except: 
     113                if self.fail_silently: 
     114                    return 
     115                raise 
     116        finally: 
     117            self.connection = None 
     118 
     119    def send_messages(self, email_messages): 
     120        """ 
     121        Send one or more EmailMessage objects and return the number of email 
     122        messages sent. 
     123        """ 
     124        if not email_messages: 
     125            return 
     126        new_conn_created = self.open() 
     127        if not self.connection: 
     128            # We failed silently on open(). Trying to send would be pointless. 
     129            return 
     130        num_sent = 0 
     131        for message in email_messages: 
     132            sent = self._send(message) 
     133            if sent: 
     134                num_sent += 1 
     135        if new_conn_created: 
     136            self.close() 
     137        return num_sent 
     138 
     139    def _send(self, email_message): 
     140        """A helper method that does the actual sending.""" 
     141        if not email_message.to: 
     142            return False 
     143        try: 
     144            self.connection.sendmail(email_message.from_email, 
     145                    email_message.recipients(), 
     146                    email_message.message().as_string()) 
     147        except: 
     148            if not self.fail_silently: 
     149                raise 
     150            return False 
     151        return True 
     152 
     153class EmailMessage(object): 
     154    """ 
     155    A container for email information. 
     156    """ 
     157    def __init__(self, subject='', body='', from_email=None, to=None, bcc=None, connection=None): 
     158        self.to = to or [] 
     159        self.bcc = bcc or [] 
     160        self.from_email = from_email or settings.DEFAULT_FROM_EMAIL 
     161        self.subject = subject 
     162        self.body = body 
     163        self.connection = connection 
     164 
     165    def get_connection(self, fail_silently=False): 
     166        if not self.connection: 
     167            self.connection = SMTPConnection(fail_silently=fail_silently) 
     168        return self.connection 
     169 
     170    def message(self): 
     171        msg = SafeMIMEText(self.body, 'plain', settings.DEFAULT_CHARSET) 
     172        msg['Subject'] = self.subject 
     173        msg['From'] = self.from_email 
     174        msg['To'] = ', '.join(self.to) 
     175        msg['Date'] = formatdate() 
     176        msg['Message-ID'] = make_msgid() 
     177        if self.bcc: 
     178            msg['Bcc'] = ', '.join(self.bcc) 
     179        return msg 
     180 
     181    def recipients(self): 
     182        """ 
     183        Returns a list of all recipients of the email (includes direct 
     184        addressees as well as Bcc entries). 
     185        """ 
     186        return self.to + self.bcc 
     187 
     188    def send(self, fail_silently=False): 
     189        """Send the email message.""" 
     190        return self.get_connection(fail_silently).send_messages([self]) 
     191 
    37192def send_mail(subject, message, from_email, recipient_list, fail_silently=False, auth_user=None, auth_password=None): 
    38193    """ 
     
    42197    If auth_user is None, the EMAIL_HOST_USER setting is used. 
    43198    If auth_password is None, the EMAIL_HOST_PASSWORD setting is used. 
    44     """ 
    45     return send_mass_mail([[subject, message, from_email, recipient_list]], fail_silently, auth_user, auth_password) 
     199 
     200    NOTE: This method is deprecated. It exists for backwards compatibility. 
     201    New code should use the EmailMessage class directly. 
     202    """ 
     203    connection = SMTPConnection(username=auth_user, password=auth_password, 
     204                                 fail_silently=fail_silently) 
     205    return EmailMessage(subject, message, from_email, recipient_list, connection=connection).send() 
    46206 
    47207def send_mass_mail(datatuple, fail_silently=False, auth_user=None, auth_password=None): 
     
    54214    If auth_user is None, the EMAIL_HOST_USER setting is used. 
    55215    If auth_password is None, the EMAIL_HOST_PASSWORD setting is used. 
    56     """ 
    57     if auth_user is None: 
    58         auth_user = settings.EMAIL_HOST_USER 
    59     if auth_password is None: 
    60         auth_password = settings.EMAIL_HOST_PASSWORD 
    61     try: 
    62         server = smtplib.SMTP(settings.EMAIL_HOST, settings.EMAIL_PORT) 
    63         if auth_user and auth_password: 
    64             server.login(auth_user, auth_password) 
    65     except: 
    66         if fail_silently: 
    67             return 
    68         raise 
    69     num_sent = 0 
    70     for subject, message, from_email, recipient_list in datatuple: 
    71         if not recipient_list: 
    72             continue 
    73         from_email = from_email or settings.DEFAULT_FROM_EMAIL 
    74         msg = SafeMIMEText(message, 'plain', settings.DEFAULT_CHARSET) 
    75         msg['Subject'] = subject 
    76         msg['From'] = from_email 
    77         msg['To'] = ', '.join(recipient_list) 
    78         msg['Date'] = formatdate() 
    79         try: 
    80             random_bits = str(random.getrandbits(64)) 
    81         except AttributeError: # Python 2.3 doesn't have random.getrandbits(). 
    82             random_bits = ''.join([random.choice('1234567890') for i in range(19)]) 
    83         msg['Message-ID'] = "<%d.%s@%s>" % (time.time(), random_bits, DNS_NAME) 
    84         try: 
    85             server.sendmail(from_email, recipient_list, msg.as_string()) 
    86             num_sent += 1 
    87         except: 
    88             if not fail_silently: 
    89                 raise 
    90     try: 
    91         server.quit() 
    92     except: 
    93         if fail_silently: 
    94             return 
    95         raise 
    96     return num_sent 
     216 
     217    NOTE: This method is deprecated. It exists for backwards compatibility. 
     218    New code should use the EmailMessage class directly. 
     219    """ 
     220    connection = SMTPConnection(username=auth_user, password=auth_password, 
     221                                 fail_silently=fail_silently) 
     222    messages = [EmailMessage(subject, message, sender, recipient) for subject, message, sender, recipient in datatuple] 
     223    return connection.send_messages(messages) 
    97224 
    98225def mail_admins(subject, message, fail_silently=False): 
    99226    "Sends a message to the admins, as defined by the ADMINS setting." 
    100     send_mail(settings.EMAIL_SUBJECT_PREFIX + subject, message, settings.SERVER_EMAIL, [a[1] for a in settings.ADMINS], fail_silently) 
     227    EmailMessage(settings.EMAIL_SUBJECT_PREFIX + subject, message, 
     228            settings.SERVER_EMAIL, [a[1] for a in 
     229                settings.ADMINS]).send(fail_silently=fail_silently) 
    101230 
    102231def mail_managers(subject, message, fail_silently=False): 
    103232    "Sends a message to the managers, as defined by the MANAGERS setting." 
    104     send_mail(settings.EMAIL_SUBJECT_PREFIX + subject, message, settings.SERVER_EMAIL, [a[1] for a in settings.MANAGERS], fail_silently) 
     233    EmailMessage(settings.EMAIL_SUBJECT_PREFIX + subject, message, 
     234            settings.SERVER_EMAIL, [a[1] for a in 
     235                settings.MANAGERS]).send(fail_silently=fail_silently) 
     236 
  • django/branches/boulder-oracle-sprint/docs/documentation.txt

    r4990 r5148  
    9595The text documentation is written in ReST (ReStructured Text) format. That 
    9696means it's easy to read but is also formatted in a way that makes it easy to 
    97 convert into other formats, such as HTML. If you're interested, the script that 
    98 converts the ReST text docs into djangoproject.com's HTML lives at 
    99 `djangoproject.com/django_website/apps/docs/parts/build_documentation.py`_ in 
    100 the Django Subversion repository. 
     97convert into other formats, such as HTML. If you have the `reStructuredText`_ 
     98library installed, you can use ``rst2html`` to generate your own HTML files. 
    10199 
    102 .. _djangoproject.com/django_website/apps/docs/parts/build_documentation.py: http://code.djangoproject.com/browser/djangoproject.com/django_website/apps/docs/parts/build_documentation.py 
     100.. _reStructuredText: http://docutils.sourceforge.net/rst.html 
    103101 
    104102Differences between versions 
  • django/branches/boulder-oracle-sprint/docs/email.txt

    r5128 r5148  
    2323Mail will be sent using the SMTP host and port specified in the `EMAIL_HOST`_ 
    2424and `EMAIL_PORT`_ settings. The `EMAIL_HOST_USER`_ and `EMAIL_HOST_PASSWORD`_ 
    25 settings, if set, will be used to authenticate to the SMTP server. 
     25settings, if set, will be used to authenticate to the SMTP server and the 
     26`EMAIL_USE_TLS`_ settings will control whether a secure connection is used. 
    2627 
    2728.. note:: 
     
    3536.. _EMAIL_HOST_USER: ../settings/#email-host-user 
    3637.. _EMAIL_HOST_PASSWORD: ../settings/#email-host-password 
     38.. _EMAIL_USE_TLS: ../settings/#email-use-tls 
    3739 
    3840 
     
    184186 
    185187.. _Header injection: http://securephp.damonkohler.com/index.php/Email_Injection 
     188 
     189The EmailMessage and SMTPConnection classes 
     190=========================================== 
     191 
     192**New in Django development version** 
     193 
     194Django's ``send_mail()`` and ``send_mass_mail()`` functions are actually thin 
     195wrappers that make use of the ``EmailMessage`` and ``SMTPConnection`` classes 
     196in ``django.mail``.  If you ever need to customize the way Django sends email, 
     197you can subclass these two classes to suit your needs. 
     198 
     199.. note:: 
     200    Not all features of the ``EmailMessage`` class are available through the 
     201    ``send_mail()`` and related wrapper functions. If you wish to use advanced 
     202    features such as including BCC recipients or multi-part email, you will 
     203    need to create ``EmailMessage`` instances directly. 
     204 
     205In general, ``EmailMessage`` is responsible for creating the email message 
     206itself. ``SMTPConnection`` is responsible for the network connection side of 
     207the operation. This means you can reuse the same connection (an 
     208``SMTPConnection`` instance) for multiple messages. 
     209 
     210The ``EmailMessage`` class is initialised as follows:: 
     211 
     212    email = EmailMessage(subject, body, from_email, to, bcc, connection) 
     213 
     214All of these parameters are optional. If ``from_email`` is omitted, the value 
     215from ``settings.DEFAULT_FROM_EMAIL`` is used. Both the ``to`` and ``bcc`` 
     216parameters are lists of addresses. 
     217 
     218The class has the following methods that you can use: 
     219 
     220 * ``send()`` sends the message, using either the connection that is specified 
     221   in the ``connection`` attribute, or creating a new connection if none already 
     222   exists. 
     223 * ``message()`` constructs a ``django.core.mail.SafeMIMEText`` object (a 
     224   sub-class of Python's ``email.MIMEText.MIMEText`` class) holding the 
     225   message to be sent. If you ever need to extend the `EmailMessage` class, 
     226   you will probably want to override this method to put the content you wish 
     227   into the MIME object. 
     228 * ``recipients()`` returns a lists of all the recipients of the message, 
     229   whether they are recorded in the ``to`` or ``bcc`` attributes. This is 
     230   another method you need to possibly override when sub-classing, since the 
     231   SMTP server needs to be told the full list of recipients when the message 
     232   is sent. If you add another way to specify recipients in your class, they 
     233   need to be returned from this method as well. 
     234 
     235The ``SMTPConnection`` class is initialized with the host, port, username and 
     236password for the SMTP server. If you don't specify one or more of those 
     237options, they are read from your settings file. 
     238 
     239If you are sending lots of messages at once, the ``send_messages()`` method of 
     240the ``SMTPConnection`` class will be useful. It takes a list of ``EmailMessage`` 
     241instances (or sub-classes) and sends them over a single connection. For 
     242example, if you have a function called ``get_notification_email()`` that returns a 
     243list of ``EmailMessage`` objects representing some periodic email you wish to 
     244send out, you could send this with:: 
     245 
     246    connection = SMTPConnection()   # Use default settings for connection 
     247    messages = get_notification_email() 
     248    connection.send_messages(messages) 
     249 
  • django/branches/boulder-oracle-sprint/docs/sessions.txt

    r4842 r5148  
    108108 
    109109    def login(request): 
    110         m = members.get_object(username__exact=request.POST['username']) 
     110        m = Member.objects.get(username=request.POST['username']) 
    111111        if m.password == request.POST['password']: 
    112112            request.session['member_id'] = m.id 
  • django/branches/boulder-oracle-sprint/docs/settings.txt

    r5135 r5148  
    428428or ``django.core.mail.mail_managers``. You'll probably want to include the 
    429429trailing space. 
     430 
     431EMAIL_USE_TLS 
     432------------- 
     433 
     434**New in Django development version** 
     435 
     436Default: ``False`` 
     437 
     438Whether to use a TLS (secure) connection when talking to the SMTP server. 
    430439 
    431440FIXTURE_DIRS 
  • django/branches/boulder-oracle-sprint/docs/syndication_feeds.txt

    r5079 r5148  
    647647            """ 
    648648            Takes an item, as returned by items(), and returns the item's 
    649             enclosure mime type. 
     649            enclosure MIME type. 
    650650            """ 
    651651 
    652652        def item_enclosure_mime_type(self): 
    653653            """ 
    654             Returns the enclosure length, in bytes, for every item in the feed. 
    655             """ 
    656  
    657         item_enclosure_mime_type = "audio/mpeg" # Hard-coded enclosure mime-type. 
     654            Returns the enclosure MIME type for every item in the feed. 
     655            """ 
     656 
     657        item_enclosure_mime_type = "audio/mpeg" # Hard-coded enclosure MIME type. 
    658658 
    659659        # ITEM PUBDATE -- It's optional to use one of these three. This is a 
  • django/branches/boulder-oracle-sprint/docs/templates_python.txt

    r5047 r5148  
    346346      collects the user's messages and deletes them from the database. 
    347347 
    348       Note that messages are set with ``user.add_message()``. See the 
     348      Note that messages are set with ``user.message_set.create``. See the 
    349349      `message docs`_ for more. 
    350350