mirror of
https://github.com/pacnpal/django-anymail.git
synced 2025-12-20 11:51:05 -05:00
Merge pull request #30 from brack3t/docs
Break up readme into docs; add to readthedocs.org
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,5 +3,6 @@
|
|||||||
*.pyc
|
*.pyc
|
||||||
*.egg-info
|
*.egg-info
|
||||||
dist/
|
dist/
|
||||||
|
docs/_build/
|
||||||
TODO.txt
|
TODO.txt
|
||||||
local.py
|
local.py
|
||||||
|
|||||||
352
README.rst
352
README.rst
@@ -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
|
.. 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
|
||||||
|
|
||||||
|
.. |release| replace:: (source)
|
||||||
|
|
||||||
|
.. |version| replace:: |release|
|
||||||
|
|
||||||
|
.. |buildstatus| image:: https://secure.travis-ci.org/brack3t/Djrill.png?branch=master
|
||||||
:target: https://travis-ci.org/brack3t/Djrill
|
:target: https://travis-ci.org/brack3t/Djrill
|
||||||
|
|
||||||
Djrill is an email backend for Django users who want to take advantage of the
|
.. default-role:: literal
|
||||||
Mandrill_ transactional email service from MailChimp_.
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
An optional Django admin interface is included. The admin interface allows you to:
|
.. _shared-intro:
|
||||||
|
.. This shared-intro section is also included in docs/index.rst
|
||||||
|
|
||||||
* Check the status of your Mandrill API connection.
|
Djrill: Mandrill Transactional Email for Django
|
||||||
* See stats on email senders, tags and urls.
|
===============================================
|
||||||
|
|
||||||
Djrill is made available under the BSD license.
|
Release |release|
|
||||||
|
|
||||||
Installation
|
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
|
.. code-block:: console
|
||||||
Reitz. (If you do not install Djrill using pip or setuptools, you will also
|
|
||||||
need to ``pip install requests``.)
|
$ pip install djrill
|
||||||
|
|
||||||
|
|
||||||
Configuration
|
2. Edit your project's ``settings.py``:
|
||||||
-------------
|
|
||||||
|
|
||||||
In ``settings.py``:
|
.. code-block:: python
|
||||||
|
|
||||||
1. Add ``djrill`` to your ``INSTALLED_APPS``:
|
|
||||||
|
|
||||||
.. code:: python
|
|
||||||
|
|
||||||
INSTALLED_APPS = (
|
INSTALLED_APPS = (
|
||||||
...
|
...
|
||||||
"djrill"
|
"djrill"
|
||||||
)
|
)
|
||||||
|
|
||||||
2. Add the following line, substituting your own ``MANDRILL_API_KEY``:
|
MANDRILL_API_KEY = "<your Mandrill key>"
|
||||||
|
|
||||||
.. code:: python
|
|
||||||
|
|
||||||
MANDRILL_API_KEY = "brack3t-is-awesome"
|
|
||||||
|
|
||||||
3. Override your existing email backend with the following line:
|
|
||||||
|
|
||||||
.. code:: python
|
|
||||||
|
|
||||||
EMAIL_BACKEND = "djrill.mail.backends.djrill.DjrillBackend"
|
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``:
|
|
||||||
|
|
||||||
.. code:: python
|
3. Now the regular `Django email functions <https://docs.djangoproject.com/en/dev/topics/email/>`_
|
||||||
|
will send through Mandrill:
|
||||||
|
|
||||||
...
|
.. code-block:: python
|
||||||
from django.contrib import admin
|
|
||||||
|
|
||||||
from djrill import DjrillAdminSite
|
from django.core.mail import send_mail
|
||||||
|
|
||||||
admin.site = DjrillAdminSite()
|
send_mail("It works!", "This will get sent through Mandrill",
|
||||||
admin.autodiscover()
|
"Djrill Sender <djrill@example.com>", ["to@example.com"])
|
||||||
...
|
|
||||||
|
|
||||||
urlpatterns = patterns('',
|
|
||||||
...
|
|
||||||
url(r'^admin/', include(admin.site.urls)),
|
|
||||||
)
|
|
||||||
|
|
||||||
Usage
|
You could send an HTML message, complete with custom Mandrill tags and metadata:
|
||||||
-----
|
|
||||||
|
|
||||||
Since you are replacing the global ``EMAIL_BACKEND``, **all** emails are sent
|
.. code-block:: python
|
||||||
through Mandrill's service. (To selectively use Mandrill for some messages, see
|
|
||||||
`Using Multiple Email Backends`_ below.)
|
|
||||||
|
|
||||||
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
|
from django.core.mail import EmailMultiAlternatives
|
||||||
|
|
||||||
msg = EmailMultiAlternatives(
|
msg = EmailMultiAlternatives(
|
||||||
subject="Djrill Message",
|
subject="Djrill Message",
|
||||||
body="This is the text version of your email",
|
body="This is the text email body",
|
||||||
from_email="Djrill Sender <djrill@example.com>",
|
from_email="Djrill Sender <djrill@example.com>",
|
||||||
to=["Djrill Receiver <djrill.receiver@example.com>", "another.person@example.com"],
|
to=["Recipient One <someone@example.com>", "another.person@example.com"],
|
||||||
headers={'Reply-To': "Service <support@example.com>"} # optional extra headers
|
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")
|
msg.attach_alternative("<p>This is the HTML email body</p>", "text/html")
|
||||||
|
|
||||||
# Optional Mandrill-specific extensions (see full list below):
|
# Optional Mandrill-specific extensions:
|
||||||
msg.tags = ["one tag", "two tag", "red tag", "blue tag"]
|
msg.tags = ["one tag", "two tag", "red tag", "blue tag"]
|
||||||
msg.metadata = {'user_id': "8675309"}
|
msg.metadata = {'user_id': "8675309"}
|
||||||
|
|
||||||
# Send it:
|
# Send it:
|
||||||
msg.send()
|
msg.send()
|
||||||
|
|
||||||
If the email tries to use features that aren't supported by Mandrill, the send
|
(Be sure to use a ``from_email`` that's in one of your Mandrill approved sending
|
||||||
call will raise a ``djrill.NotSupportedByMandrillError`` exception (a subclass
|
domains, or the message won't get sent.)
|
||||||
of ValueError).
|
|
||||||
|
|
||||||
If the Mandrill API fails or returns an error response, the send call will
|
.. END quickstart
|
||||||
raise a ``djrill.MandrillAPIError`` exception (a subclass of
|
|
||||||
requests.HTTPError).
|
|
||||||
|
|
||||||
|
|
||||||
Django EmailMessage Support
|
See the `full documentation <https://djrill.readthedocs.org/en/latest/>`_
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
for more features and options.
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,7 @@ from django.utils.text import capfirst
|
|||||||
|
|
||||||
from djrill.exceptions import MandrillAPIError, NotSupportedByMandrillError
|
from djrill.exceptions import MandrillAPIError, NotSupportedByMandrillError
|
||||||
|
|
||||||
VERSION = (0, 3, 1)
|
from ._version import *
|
||||||
__version__ = '.'.join([str(x) for x in VERSION])
|
|
||||||
|
|
||||||
# This backend was developed against this API endpoint.
|
# This backend was developed against this API endpoint.
|
||||||
# You can override in settings.py, if desired.
|
# You can override in settings.py, if desired.
|
||||||
|
|||||||
3
djrill/_version.py
Normal file
3
djrill/_version.py
Normal 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
153
docs/Makefile
Normal 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
282
docs/conf.py
Normal 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
54
docs/contributing.rst
Normal 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
25
docs/history.rst
Normal 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
45
docs/index.rst
Normal 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
61
docs/installation.rst
Normal 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
190
docs/make.bat
Normal 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
9
docs/quickstart.rst
Normal 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
|
||||||
32
docs/usage/multiple_backends.rst
Normal file
32
docs/usage/multiple_backends.rst
Normal 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
225
docs/usage/sending_mail.rst
Normal 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
70
docs/usage/templates.rst
Normal 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()
|
||||||
|
|
||||||
29
setup.py
29
setup.py
@@ -1,14 +1,31 @@
|
|||||||
from setuptools import setup
|
from setuptools import setup
|
||||||
|
import re
|
||||||
|
|
||||||
with open('LICENSE') as file:
|
# define __version__ and __minor_version__ from djrill/_version.py,
|
||||||
license_text = file.read()
|
# but without importing from djrill (which would break setup)
|
||||||
with open('README.rst') as file:
|
with open("djrill/_version.py") as f:
|
||||||
long_description = file.read()
|
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(
|
setup(
|
||||||
name="djrill",
|
name="djrill",
|
||||||
version="0.3.1",
|
version=__version__,
|
||||||
description='Django email backend for Mandrill.',
|
description='Mandrill transactional email for Django',
|
||||||
keywords="django, mailchimp, mandrill, email, email backend",
|
keywords="django, mailchimp, mandrill, email, email backend",
|
||||||
author="Kenneth Love <kenneth@brack3t.com>, Chris Jones <chris@brack3t.com>",
|
author="Kenneth Love <kenneth@brack3t.com>, Chris Jones <chris@brack3t.com>",
|
||||||
author_email="kenneth@brack3t.com",
|
author_email="kenneth@brack3t.com",
|
||||||
|
|||||||
Reference in New Issue
Block a user