Ticket #17193: send_templated_mail.diff

File send_templated_mail.diff, 5.2 KB (added by tomchristie, 4 years ago)
  • django/shortcuts/__init__.py

    diff --git a/django/shortcuts/__init__.py b/django/shortcuts/__init__.py
    index 9f97cae..db31ee4 100644
    a b of MVC. In other words, these functions/classes introduce controlled coupling 
    44for convenience's sake.
    55"""
    66
    7 from django.template import loader, RequestContext
     7from django.template import loader, Context, RequestContext
     8from django.template.loader_tags import BlockNode, ExtendsNode
    89from django.http import HttpResponse, Http404
    910from django.http import HttpResponseRedirect, HttpResponsePermanentRedirect
    1011from django.db.models.manager import Manager
    1112from django.db.models.query import QuerySet
    12 from django.core import urlresolvers
     13from django.core import urlresolvers, mail
     14from django.utils.html import strip_tags
    1315
    1416def render_to_response(*args, **kwargs):
    1517    """
    def get_list_or_404(klass, *args, **kwargs): 
    128130        raise Http404('No %s matches the given query.' % queryset.model._meta.object_name)
    129131    return obj_list
    130132
     133
     134def _get_node(template, name):
     135    """
     136    Get a named node from a template.
     137    Returns `None` if a node with the given name does not exist.
     138    """
     139    for node in template:
     140        if isinstance(node, BlockNode) and node.name == name:
     141            return node
     142        elif isinstance(node, ExtendsNode):
     143            return _get_node(node.nodelist, name)
     144    return None
     145
     146
     147def _render_node(template, node_name, context):
     148    """
     149    Shortcut to render a named node from a template, using the given context.
     150    Returns `None` if a node with the given name does not exist.
     151
     152    Note that leading and trailing whitespace is stripped from the output.
     153    """
     154    node = _get_node(template, node_name)
     155    if node is None:
     156        return None
     157    return node.render(context).strip()
     158
     159
     160def _create_message(subject, plain, html,
     161                    from_email, recipient_list, connection):
     162    """
     163    Return an EmailMessage instance, containing either a plaintext
     164    representation, or a multipart html/plaintext representation.
     165    """
     166    if html:
     167        message = mail.EmailMultiAlternatives(
     168            subject or '',
     169            plain or '',
     170            from_email,
     171            recipient_list,
     172            connection=connection,
     173        )
     174        message.attach_alternative(html, 'text/html')
     175
     176    else:
     177        message = mail.EmailMessage(
     178            subject or '',
     179            plain or '',
     180            from_email,
     181            recipient_list,
     182            connection=connection,
     183        )
     184
     185    return message
     186
     187
     188def _render_mail(template_name, from_email, recipient_list,
     189                 dictionary=None, context_instance=None,
     190                 fail_silently=False,
     191                 auth_user=None, auth_password=None,
     192                 connection=None):
     193    """
     194    Returns an EmailMessage instance, rendering the subject and body of the
     195    email from a template.
     196
     197    The template should contain a block named 'subject',
     198    and either/both of a 'plain' and/or 'html' block.
     199
     200    If only the 'plain' block exists, a plaintext email will be sent.
     201
     202    If only the 'html' block exists, the plaintext component will be
     203      automatically generated from the html, and a multipart email will be sent.
     204
     205    If both the 'plain' and 'html' blocks exist, a multipart email will be sent.
     206
     207    Required arguments:
     208    `template_name` - The template that should be used to render the email.
     209    `from_email` - The sender's email address.
     210    `recipient_list` - A list of reciepient's email addresses.
     211
     212    Optional arguments:
     213    `dictionary` - The context dictionary used to render the template.
     214                   By default, this is an empty dictionary.
     215    `context_instance` - The Context instance used to render the template.
     216                         By default, the template will be rendered with a
     217                         Context instance (filled with values from dictionary).
     218    `fail_silently` - As in Django's send_mail.
     219    `auth_user`     - As in Django's send_mail.
     220    `auth_password` - As in Django's send_mail.
     221    `connection`    - As in Django's send_mail.
     222    """
     223    if dictionary is None:
     224        dictionary = {}
     225    if context_instance is None:
     226        context_instance = Context()
     227    if connection is None:
     228        connection = mail.get_connection(username=auth_user,
     229                                         password=auth_password,
     230                                         fail_silently=fail_silently)
     231
     232    context_instance.update(dictionary)
     233    template = loader.get_template(template_name)
     234
     235    subject = _render_node(template, 'subject', context_instance)
     236    plain = _render_node(template, 'plain', context_instance)
     237    html = _render_node(template, 'html', context_instance)
     238
     239    # Always strip newlines from subject
     240    if subject is not None:
     241        subject = ' '.join(subject.splitlines())
     242
     243    # Auto-generate plaintext if no 'plain' block exists
     244    if plain is None and not html is None:
     245        plain = strip_tags(html)
     246
     247    message = _create_message(subject, plain, html,
     248                              from_email, recipient_list, connection)
     249    return message
     250
     251
     252def send_templated_mail(*args, **kwargs):
     253    return _render_mail(*args, **kwargs).send()
Back to Top