diff --git a/README.rst b/README.rst index ea2bdbe..ed6d66b 100644 --- a/README.rst +++ b/README.rst @@ -1,327 +1,23 @@ -Djrill, for Mandrill -==================== +Djrill: Mandrill for Django +=========================== + +Djrill integrates the `Mandrill `_ transactional +email service into Django. + +In general, Djrill "just works" with Django's built-in +`django.core.mail `_ +functions. It supports: + +* HTML email, attachments, extra headers, and other basic email functionality +* Mandrill-specific extensions like tags, metadata, tracking, and MailChimp templates +* An optional Django admin interface .. 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 -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: - -* Check the status of your Mandrill API connection. -* See stats on email senders, tags and urls. - -Djrill is made available under the BSD license. - -Installation ------------- - -Install from PyPI:: - - pip install djrill - -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``.) - - -Configuration -------------- - -In ``settings.py``: - -1. Add ``djrill`` to your ``INSTALLED_APPS``: - -.. code:: python - - INSTALLED_APPS = ( - ... - "djrill" - ) - -2. Add the following line, substituting your own ``MANDRILL_API_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" - -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 - - ... - from django.contrib import admin - - from djrill import DjrillAdminSite - - admin.site = DjrillAdminSite() - admin.autodiscover() - ... - - urlpatterns = patterns('', - ... - url(r'^admin/', include(admin.site.urls)), - ) - -Usage ------ - -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.) - -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 ", - to=["Djrill Receiver ", "another.person@example.com"], - headers={'Reply-To': "Service "} # optional extra headers - ) - msg.attach_alternative("

This is the HTML version of your email

", "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 "). -* **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': "track it" } - 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 +Djrill is tested with Django 1.3 and later (including Python 3 support with Django 1.5). +It is made available under the BSD license. +* Documentation: https://readthedocs.org/docs/djrill/en/latest/ +* Package on PyPI: https://pypi.python.org/pypi/djrill +* Latest source: https://github.com/brack3t/Djrill diff --git a/docs/conf.py b/docs/conf.py index 49222ff..fe3bb3c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -23,11 +23,11 @@ execfile('../djrill/_version.py') # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' +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 = [] +extensions = ['sphinx.ext.intersphinx'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -43,6 +43,7 @@ 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 @@ -69,7 +70,7 @@ release = __version__ exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all documents. -#default_role = None +default_role = "py:obj" # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True @@ -242,3 +243,36 @@ texinfo_documents = [ # 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", + ) diff --git a/docs/contributing.rst b/docs/contributing.rst new file mode 100644 index 0000000..218778e --- /dev/null +++ b/docs/contributing.rst @@ -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 `_. + + +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 `_ 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 `_ (``pip install mock``). + +To run the tests, either:: + + python -Wall setup.py test + +or:: + + python -Wall runtests.py + diff --git a/docs/history.rst b/docs/history.rst new file mode 100644 index 0000000..4bc6876 --- /dev/null +++ b/docs/history.rst @@ -0,0 +1,25 @@ +Release Notes +============= + +Version 0.3.0: + +* :ref:`Attachments ` are now supported +* :ref:`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``.) + diff --git a/docs/index.rst b/docs/index.rst index 1f3bdd0..896d4e6 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -3,20 +3,105 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -Welcome to Djrill's documentation! -================================== +Djrill: Mandrill for Django +=========================== -Contents: +Release |release| + +Djrill integrates the `Mandrill `_ transactional +email service into Django. + +In general, Djrill "just works" with Django's built-in +`django.core.mail `_ +functions. It supports: + +* HTML email, attachments, extra headers, and other basic email functionality +* Mandrill-specific extensions like tags, metadata, tracking, and MailChimp templates +* An optional Django admin interface + +Djrill is tested with Django 1.3 and later (including Python 3 support with Django 1.5). +It is made available under the BSD license. + + +.. _quickstart: + +Quick Start +----------- + +1. Install from PyPI: + + .. code-block:: console + + $ pip install djrill + + +2. Edit your project's :file:`settings.py`: + + .. code-block:: python + + INSTALLED_APPS = ( + ... + "djrill" + ) + + MANDRILL_API_KEY = "" + EMAIL_BACKEND = "djrill.mail.backends.djrill.DjrillBackend" + + +3. Now the regular `Django email functions `_ + will send through Mandrill:: + + from django.core.mail import send_mail + + send_mail("It works!", "This will get sent through Mandrill", + "Djrill Sender ", ["to@example.com"]) + + + You could send an HTML message, complete with custom Mandrill tags and metadata:: + + from django.core.mail import EmailMultiAlternatives + + msg = EmailMultiAlternatives( + subject="Djrill Message", + body="This is the text email body", + from_email="Djrill Sender ", + to=["Recipient One ", "another.person@example.com"], + headers={'Reply-To': "Service "} # optional extra headers + ) + msg.attach_alternative("

This is the HTML email body

", "text/html") + + # Optional Mandrill-specific extensions: + msg.tags = ["one tag", "two tag", "red tag", "blue tag"] + msg.metadata = {'user_id': "8675309"} + + # Send it: + msg.send() + + (Be sure to use a ``from_email`` that's in one of your Mandrill approved sending + domains, or the message won't get sent.) + + +Documentation +------------- .. toctree:: :maxdepth: 2 + installation + usage/sending_mail + usage/templates + usage/multiple_backends + contributing + history -Indices and tables -================== +Thanks +------ -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` +Thanks to the MailChimp team for asking us to build this nifty little app, and to all of Djrill's +:doc:`contributors `. 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 diff --git a/docs/installation.rst b/docs/installation.rst new file mode 100644 index 0000000..d9af9ac --- /dev/null +++ b/docs/installation.rst @@ -0,0 +1,61 @@ +Installation +============ + +It's easiest to install Djrill from `PyPI `_: + + .. 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 `_ +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)), + ) diff --git a/docs/usage/multiple_backends.rst b/docs/usage/multiple_backends.rst new file mode 100644 index 0000000..025d950 --- /dev/null +++ b/docs/usage/multiple_backends.rst @@ -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 ` +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`. diff --git a/docs/usage/sending_mail.rst b/docs/usage/sending_mail.rst new file mode 100644 index 0000000..b8e5bca --- /dev/null +++ b/docs/usage/sending_mail.rst @@ -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 `. + + +.. _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 "). + +**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 body", "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 `_ +`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. diff --git a/docs/usage/templates.rst b/docs/usage/templates.rst new file mode 100644 index 0000000..368f0e8 --- /dev/null +++ b/docs/usage/templates.rst @@ -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': "track it" + } + 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 `_, +and will ignore any `body` text set on the `EmailMessage`. + +All of Djrill's other :ref:`Mandrill-specific options ` +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() +