Commit aba53893 authored by Russell Keith-Magee's avatar Russell Keith-Magee
Browse files

Fixed #10355 -- Added an API for pluggable e-mail backends.

Thanks to Andi Albrecht for his work on this patch, and to everyone else that contributed during design and development.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@11709 bcc190cf-cafb-0310-a4f2-bffc1f526a37
parent 8287c27b
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ answer newbie questions, and generally made Django that much better:

    ajs <adi@sieker.info>
    alang@bright-green.com
    Andi Albrecht <albrecht.andi@gmail.com>
    Marty Alchin <gulopine@gamemusic.org>
    Ahmad Alhashemi <trans@ahmadh.com>
    Daniel Alves Barbosa de Oliveira Vaz <danielvaz@gmail.com>
+6 −0
Original line number Diff line number Diff line
@@ -131,6 +131,12 @@ DATABASE_HOST = '' # Set to empty string for localhost. Not used wit
DATABASE_PORT = ''             # Set to empty string for default. Not used with sqlite3.
DATABASE_OPTIONS = {}          # Set to empty dictionary for default.

# The email backend to use. For possible shortcuts see django.core.mail.
# The default is to use the SMTP backend.
# Third-party backends can be specified by providing a Python path
# to a module that defines an EmailBackend class.
EMAIL_BACKEND = 'django.core.mail.backends.smtp'

# Host for sending e-mail.
EMAIL_HOST = 'localhost'

+110 −0
Original line number Diff line number Diff line
"""
Tools for sending email.
"""

from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.utils.importlib import import_module

# Imported for backwards compatibility, and for the sake
# of a cleaner namespace. These symbols used to be in
# django/core/mail.py before the introduction of email
# backends and the subsequent reorganization (See #10355)
from django.core.mail.utils import CachedDnsName, DNS_NAME
from django.core.mail.message import \
    EmailMessage, EmailMultiAlternatives, \
    SafeMIMEText, SafeMIMEMultipart, \
    DEFAULT_ATTACHMENT_MIME_TYPE, make_msgid, \
    BadHeaderError, forbid_multi_line_headers
from django.core.mail.backends.smtp import EmailBackend as _SMTPConnection

def get_connection(backend=None, fail_silently=False, **kwds):
    """Load an e-mail backend and return an instance of it.

    If backend is None (default) settings.EMAIL_BACKEND is used.

    Both fail_silently and other keyword arguments are used in the
    constructor of the backend.
    """
    path = backend or settings.EMAIL_BACKEND
    try:
        mod = import_module(path)
    except ImportError, e:
        raise ImproperlyConfigured(('Error importing email backend %s: "%s"'
                                    % (path, e)))
    try:
        cls = getattr(mod, 'EmailBackend')
    except AttributeError:
        raise ImproperlyConfigured(('Module "%s" does not define a '
                                    '"EmailBackend" class' % path))
    return cls(fail_silently=fail_silently, **kwds)


def send_mail(subject, message, from_email, recipient_list,
              fail_silently=False, auth_user=None, auth_password=None,
              connection=None):
    """
    Easy wrapper for sending a single message to a recipient list. All members
    of the recipient list will see the other recipients in the 'To' field.

    If auth_user is None, the EMAIL_HOST_USER setting is used.
    If auth_password is None, the EMAIL_HOST_PASSWORD setting is used.

    Note: The API for this method is frozen. New code wanting to extend the
    functionality should use the EmailMessage class directly.
    """
    connection = connection or get_connection(username=auth_user,
                                    password=auth_password,
                                    fail_silently=fail_silently)
    return EmailMessage(subject, message, from_email, recipient_list,
                        connection=connection).send()


def send_mass_mail(datatuple, fail_silently=False, auth_user=None,
                   auth_password=None, connection=None):
    """
    Given a datatuple of (subject, message, from_email, recipient_list), sends
    each message to each recipient list. Returns the number of e-mails sent.

    If from_email is None, the DEFAULT_FROM_EMAIL setting is used.
    If auth_user and auth_password are set, they're used to log in.
    If auth_user is None, the EMAIL_HOST_USER setting is used.
    If auth_password is None, the EMAIL_HOST_PASSWORD setting is used.

    Note: The API for this method is frozen. New code wanting to extend the
    functionality should use the EmailMessage class directly.
    """
    connection = connection or get_connection(username=auth_user,
                                    password=auth_password,
                                    fail_silently=fail_silently)
    messages = [EmailMessage(subject, message, sender, recipient)
                for subject, message, sender, recipient in datatuple]
    return connection.send_messages(messages)


def mail_admins(subject, message, fail_silently=False, connection=None):
    """Sends a message to the admins, as defined by the ADMINS setting."""
    if not settings.ADMINS:
        return
    EmailMessage(settings.EMAIL_SUBJECT_PREFIX + subject, message,
                 settings.SERVER_EMAIL, [a[1] for a in settings.ADMINS],
                 connection=connection).send(fail_silently=fail_silently)


def mail_managers(subject, message, fail_silently=False, connection=None):
    """Sends a message to the managers, as defined by the MANAGERS setting."""
    if not settings.MANAGERS:
        return
    EmailMessage(settings.EMAIL_SUBJECT_PREFIX + subject, message,
                 settings.SERVER_EMAIL, [a[1] for a in settings.MANAGERS],
                 connection=connection).send(fail_silently=fail_silently)


class SMTPConnection(_SMTPConnection):
    def __init__(self, *args, **kwds):
        import warnings
        warnings.warn(
            'mail.SMTPConnection is deprecated; use mail.get_connection() instead.',
            DeprecationWarning
        )
        super(SMTPConnection, self).__init__(*args, **kwds)
+1 −0
Original line number Diff line number Diff line
# Mail backends shipped with Django.
+39 −0
Original line number Diff line number Diff line
"""Base email backend class."""

class BaseEmailBackend(object):
    """
    Base class for email backend implementations.

    Subclasses must at least overwrite send_messages().
    """
    def __init__(self, fail_silently=False, **kwargs):
        self.fail_silently = fail_silently

    def open(self):
        """Open a network connection.

        This method can be overwritten by backend implementations to
        open a network connection.

        It's up to the backend implementation to track the status of
        a network connection if it's needed by the backend.

        This method can be called by applications to force a single
        network connection to be used when sending mails. See the
        send_messages() method of the SMTP backend for a reference
        implementation.

        The default implementation does nothing.
        """
        pass

    def close(self):
        """Close a network connection."""
        pass

    def send_messages(self, email_messages):
        """
        Sends one or more EmailMessage objects and returns the number of email
        messages sent.
        """
        raise NotImplementedError
Loading