Merge pull request #30 from brack3t/docs

Break up readme into docs; add to readthedocs.org
This commit is contained in:
Mike Edmunds
2013-03-04 21:28:10 -08:00
16 changed files with 1262 additions and 302 deletions

1
.gitignore vendored
View File

@@ -3,5 +3,6 @@
*.pyc
*.egg-info
dist/
docs/_build/
TODO.txt
local.py

View File

@@ -1,327 +1,121 @@
Djrill, for Mandrill
====================
.. This README is reused in multiple places:
* Github: project page, exactly as it appears here
* Docs: shared-intro section gets included in docs/index.rst
quickstart section gets included in docs/quickstart.rst
* PyPI: project page (via setup.py long_description),
with several edits to freeze it to the specific PyPI release
(see long_description_from_readme in setup.py)
You can use docutils 1.0 markup, but *not* any Sphinx additions.
.. image:: https://secure.travis-ci.org/brack3t/Djrill.png?branch=master
:target: https://travis-ci.org/brack3t/Djrill
.. These substitution definitions apply in the readme (github) only;
they're altered by setup.py for the long_description,
and defined differently for the docs includes
Djrill is an email backend for Django users who want to take advantage of the
Mandrill_ transactional email service from MailChimp_.
.. |release| replace:: (source)
In general, Djrill "just works" with Django's built-in `django.core.mail`_
package. You can also take advantage of Mandrill-specific features like tags,
metadata, and tracking.
.. |version| replace:: |release|
An optional Django admin interface is included. The admin interface allows you to:
.. |buildstatus| image:: https://secure.travis-ci.org/brack3t/Djrill.png?branch=master
:target: https://travis-ci.org/brack3t/Djrill
* Check the status of your Mandrill API connection.
* See stats on email senders, tags and urls.
.. default-role:: literal
Djrill is made available under the BSD license.
Installation
.. _shared-intro:
.. This shared-intro section is also included in docs/index.rst
Djrill: Mandrill Transactional Email for Django
===============================================
Release |release|
Djrill integrates the `Mandrill <http://mandrill.com>`_ transactional
email service into Django.
In general, Djrill "just works" with Django's built-in `django.core.mail`
package. It includes:
* Support for HTML, attachments, extra headers, and other features of
`Django's built-in email <https://docs.djangoproject.com/en/dev/topics/email/>`_
* Mandrill-specific extensions like tags, metadata, tracking, and MailChimp templates
* An optional Django admin interface
Djrill is released under the BSD license. It is tested against Django 1.3, 1.4, and 1.5
(including Python 3 support with Django 1.5). |buildstatus|
.. END shared-intro
Resources:
* Full documentation: https://djrill.readthedocs.org/en/latest/
* Package on PyPI: https://pypi.python.org/pypi/djrill
* Project on Github: https://github.com/brack3t/Djrill
Djrill 1-2-3
------------
Install from PyPI::
.. _quickstart:
.. This quickstart section is also included in docs/quickstart.rst
pip install djrill
1. Install Djrill from PyPI:
The only dependency other than Django is the requests_ library from Kenneth
Reitz. (If you do not install Djrill using pip or setuptools, you will also
need to ``pip install requests``.)
.. code-block:: console
$ pip install djrill
Configuration
-------------
In ``settings.py``:
2. Edit your project's ``settings.py``:
1. Add ``djrill`` to your ``INSTALLED_APPS``:
.. code-block:: python
.. code:: python
INSTALLED_APPS = (
...
"djrill"
)
INSTALLED_APPS = (
...
"djrill"
)
MANDRILL_API_KEY = "<your Mandrill key>"
EMAIL_BACKEND = "djrill.mail.backends.djrill.DjrillBackend"
2. Add the following line, substituting your own ``MANDRILL_API_KEY``:
.. code:: python
3. Now the regular `Django email functions <https://docs.djangoproject.com/en/dev/topics/email/>`_
will send through Mandrill:
MANDRILL_API_KEY = "brack3t-is-awesome"
.. code-block:: python
3. Override your existing email backend with the following line:
from django.core.mail import send_mail
.. code:: python
send_mail("It works!", "This will get sent through Mandrill",
"Djrill Sender <djrill@example.com>", ["to@example.com"])
EMAIL_BACKEND = "djrill.mail.backends.djrill.DjrillBackend"
4. (optional) If you want to be able to add senders through Django's admin or
view stats about your messages, do the following in your base ``urls.py``:
You could send an HTML message, complete with custom Mandrill tags and metadata:
.. code:: python
.. code-block:: python
...
from django.contrib import admin
from django.core.mail import EmailMultiAlternatives
from djrill import DjrillAdminSite
msg = EmailMultiAlternatives(
subject="Djrill Message",
body="This is the text email body",
from_email="Djrill Sender <djrill@example.com>",
to=["Recipient One <someone@example.com>", "another.person@example.com"],
headers={'Reply-To': "Service <support@example.com>"} # optional extra headers
)
msg.attach_alternative("<p>This is the HTML email body</p>", "text/html")
admin.site = DjrillAdminSite()
admin.autodiscover()
...
# Optional Mandrill-specific extensions:
msg.tags = ["one tag", "two tag", "red tag", "blue tag"]
msg.metadata = {'user_id': "8675309"}
urlpatterns = patterns('',
...
url(r'^admin/', include(admin.site.urls)),
)
# Send it:
msg.send()
Usage
-----
(Be sure to use a ``from_email`` that's in one of your Mandrill approved sending
domains, or the message won't get sent.)
Since you are replacing the global ``EMAIL_BACKEND``, **all** emails are sent
through Mandrill's service. (To selectively use Mandrill for some messages, see
`Using Multiple Email Backends`_ below.)
.. END quickstart
In general, Djrill "just works" with Django's built-in `django.core.mail`_
package, including ``send_mail``, ``send_mass_mail``, ``EmailMessage`` and
``EmailMultiAlternatives``.
You can also take advantage of Mandrill-specific features like tags, metadata,
and tracking by creating a Django EmailMessage_ (or for HTML,
EmailMultiAlternatives_) object and setting Mandrill-specific
properties on it before calling its ``send`` method. (See
`Mandrill Message Options`_ below.)
Example, sending HTML email with Mandrill tags and metadata:
.. code:: python
from django.core.mail import EmailMultiAlternatives
msg = EmailMultiAlternatives(
subject="Djrill Message",
body="This is the text version of your email",
from_email="Djrill Sender <djrill@example.com>",
to=["Djrill Receiver <djrill.receiver@example.com>", "another.person@example.com"],
headers={'Reply-To': "Service <support@example.com>"} # optional extra headers
)
msg.attach_alternative("<p>This is the HTML version of your email</p>", "text/html")
# Optional Mandrill-specific extensions (see full list below):
msg.tags = ["one tag", "two tag", "red tag", "blue tag"]
msg.metadata = {'user_id': "8675309"}
# Send it:
msg.send()
If the email tries to use features that aren't supported by Mandrill, the send
call will raise a ``djrill.NotSupportedByMandrillError`` exception (a subclass
of ValueError).
If the Mandrill API fails or returns an error response, the send call will
raise a ``djrill.MandrillAPIError`` exception (a subclass of
requests.HTTPError).
Django EmailMessage Support
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Djrill supports most of the functionality of Django's `EmailMessage`_ and
`EmailMultiAlternatives`_ classes. Some notes and limitations:
* **Display Names:** All email addresses (from, to, cc) can be simple
("email@example.com") or can include a display name
("Real Name <email@example.com>").
* **From Address:** The ``from_email`` must be in one of the approved sending
domains in your Mandrill account.
* **CC Recipients:** Djrill treats all "cc" recipients as if they were
additional "to" addresses. (Mandrill does not distinguish "cc" from "to".)
Note that you will also need to set ``preserve_recipients`` True if you want
each recipient to see the other recipients listed in the email headers.
* **BCC Recipients:** Mandrill does not permit more than one "bcc" address.
Djrill raises ``djrill.NotSupportedByMandrillError`` if you attempt to send a
message with multiple bcc's. (Mandrill's bcc option seems intended primarily
for logging. To send a single message to multiple recipients without exposing
their email addresses to each other, simply include them all in the "to" list
and leave ``preserve_recipients`` set to False.)
* **Attachments:** Djrill includes a message's attachments. Also, if an image
attachment has a Content-ID header, Djrill will tell Mandrill to treat that
as an embedded image rather than an ordinary attachment. (For an example,
see ``test_embedded_images`` in tests/test_mandrill_send.py.)
* **Headers:** Djrill accepts additional headers, but only ``Reply-To`` and
``X-*`` (since that is all that Mandrill accepts). Any other extra headers
will raise ``djrill.NotSupportedByMandrillError`` when you attempt to send the
message.
* **Alternative Parts:** Djrill requires that if you ``attach_alternative`` to a
message, there must be only one alternative part, and it must be text/html.
Otherwise, Djrill will raise ``djrill.NotSupportedByMandrillError`` when you
attempt to send the message. (Mandrill doesn't support sending multiple html
alternative parts, or any non-html alternatives.)
Mandrill Message Options
~~~~~~~~~~~~~~~~~~~~~~~~
Many of the options from the Mandrill `messages/send API`_ ``message``
struct can be set directly on an ``EmailMessage`` (or subclass) object:
* ``track_opens`` - Boolean
* ``track_clicks`` - Boolean (If you want to track clicks in HTML only, not
plaintext mail, you must *not* set this property, and instead just set the
default in your Mandrill account sending options.)
* ``auto_text`` - Boolean
* ``url_strip_qs`` - Boolean
* ``preserve_recipients`` - Boolean
* ``global_merge_vars`` - a dict -- e.g.,
``{ 'company': "ACME", 'offer': "10% off" }``
* ``recipient_merge_vars`` - a dict whose keys are the recipient email addresses
and whose values are dicts of merge vars for each recipient -- e.g.,
``{ 'wiley@example.com': { 'offer': "15% off anvils" } }``
* ``tags`` - a list of strings
* ``google_analytics_domains`` - a list of string domain names
* ``google_analytics_campaign`` - a string or list of strings
* ``metadata`` - a dict
* ``recipient_metadata`` - a dict whose keys are the recipient email addresses,
and whose values are dicts of metadata for each recipient (similar to
``recipient_merge_vars``)
These Mandrill-specific properties work with *any* ``EmailMessage``-derived
object, so you can use them with many other apps that add Django mail
functionality (such as Django template-based messages).
If you have any questions about the python syntax for any of these properties,
see ``DjrillMandrillFeatureTests`` in tests/test_mandrill_send.py for examples.
Mandrill Templates
~~~~~~~~~~~~~~~~~~
To use a Mandrill (MailChimp) template, set a ``template_name`` and (optionally)
``template_content`` on your ``EmailMessage`` object:
.. code:: python
msg = EmailMessage(subject="Shipped!", from_email="store@example.com",
to=["customer@example.com", "accounting@example.com"])
msg.template_name = "SHIPPING_NOTICE" # A Mandrill template name
msg.template_content = { # Content blocks to fill in
'TRACKING_BLOCK': "<a href='.../\*\|TRACKINGNO\|\*'>track it</a>" }
msg.global_merge_vars = { # Merge tags in your template
'ORDERNO': "12345", 'TRACKINGNO': "1Z987" }
msg.merge_vars = { # Per-recipient merge tags
'accounting@example.com': { 'NAME': "Pat" },
'customer@example.com': { 'NAME': "Kim" } }
msg.send()
If template_name is set, Djrill will use Mandrill's `messages/send-template API`_,
rather than messages/send. All of the other options listed above can be used.
(This is for *MailChimp* templates stored in your Mandrill account. If you
want to use a *Django* template, you can use Django's render_to_string_ template
shortcut to build the body and html, and send using EmailMultiAlternatives as
in the earlier examples.)
Using Multiple Email Backends
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can use Django mail's optional ``connection`` argument to send some mail
through Mandrill and others through a different system. This can be useful to
send customer emails with Mandrill, but admin emails directly through an SMTP
server. Example:
.. code:: python
from django.core.mail import send_mail, get_connection
# send_mail connection defaults to the settings EMAIL_BACKEND, which
# we've set to DjrillBackend. This will be sent using Mandrill:
send_mail("Subject", "Body", "support@example.com", ["user@example.com"])
# Get a connection to an SMTP backend, and send using that instead:
smtp_backend = get_connection('django.core.mail.backends.smtp.EmailBackend')
send_mail("Subject", "Body", "admin@example.com", ["alert@example.com"],
connection=smtp_backend)
You can supply a different connection to Django's `django.core.mail`_
``send_mail`` and ``send_mass_mail`` helpers, and in the constructor for an
EmailMessage_ or EmailMultiAlternatives_.
Testing
-------
Djrill is tested against Django 1.3 and 1.4 on Python 2.6 and 2.7, and
Django 1.5RC on Python 2.7 and 3.2.
(It may also work with Django 1.2 and Python 2.5, if you use an older
version of requests compatible with that code.)
.. image:: https://secure.travis-ci.org/brack3t/Djrill.png?branch=master
:target: https://travis-ci.org/brack3t/Djrill
The included tests verify that Djrill constructs the expected Mandrill API
calls, without actually calling Mandrill or sending any email. So the tests
don't require a Mandrill API key, but they *do* require mock_
(``pip install mock``). To run the tests, either::
python -Wall setup.py test
or::
python -Wall runtests.py
Contributing
------------
Djrill is maintained by its users -- it's not managed by the folks at MailChimp.
Pull requests are always welcome to improve support for Mandrill and Django
features.
Please include test cases with pull requests. (And by submitting a pull request,
you're agreeing to release your changes under under the same BSD license as the
rest of this project.)
Release Notes
-------------
Version 0.3.0:
* Attachments are now supported
* Mandrill templates are now supported
* A bcc address is now passed to Mandrill as bcc, rather than being lumped in
with the "to" recipients. Multiple bcc recipients will now raise an exception,
as Mandrill only allows one.
* Python 3 support (with Django 1.5)
* Exceptions should be more useful: ``djrill.NotSupportedByMandrillError``
replaces generic ValueError; ``djrill.MandrillAPIError`` replaces
DjrillBackendHTTPError, and is now derived from requests.HTTPError. (New
exceptions are backwards compatible with old ones for existing code.)
Version 0.2.0:
* ``MANDRILL_API_URL`` is no longer required in settings.py
* Earlier versions of Djrill required use of a ``DjrillMessage`` class to
specify Mandrill-specific options. This is no longer needed -- Mandrill
options can now be set directly on a Django EmailMessage_ object or any
subclass. (Existing code can continue to use ``DjrillMessage``.)
Thanks
------
Thanks to the MailChimp team for asking us to build this nifty little app. Also thanks to James Socol on Github for his
django-adminplus_ library that got us off on the right foot for the custom admin views. Oh, and, of course, Kenneth Reitz for
the awesome ``requests`` library.
.. _Mandrill: http://mandrill.com
.. _MailChimp: http://mailchimp.com
.. _requests: http://docs.python-requests.org
.. _django-adminplus: https://github.com/jsocol/django-adminplus
.. _mock: http://www.voidspace.org.uk/python/mock/index.html
.. _django.core.mail: https://docs.djangoproject.com/en/dev/topics/email/
.. _EmailMessage: https://docs.djangoproject.com/en/dev/topics/email/#django.core.mail.EmailMessage
.. _EmailMultiAlternatives: https://docs.djangoproject.com/en/dev/topics/email/#sending-alternative-content-types
.. _render_to_string: https://docs.djangoproject.com/en/dev/ref/templates/api/#the-render-to-string-shortcut
.. _messages/send API: https://mandrillapp.com/api/docs/messages.html#method=send
.. _messages/send-template API: https://mandrillapp.com/api/docs/messages.html#method=send-template
See the `full documentation <https://djrill.readthedocs.org/en/latest/>`_
for more features and options.

View File

@@ -4,8 +4,7 @@ from django.utils.text import capfirst
from djrill.exceptions import MandrillAPIError, NotSupportedByMandrillError
VERSION = (0, 3, 1)
__version__ = '.'.join([str(x) for x in VERSION])
from ._version import *
# This backend was developed against this API endpoint.
# You can override in settings.py, if desired.

3
djrill/_version.py Normal file
View File

@@ -0,0 +1,3 @@
VERSION = (0, 3, 9)
__version__ = '.'.join([str(x) for x in VERSION])
__minor_version__ = '.'.join([str(x) for x in VERSION[:2]]) # Sphinx's X.Y "version"

153
docs/Makefile Normal file
View File

@@ -0,0 +1,153 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
-rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Djrill.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Djrill.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/Djrill"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Djrill"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."

282
docs/conf.py Normal file
View File

@@ -0,0 +1,282 @@
# -*- coding: utf-8 -*-
#
# Djrill documentation build configuration file, created by
# sphinx-quickstart on Sat Mar 2 13:07:34 2013.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys, os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
sys.path.insert(0, os.path.abspath('..'))
# define __version__ and __minor_version__ from ../djrill/_version.py,
# but without importing from djrill (which would make docs dependent on Django, etc.)
with open("../djrill/_version.py") as f:
code = compile(f.read(), "../djrill/_version.py", 'exec')
exec(code)
# -- General configuration -----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.intersphinx']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'Djrill'
# noinspection PyShadowingBuiltins
copyright = u'2013, Djrill contributors (see AUTHORS.txt)'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = __minor_version__
# The full version, including alpha/beta/rc tags.
release = __version__
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for all documents.
default_role = "py:obj"
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# -- Options for HTML output ---------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'default'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'Djrilldoc'
# -- Options for LaTeX output --------------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index', 'Djrill.tex', u'Djrill Documentation',
u'Djrill contributors (see AUTHORS.txt)', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output --------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'djrill', u'Djrill Documentation',
[u'Djrill contributors (see AUTHORS.txt)'], 1)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# -- Options for Texinfo output ------------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'Djrill', u'Djrill Documentation',
u'Djrill contributors (see AUTHORS.txt)', 'Djrill', 'Mandrill integration for Django.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
# -- Options for Intersphinx ------------------------------------------------
intersphinx_mapping = {
'python': ('http://docs.python.org/2.7', None),
'django': ('http://docs.djangoproject.com/en/dev/', 'http://docs.djangoproject.com/en/dev/_objects/'),
'requests': ('http://docs.python-requests.org/en/latest/', None),
}
def setup(app):
# Django-specific roles, from https://github.com/django/django/blob/master/docs/_ext/djangodocs.py:
app.add_crossref_type(
directivename = "setting",
rolename = "setting",
indextemplate = "pair: %s; setting",
)
app.add_crossref_type(
directivename = "templatetag",
rolename = "ttag",
indextemplate = "pair: %s; template tag"
)
app.add_crossref_type(
directivename = "templatefilter",
rolename = "tfilter",
indextemplate = "pair: %s; template filter"
)
app.add_crossref_type(
directivename = "fieldlookup",
rolename = "lookup",
indextemplate = "pair: %s; field lookup type",
)

54
docs/contributing.rst Normal file
View File

@@ -0,0 +1,54 @@
Contributing
============
Djrill is maintained by its users. Your contributions are encouraged!
The `Djrill source code`_ is on github. See `AUTHORS.txt`_ for a list
of some of the people who have helped improve Djrill.
.. _Djrill source code: https://github.com/brack3t/Djrill:
.. _AUTHORS.txt: https://github.com/brack3t/Djrill/blob/master/AUTHORS.txt
Bugs
----
You can report problems or request features in
`Djrill's github issue tracker <https://github.com/brack3t/Djrill/issues>`_.
Pull Requests
-------------
Pull requests are always welcome to fix bugs and improve support for Mandrill and Django features.
* Please include test cases.
* We try to follow the `Django coding style`_ (basically, PEP 8 with longer lines OK).
* By submitting a pull request, you're agreeing to release your changes under under
the same BSD license as the rest of this project.
.. _Django coding style: https://docs.djangoproject.com/en/dev/internals/contributing/writing-code/coding-style/
Testing
-------
Djrill is `tested on Travis <https://travis-ci.org/brack3t/Djrill>`_ against:
* Django 1.3 on Python 2.6 and 2.7
* Django 1.4 on Python 2.6 and 2.7
* Django 1.5 on Python 2.7 and 3.2
The included tests verify that Djrill constructs the expected Mandrill API
calls, without actually calling Mandrill or sending any email. So the tests
don't require a Mandrill API key, but they *do* require
`mock <http://www.voidspace.org.uk/python/mock/index.html>`_ (``pip install mock``).
To run the tests, either::
python -Wall setup.py test
or::
python -Wall runtests.py

25
docs/history.rst Normal file
View File

@@ -0,0 +1,25 @@
Release Notes
=============
Version 0.3.0:
* :ref:`Attachments <sending-attachments>` are now supported
* :ref:`Mandrill templates <mandrill-templates>` are now supported
* A bcc address is now passed to Mandrill as bcc, rather than being lumped in
with the "to" recipients. Multiple bcc recipients will now raise an exception,
as Mandrill only allows one.
* Python 3 support (with Django 1.5)
* Exceptions should be more useful:
:exc:`djrill.NotSupportedByMandrillError` replaces generic ValueError;
:exc:`djrill.MandrillAPIError` replaces DjrillBackendHTTPError, and is now
derived from requests.HTTPError.
(New exceptions are backwards compatible with old ones for existing code.)
Version 0.2.0:
* ``MANDRILL_API_URL`` is no longer required in settings.py
* Earlier versions of Djrill required use of a ``DjrillMessage`` class to
specify Mandrill-specific options. This is no longer needed -- Mandrill
options can now be set directly on a Django ``EmailMessage`` object or any
subclass. (Existing code can continue to use ``DjrillMessage``.)

45
docs/index.rst Normal file
View File

@@ -0,0 +1,45 @@
.. Djrill documentation master file, created by
sphinx-quickstart on Sat Mar 2 13:07:34 2013.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
.. Incorporate the shared-intro section from the root README:
.. include:: ../README.rst
:start-after: _shared-intro:
:end-before: END shared-intro
.. Eliminate the README's Travis build status indicator.
(Is there some way we could link to Travis status for the
specific |VERSION| of the app being documented here???)
.. |buildstatus| replace:: \
.. _toc:
Documentation
-------------
.. toctree::
:maxdepth: 2
quickstart
installation
usage/sending_mail
usage/templates
usage/multiple_backends
contributing
history
Thanks
------
Thanks to the MailChimp team for asking us to build this nifty little app, and to all of Djrill's
:doc:`contributors <contributing>`. Also thanks to James Socol on Github for his django-adminplus_
library that got us off on the right foot for the custom admin views.
Oh, and, of course, Kenneth Reitz for the awesome requests_ library.
.. _requests: http://docs.python-requests.org
.. _django-adminplus: https://github.com/jsocol/django-adminplus

61
docs/installation.rst Normal file
View File

@@ -0,0 +1,61 @@
Installation
============
It's easiest to install Djrill from `PyPI <https://pypi.python.org/pypi/djrill>`_:
.. code-block:: console
$ pip install djrill
If you decide to install Djrill some other way, you'll also need to install its
one dependency (other than Django, of course): the `requests <http://docs.python-requests.org>`_
library from Kenneth Reitz.
Configuration
-------------
In your project's :file:`settings.py`:
1. Add :mod:`djrill` to your :setting:`INSTALLED_APPS`::
INSTALLED_APPS = (
...
"djrill"
)
2. Add the following line, substituting your own :setting:`MANDRILL_API_KEY`::
MANDRILL_API_KEY = "brack3t-is-awesome"
3. Override your existing :setting:`EMAIL_BACKEND` with the following line::
EMAIL_BACKEND = "djrill.mail.backends.djrill.DjrillBackend"
Admin (Optional)
----------------
Djrill includes an optional Django admin interface, which allows you to:
* Check the status of your Mandrill API connection
* See stats on email senders, tags and urls
If you want to enable the Djrill admin interface, edit your base :file:`urls.py`:
.. code-block:: python
:emphasize-lines: 4,6
...
from django.contrib import admin
from djrill import DjrillAdminSite
admin.site = DjrillAdminSite()
admin.autodiscover()
...
urlpatterns = patterns('',
...
url(r'^admin/', include(admin.site.urls)),
)

190
docs/make.bat Normal file
View File

@@ -0,0 +1,190 @@
@ECHO OFF
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set BUILDDIR=_build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
set I18NSPHINXOPTS=%SPHINXOPTS% .
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^<target^>` where ^<target^> is one of
echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories
echo. singlehtml to make a single large HTML file
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. devhelp to make HTML files and a Devhelp project
echo. epub to make an epub
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. text to make text files
echo. man to make manual pages
echo. texinfo to make Texinfo files
echo. gettext to make PO message catalogs
echo. changes to make an overview over all changed/added/deprecated items
echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled
goto end
)
if "%1" == "clean" (
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
del /q /s %BUILDDIR%\*
goto end
)
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end
)
if "%1" == "singlehtml" (
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Djrill.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Djrill.ghc
goto end
)
if "%1" == "devhelp" (
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished.
goto end
)
if "%1" == "epub" (
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The epub file is in %BUILDDIR%/epub.
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
if errorlevel 1 exit /b 1
echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "text" (
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The text files are in %BUILDDIR%/text.
goto end
)
if "%1" == "man" (
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The manual pages are in %BUILDDIR%/man.
goto end
)
if "%1" == "texinfo" (
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
goto end
)
if "%1" == "gettext" (
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
if errorlevel 1 exit /b 1
echo.
echo.The overview file is in %BUILDDIR%/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
if errorlevel 1 exit /b 1
echo.
echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
if errorlevel 1 exit /b 1
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
goto end
)
:end

9
docs/quickstart.rst Normal file
View File

@@ -0,0 +1,9 @@
Djrill 1-2-3
============
.. Quickstart is maintained in README.rst at the source root.
(Docs can include from the readme; the readme can't include anything.)
.. include:: ../README.rst
:start-after: _quickstart:
:end-before: END quickstart

View File

@@ -0,0 +1,32 @@
.. _multiple-backends:
Mixing Email Backends
=====================
Since you are replacing Django's global :setting:`EMAIL_BACKEND`, by default
Djrill will handle all outgoing mail, sending everything through Mandrill.
You can use Django mail's optional :func:`connection <django.core.mail.get_connection>`
argument to send some mail through Mandrill and others through a different system.
This could be useful, for example, to deliver customer emails with Mandrill,
but send admin emails directly through an SMTP server:
.. code-block:: python
:emphasize-lines: 8,10
from django.core.mail import send_mail, get_connection
# send_mail connection defaults to the settings EMAIL_BACKEND, which
# we've set to DjrillBackend. This will be sent using Mandrill:
send_mail("Thanks", "We sent your order", "sales@example.com", ["customer@example.com"])
# Get a connection to an SMTP backend, and send using that instead:
smtp_backend = get_connection('django.core.mail.backends.smtp.EmailBackend')
send_mail("Uh-Oh", "Need your attention", "admin@example.com", ["alert@example.com"],
connection=smtp_backend)
You can supply a different connection to Django's
:func:`~django.core.mail.send_mail` and :func:`~django.core.mail.send_mass_mail` helpers,
and in the constructor for an
:class:`~django.core.mail.EmailMessage` or :class:`~django.core.mail.EmailMultiAlternatives`.

225
docs/usage/sending_mail.rst Normal file
View File

@@ -0,0 +1,225 @@
Sending Mail
============
Djrill handles **all** outgoing email sent through Django's standard
:mod:`django.core.mail` package, including :func:`~django.core.mail.send_mail`,
:func:`~django.core.mail.send_mass_mail`, the :class:`~django.core.mail.EmailMessage` class,
and even :func:`~django.core.mail.mail_admins`.
If you'd like to selectively send only some messages through Mandrill,
there is a way to :ref:`use multiple email backends <multiple-backends>`.
.. _django-send-support:
Django Email Support
--------------------
Djrill supports most of the functionality of Django's :class:`~django.core.mail.EmailMessage`
and :class:`~django.core.mail.EmailMultiAlternatives` classes.
Some notes and limitations:
**Display Names**
All email addresses (from, to, cc) can be simple
("email\@example.com") or can include a display name
("Real Name <email\@example.com>").
**From Address**
The ``from_email`` must be in one of the approved sending
domains in your Mandrill account, or Mandrill will refuse to send the message.
**CC Recipients**
Djrill treats all "cc" recipients as if they were
additional "to" addresses. (Mandrill does not distinguish "cc" from "to".)
.. note::
By default, Mandrill hides all recipients from each other. If you want the
headers to list everyone who was sent the message, you'll also need to set the
Mandrill option :attr:`preserve_recipients` to `!True`
**BCC Recipients**
Mandrill does not permit more than one "bcc" address.
Djrill raises :exc:`~djrill.NotSupportedByMandrillError` if you attempt to send a
message with multiple bcc's.
(Mandrill's bcc option seems intended primarily
for logging. To send a single message to multiple recipients without exposing
their email addresses to each other, simply include them all in the "to" list
and leave Mandrill's :attr:`preserve_recipients` set to `!False`.)
.. versionadded:: 0.3
Previously "bcc" was treated as "cc"
.. _sending-html:
**HTML/Alternative Parts**
To include an HTML version of a message, use
:meth:`~django.core.mail.EmailMultiAlternatives.attach_alternative`:
.. code-block:: python
from django.core.mail import EmailMultiAlternatives
msg = EmailMultiAlternatives("Subject", "text body",
"from@example.com", ["to@example.com"])
msg.attach_alternative("<html>html body</html>", "text/html")
Djrill allows a maximum of one
:meth:`~django.core.mail.EmailMultiAlternatives.attach_alternative`
on a message, and it must be ``mimetype="text/html"``.
Otherwise, Djrill will raise :exc:`~djrill.NotSupportedByMandrillError` when you
attempt to send the message. (Mandrill doesn't support sending multiple html
alternative parts, or any non-html alternatives.)
.. _sending-attachments:
**Attachments**
Djrill will send a message's attachments. (Note that Mandrill may impose limits
on size and type of attachments.)
Also, if an image attachment has a Content-ID header, Djrill will tell Mandrill
to treat that as an embedded image rather than an ordinary attachment.
(For an example, see :meth:`~DjrillBackendTests.test_embedded_images`
in :file:`tests/test_mandrill_send.py`.)
.. versionadded:: 0.3
Attachments
.. versionchanged:: 0.4
Special handling for embedded images
**Headers**
Djrill accepts additional headers, but only ``Reply-To`` and
``X-*`` (since that is all that Mandrill accepts). Any other extra headers
will raise :exc:`~djrill.NotSupportedByMandrillError` when you attempt to send the
message.
.. _mandrill-send-support:
Mandrill-Specific Options
-------------------------
Most of the options from the Mandrill
`messages/send API <https://mandrillapp.com/api/docs/messages.html#method=send>`_
`message` struct can be set directly on an :class:`~django.core.mail.EmailMessage`
(or subclass) object:
.. attribute:: track_opens
``Boolean``: whether Mandrill should enable open-tracking for this message.
Default from your Mandrill account settings. ::
message.track_opens = True
.. attribute:: track_clicks
``Boolean``: whether Mandrill should enable click-tracking for this message.
Default from your Mandrill account settings.
.. note::
Mandrill has an option to track clicks in HTML email but not plaintext, but
it's *only* available in your Mandrill account settings. If you want to use that
option, set it at Mandrill, and *don't* set the ``track_clicks`` attribute here.
.. attribute:: auto_text
``Boolean``: whether Mandrill should automatically generate a text body from the HTML.
Default from your Mandrill account settings.
.. attribute:: url_strip_qs
``Boolean``: whether Mandrill should ignore any query parameters when aggregating
URL tracking data. Default from your Mandrill account settings.
.. attribute:: preserve_recipients
``Boolean``: whether Mandrill should include all recipients in the "to" message header.
Default from your Mandrill account settings.
.. attribute:: global_merge_vars
``dict``: merge variables to use for all recipients (most useful with :ref:`mandrill-templates`). ::
message.global_merge_vars = {'company': "ACME", 'offer': "10% off"}
.. attribute:: recipient_merge_vars
``dict``: per-recipient merge variables (most useful with :ref:`mandrill-templates`). The keys
in the dict are the recipient email addresses, and the values are dicts of merge vars for
each recipient::
message.recipient_merge_vars = {
'wiley@example.com': {'offer': "15% off anvils"},
'rr@example.com': {'offer': "instant tunnel paint"}
}
.. attribute:: tags
``list`` of ``str``: tags to apply to the message, for filtering reports in the Mandrill
dashboard. (Note that Mandrill prohibits tags longer than 50 characters or starting with
underscores.) ::
message.tags = ["Order Confirmation", "Test Variant A"]
.. attribute:: google_analytics_domains
``list`` of ``str``: domain names for links where Mandrill should add Google Analytics
tracking parameters. ::
message.google_analytics_domains = ["example.com"]
.. attribute:: google_analytics_campaign
``str`` or ``list`` of ``str``: the utm_campaign tracking parameter to attach to links
when adding Google Analytics tracking. (Mandrill defaults to the message's from_email as
the campaign name.)
.. attribute:: metadata
``dict``: metadata values Mandrill should store with the message for later search and
retrieval. ::
message.metadata = {'customer': customer.id, 'order': order.reference_number}
.. attribute:: recipient_metadata
``dict``: per-recipient metadata values. Keys are the recipient email addresses,
and values are dicts of metadata for each recipient (similar to
:attr:`recipient_merge_vars`)
These Mandrill-specific properties work with *any*
:class:`~django.core.mail.EmailMessage`-derived object, so you can use them with
many other apps that add Django mail functionality.
If you have questions about the python syntax for any of these properties,
see :class:`DjrillMandrillFeatureTests` in :file:`tests/test_mandrill_send.py` for examples.
.. _djrill-exceptions:
Exceptions
----------
.. versionadded:: 0.3
Djrill-specific exceptions
.. exception:: djrill.NotSupportedByMandrillError
If the email tries to use features that aren't supported by Mandrill, the send
call will raise a :exc:`~!djrill.NotSupportedByMandrillError` exception (a subclass
of :exc:`ValueError`).
.. exception:: djrill.MandrillAPIError
If the Mandrill API fails or returns an error response, the send call will
raise a :exc:`~!djrill.MandrillAPIError` exception (a subclass of :exc:`requests.HTTPError`).
The exception's :attr:`status_code` and :attr:`response` attributes may
help explain what went wrong.

70
docs/usage/templates.rst Normal file
View File

@@ -0,0 +1,70 @@
Sending Template Mail
=====================
.. _mandrill-templates:
Mandrill Templates
------------------
.. versionadded:: 0.3
Mandrill template support
To use a *Mandrill* (MailChimp) template stored in your Mandrill account,
set a :attr:`template_name` and (optionally) :attr:`template_content`
on your :class:`~django.core.mail.EmailMessage` object::
from django.core.mail import EmailMessage
msg = EmailMessage(subject="Shipped!", from_email="store@example.com",
to=["customer@example.com", "accounting@example.com"])
msg.template_name = "SHIPPING_NOTICE" # A Mandrill template name
msg.template_content = { # Content blocks to fill in
'TRACKING_BLOCK': "<a href='.../*|TRACKINGNO|*'>track it</a>"
}
msg.global_merge_vars = { # Merge tags in your template
'ORDERNO': "12345", 'TRACKINGNO': "1Z987"
}
msg.merge_vars = { # Per-recipient merge tags
'accounting@example.com': {'NAME': "Pat"},
'customer@example.com': {'NAME': "Kim"}
}
msg.send()
If :attr:`template_name` is set, Djrill will use Mandrill's
`messages/send-template API <https://mandrillapp.com/api/docs/messages.html#method=send-template>`_,
and will ignore any `body` text set on the `EmailMessage`.
All of Djrill's other :ref:`Mandrill-specific options <mandrill-send-support>`
can be used with templates.
.. _django-templates:
Django Templates
----------------
To compose email using *Django* templates, you can use Django's
:func:`~django.template.loaders.django.template.loader.render_to_string`
template shortcut to build the body and html.
Example that builds an email from the templates ``message_subject.txt``,
``message_body.txt`` and ``message_body.html``::
from django.core.mail import EmailMultiAlternatives
from django.template import Context
from django.template.loader import render_to_string
template_data = {
'ORDERNO': "12345", 'TRACKINGNO': "1Z987"
}
plaintext_context = Context(autoescape=False) # HTML escaping not appropriate in plaintext
subject = render_to_string("message_subject.txt", template_data, plaintext_context)
text_body = render_to_string("message_body.txt", template_data, plaintext_context)
html_body = render_to_string("message_body.html", template_data)
msg = EmailMessage(subject=subject, from_email="store@example.com",
to=["customer@example.com"], body=text_body)
msg.attach_alternative(html_body, "text/html")
msg.send()

View File

@@ -1,14 +1,31 @@
from setuptools import setup
import re
with open('LICENSE') as file:
license_text = file.read()
with open('README.rst') as file:
long_description = file.read()
# define __version__ and __minor_version__ from djrill/_version.py,
# but without importing from djrill (which would break setup)
with open("djrill/_version.py") as f:
code = compile(f.read(), "djrill/_version.py", 'exec')
exec(code)
def long_description_from_readme(rst):
# Patch up some rest substitution variables (references only - not definitions):
rst = re.sub(r'(?<!\.\. )\|release\|', __version__, rst)
rst = re.sub(r'(?<!\.\. )\|version\|', __minor_version__, rst)
rst = re.sub(r'(?<!\.\. )\|buildstatus\|', "", rst) # hide latest-code Travis status indicator
rst = re.sub(r'(djrill\.readthedocs\.org/\w+)/latest',
r'\1/' + __version__, rst) # freeze docs link to this version
return rst
with open('LICENSE') as f:
license_text = f.read()
with open('README.rst') as f:
long_description = long_description_from_readme(f.read())
setup(
name="djrill",
version="0.3.1",
description='Django email backend for Mandrill.',
version=__version__,
description='Mandrill transactional email for Django',
keywords="django, mailchimp, mandrill, email, email backend",
author="Kenneth Love <kenneth@brack3t.com>, Chris Jones <chris@brack3t.com>",
author_email="kenneth@brack3t.com",