Skip to content

Commit

Permalink
Inital working version of the class
Browse files Browse the repository at this point in the history
  • Loading branch information
BradWhittington committed Mar 16, 2011
1 parent 8f38dfa commit 7036861
Show file tree
Hide file tree
Showing 11 changed files with 258 additions and 0 deletions.
1 change: 1 addition & 0 deletions AUTHORS
@@ -0,0 +1 @@
Bradley Whittington <radbrad182@gmail.com>
23 changes: 23 additions & 0 deletions LICENSE
@@ -0,0 +1,23 @@
Copyright (c) 2011 Bradley Whittington

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

3 changes: 3 additions & 0 deletions MANIFEST.in
@@ -0,0 +1,3 @@
include AUTHORS
include LICENSE
include README.rst
62 changes: 62 additions & 0 deletions README.rst
@@ -0,0 +1,62 @@
==========
Django-Mailgun
==========
:Info: A Django oriented templated email sending class
:Author: Bradley Whittington (http://github.com/bradwhittington, http://twitter.com/darb)

Overview
=================
django-templated-email is oriented towards sending templated emails
intended for use with transactional mailers (ala mailchimp, silverpop,
etc.), but currently comes out of the box with a backend class which
uses django's templating system, and django's core.mail functions.

Getting going - installation
=============

Installing::

pip install -e git://github.com/bradwhittington/django-templated-email.git#egg=templated_email

You can add the following to your settings.py (but it works out the box)::

TEMPLATED_EMAIL_BACKEND = 'templated_email.backends.vanilla_django.TemplateBackend'

# For the django back-end specifically
TEMPLATED_EMAIL_DJANGO_SUBJECTS = {
'welcome':'Welcome to my website',
}

Getting going - sending your template emails
=============

Example usage using vanilla_django TemplateBackend backend

Python to send mail::
from templated_email import send_templated_email
send_templated_email(
template_name='welcome',
from_email='from@example.com',
recipient_list=['to@example.com'],
context={
'username':request.user.username,
'full_name':request.user.get_full_name(),
'signup_date':request.user.date_joined
}
)

Which looks in django template directories/loaders for
*templated_email/welcome.txt* ::
Hey {{full_name}},

You just signed up for my website, using:
username: {{username}}
join date: {{signup_date}}

Thanks, you rock!

It will also use *templated_email/welcome.html* for the html part
of the email allowing you to make it so much pretty. It is plausible
that one day there will be support for attachments and inline mime / images

.. _Django: http://djangoproject.com
36 changes: 36 additions & 0 deletions setup.py
@@ -0,0 +1,36 @@
from setuptools import setup, find_packages
import os
import platform

DESCRIPTION = "A Django oriented templated / transaction email abstraction"

LONG_DESCRIPTION = None
try:
LONG_DESCRIPTION = open('README.rst').read()
except:
pass

CLASSIFIERS = [
'Development Status :: 4 - Beta',
'Intended Audience :: Developers',
'License :: OSI Approved :: MIT License',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Topic :: Software Development :: Libraries :: Python Modules',
'Framework :: Django',
]

setup(
name='django-templated-email',
version='0.1',
packages=['templated_email'],
author='Bradley Whittington',
author_email='radbrad182@gmail.com',
url='http://github.com/bradwhittington/django-templated-email/',
license='MIT',
description=DESCRIPTION,
long_description=LONG_DESCRIPTION,
platforms=['any'],
classifiers=CLASSIFIERS,
)

37 changes: 37 additions & 0 deletions templated_email/__init__.py
@@ -0,0 +1,37 @@
from django.conf import settings
from django.utils.importlib import import_module
from django.core.exceptions import ImproperlyConfigured

def get_connection(backend=None, template_prefix=None, fail_silently=False, **kwargs):
"""Load a templated e-mail backend and return an instance of it.
If backend is None (default) settings.TEMPLATED_EMAIL_BACKEND is used.
Both fail_silently and other keyword arguments are used in the
constructor of the backend.
"""
# This method is mostly a copy of the backend loader present in django.core.mail.get_connection
template_prefix = template_prefix or getattr(settings,'TEMPLATED_EMAIL_PREFIX','templated_email/')
path = backend or getattr(settings,'TEMPLATED_EMAIL_BACKEND','templated_email.backends.vanilla_django.TemplateBackend')
try:
mod_name, klass_name = path.rsplit('.', 1)
mod = import_module(mod_name)
except ImportError, e:
raise ImproperlyConfigured(('Error importing templated email backend module %s: "%s"'
% (mod_name, e)))
try:
klass = getattr(mod, klass_name)
except AttributeError:
raise ImproperlyConfigured(('Module "%s" does not define a '
'"%s" class' % (mod_name, klass_name)))
return klass(fail_silently=fail_silently, template_prefix=template_prefix, **kwargs)


def send_templated_mail(template_name, from_email, recipient_list, context, fail_silently=False, connection=None):
"""Easy wrapper for sending a templated email to a recipient list.
Final behaviour of sending depends on the currently selected engine.
See BackendClass.send.__doc__
"""
connection = connection or get_connection()
return connection.send(template_name, from_email, recipient_list, context, fail_silently)
Binary file added templated_email/__init__.pyc
Binary file not shown.
File renamed without changes.
Binary file added templated_email/backends/__init__.pyc
Binary file not shown.
96 changes: 96 additions & 0 deletions templated_email/backends/vanilla_django.py
@@ -0,0 +1,96 @@
from django.conf import settings
from django.core.mail import send_mail, EmailMessage, EmailMultiAlternatives
from django.template import Context, TemplateDoesNotExist
from django.template.loader import get_template
from django.utils.translation import ugettext as _

class TemplateBackend:
"""
Backend which uses Django's templates, and django's send_mail function.
Heavily inspired by http://stackoverflow.com/questions/2809547/creating-email-templates-with-django
Templates are loaded from (by default):
text/plain part:
templated_email/<template_name>.txt
text/html part:
templated_email/<template_name>.html
Subjects for email templates can be configured in one of two ways:
* If you are using internationalisation, you can simply create entries for
"<template_name> email subject" as a msgid in your PO file
* Using a dictionary in settings.py, TEMPLATED_EMAIL_DJANGO_SUBJECTS,
for e.g.:
TEMPLATED_EMAIL_DJANGO_SUBJECTS = {
'welcome':'Welcome to my website',
}
Additionally subjects are templatable using the context, i.e. A subject
that resolves to 'Welcome to my website, %(username)s', requires that
the context passed in to the send() method contains 'username' as one
of it's keys
"""

def __init__(self, fail_silently=False, template_prefix='templated_email/', **kwargs):
self.template_prefix = template_prefix

def send(self, template_name, from_email, recipient_list, context, fail_silently=False):
subject = getattr(
settings,'TEMPLATED_EMAIL_DJANGO_SUBJECTS',{}
).get(
template_name,
_('%s email subject' % template_name)
) % context

prefixed_template_name=''.join((self.template_prefix,template_name))

try:
html_part = get_template('%s.html' % prefixed_template_name)
except TemplateDoesNotExist:
html_part = None

try:
plain_part = get_template('%s.txt' % prefixed_template_name)
except TemplateDoesNotExist:
if not html_part:
raise TemplateDoesNotExist('%s.txt' % prefixed_template_name)
else:
plain_part = None

#TODO: Should we WARN if we only found an html part?

render_context = Context(context)

#TODO: Handle bundling in assets/attachments

if plain_part and not html_part:
e=EmailMessage(
subject,
plain_part.render(render_context),
from_email,
recipient_list,
)
e.send(fail_silently)

if html_part and not plain_part:
e=EmailMessage(
subject,
html_part.render(render_context),
from_email,
recipient_list,
)
e.content_subtype = 'html'
e.send(fail_silently)

if plain_part and html_part:
e=EmailMultiAlternatives(
subject,
plain_part.render(render_context),
from_email,
recipient_list,
)
e.attach_alternative(html_part.render(render_context),'text/html')
e.send(fail_silently)

Binary file added templated_email/backends/vanilla_django.pyc
Binary file not shown.

0 comments on commit 7036861

Please sign in to comment.