forked from Pylons/pyramid_mailer
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
-
pyramid_mailer.includeme
function added for
``config.include('pyramid_mailer')`` support - ``pyramid_mailer.testing`` module added for ``config.include('pyramid_mailer.testing')`` support. - ``pyramid_mailer.get_mailer`` API added (see docs). - ``pyramid_mailer.interfaces`` module readded (with marker IMailer interface for ZCA registration). - ``setup.cfg`` added with coverage parameters to allow for ``setup.py nosetests --with-coverage``.
- Loading branch information
Showing
8 changed files
with
264 additions
and
68 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,7 +12,7 @@ syntax: glob | |
*.orig | ||
*.cfg | ||
*.tox | ||
|
||
env26/ | ||
|
||
*~ | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
Next release | ||
------------ | ||
|
||
- ``pyramid_mailer.includeme`` function added for | ||
``config.include('pyramid_mailer')`` support | ||
|
||
- ``pyramid_mailer.testing`` module added for | ||
``config.include('pyramid_mailer.testing')`` support. | ||
|
||
- ``pyramid_mailer.get_mailer`` API added (see docs). | ||
|
||
- ``pyramid_mailer.interfaces`` module readded (with marker IMailer interface | ||
for ZCA registration). | ||
|
||
- ``setup.cfg`` added with coverage parameters to allow for ``setup.py | ||
nosetests --with-coverage``. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,66 +1,70 @@ | ||
pyramid_mailer | ||
================== | ||
|
||
**pyramid_mailer** is a package for the Pyramid framework to take the pain out of sending emails. It has the following features: | ||
**pyramid_mailer** is a package for the Pyramid framework to take the pain | ||
out of sending emails. It has the following features: | ||
|
||
1. A wrapper around the low-level email functionality of standard Python. This includes handling multipart emails with both text and | ||
HTML content, and file attachments. | ||
1. A wrapper around the low-level email functionality of standard | ||
Python. This includes handling multipart emails with both text and HTML | ||
content, and file attachments. | ||
|
||
2. The option of directly sending an email or adding it to the queue in your maildir. | ||
2. The option of directly sending an email or adding it to the queue in your | ||
maildir. | ||
|
||
3. Wrapping email sending in the transaction manager. If you have a view that sends a customer an email for example, and there is an | ||
error in that view (for example, a database error) then this ensures that the email is not sent. | ||
3. Wrapping email sending in the transaction manager. If you have a view that | ||
sends a customer an email for example, and there is an error in that view | ||
(for example, a database error) then this ensures that the email is not | ||
sent. | ||
|
||
4. A ``DummyMailer`` class to help with writing unit tests, or other situations where you want to avoid emails being sent accidentally | ||
from a non-production install. | ||
4. A ``DummyMailer`` class to help with writing unit tests, or other | ||
situations where you want to avoid emails being sent accidentally from a | ||
non-production install. | ||
|
||
**pyramid_mailer** uses the `repoze_sendmail`_ package for general email sending, queuing and transaction management, and the `Lamson`_ | ||
library for low-level multipart message encoding and wrapping. You do not have to install or run a Lamson mail service. | ||
**pyramid_mailer** uses the `repoze_sendmail`_ package for general email | ||
sending, queuing and transaction management, and the `Lamson`_ library for | ||
low-level multipart message encoding and wrapping. You do not have to install | ||
or run a Lamson mail service. | ||
|
||
Installation | ||
------------ | ||
|
||
Install using **pip install pyramid_mailer** or **easy_install pyramid_mailer**. | ||
Install using **pip install pyramid_mailer** or **easy_install | ||
pyramid_mailer**. | ||
|
||
If installing from source, untar/unzip, cd into the directory and do **python setup.py install**. | ||
If installing from source, untar/unzip, cd into the directory and do **python | ||
setup.py install**. | ||
|
||
The source repository is on `Bitbucket`_. Please report any bugs, issues or queries there. | ||
The source repository is on `Bitbucket`_. Please report any bugs, issues or | ||
queries there. | ||
|
||
Installing on Windows | ||
--------------------- | ||
|
||
Some Windows users have reported issues installing `Lamson`_ due to some dependencies that do not work on Windows. | ||
Some Windows users have reported issues installing `Lamson`_ due to some | ||
dependencies that do not work on Windows. | ||
|
||
The best way to install on Windows is to install the individual packages using the `no dependencies` option:: | ||
The best way to install on Windows is to install the individual packages | ||
using the `no dependencies` option:: | ||
|
||
easy_install -N lamson chardet repoze.sendmail pyramid_mailer | ||
|
||
|
||
Getting started | ||
--------------- | ||
Getting Started (The Easier Way) | ||
-------------------------------- | ||
|
||
To get started create an instance of :class:`pyramid_mailer.mailer.Mailer`:: | ||
In your application's configuration stanza (where you create a Pyramid | ||
"Configurator"), use the ``config.include`` method:: | ||
|
||
from pyramid_mailer.mailer import Mailer | ||
|
||
mailer = Mailer() | ||
config.include('pyramid_mailer') | ||
|
||
The ``Mailer`` class can take a number of optional settings, detailed in :ref:`configuration`. It's a good idea to create a single ``Mailer`` instance for your application, and add it to your registry in your configuration setup:: | ||
Thereafter in view code, use the ``pyramid_mailer.get_mailer`` API to obtain | ||
the configured mailer:: | ||
|
||
config = Configurator(settings=settings) | ||
config.registry['mailer'] = Mailer.from_settings(settings) | ||
from pyramid_mailer import get_mailer | ||
mailer = get_mailer(request) | ||
|
||
or alternatively:: | ||
|
||
from pyramid_mailer import mailer_factory_from_settings | ||
config.registry['mailer'] = mailer_factory_from_settings(settings) | ||
|
||
You can then access your mailer in a view:: | ||
|
||
def my_view(request): | ||
mailer = request.registry['mailer'] | ||
|
||
To send a message, you must first create a :class:`pyramid_mailer.message.Message` instance:: | ||
To send a message, you must first create a | ||
:class:`pyramid_mailer.message.Message` instance:: | ||
|
||
from pyramid_mailer.message import Message | ||
|
||
|
@@ -69,30 +73,78 @@ To send a message, you must first create a :class:`pyramid_mailer.message.Messag | |
recipients=["[email protected]"], | ||
body="hello, arthur") | ||
|
||
The ``Message`` is then passed to the ``Mailer`` instance. You can either send the message right away:: | ||
The ``Message`` is then passed to the ``Mailer`` instance. You can either | ||
send the message right away:: | ||
|
||
mailer.send(message) | ||
|
||
or add it to your mail queue (a maildir on disk):: | ||
|
||
mailer.send_to_queue(message) | ||
|
||
|
||
Usually you provide the ``sender`` to your ``Message`` instance. Often however a site might just use a single from address. If that is the case you can provide the ``default_sender`` to your ``Mailer`` and this will be used in throughout your application as the default if the ``sender`` is not otherwise provided. | ||
Usually you provide the ``sender`` to your ``Message`` instance. Often | ||
however a site might just use a single from address. If that is the case you | ||
can provide the ``default_sender`` to your ``Mailer`` and this will be used | ||
in throughout your application as the default if the ``sender`` is not | ||
otherwise provided. | ||
|
||
|
||
If you don't want to use transactions, you can side-step them by using **send_immediately**:: | ||
If you don't want to use transactions, you can side-step them by using | ||
**send_immediately**:: | ||
|
||
mailer.send_immediately(message, fail_silently=False) | ||
|
||
This will send the email immediately, outwith the transaction, so if it fails you have to deal with it manually. The ``fail_silently`` flag will swallow any connection errors silently - if it's not important whether the email gets sent. | ||
This will send the email immediately, outwith the transaction, so if it fails | ||
you have to deal with it manually. The ``fail_silently`` flag will swallow | ||
any connection errors silently - if it's not important whether the email gets | ||
sent. | ||
|
||
Getting Started (The Harder Way) | ||
-------------------------------- | ||
|
||
To get started the harder way (without using ``config.include``), create an | ||
instance of :class:`pyramid_mailer.mailer.Mailer`:: | ||
|
||
from pyramid_mailer.mailer import Mailer | ||
|
||
mailer = Mailer() | ||
|
||
The ``Mailer`` class can take a number of optional settings, detailed in | ||
:ref:`configuration`. It's a good idea to create a single ``Mailer`` instance | ||
for your application, and add it to your registry in your configuration | ||
setup:: | ||
|
||
config = Configurator(settings=settings) | ||
config.registry['mailer'] = Mailer.from_settings(settings) | ||
|
||
or alternatively:: | ||
|
||
from pyramid_mailer import mailer_factory_from_settings | ||
config.registry['mailer'] = mailer_factory_from_settings(settings) | ||
|
||
You can then access your mailer in a view:: | ||
|
||
def my_view(request): | ||
mailer = request.registry['mailer'] | ||
|
||
Note that the ``pyramid_mailer.get_mailer()`` API will not work if you | ||
construct and seat your own mailer in this way. | ||
|
||
.. _configuration: | ||
|
||
Configuration | ||
------------- | ||
|
||
If you create your ``Mailer`` instance using :meth:`pyramid_mailer.mailer.Mailer.from_settings`, you can pass the settings from your .ini file or other source. By default, the prefix is assumed to be `mail.` although you can use another prefix if you wish. | ||
If you create your ``Mailer`` instance using | ||
:meth:`pyramid_mailer.mailer.Mailer.from_settings` or | ||
``config.include('pyramid_mailer')``, you can pass the settings from your | ||
.ini file or other source. By default, the prefix is assumed to be `mail.`. | ||
If you use the ``config.include`` mechanism, to set another prefix, use the | ||
``pyramid_mailer.prefix`` key in the config file, | ||
e.g. ``pyramid_mailer.prefix = foo.``. If you use the | ||
:meth:`pyramid_mailer.Mailer.Mailer.from_settings` or | ||
:func:`pyramid_mailer.mailer_factory_from_settings` API, these accept a | ||
prefix directly. | ||
|
||
========================= =============== ===================== | ||
Setting Default Description | ||
|
@@ -110,12 +162,18 @@ Setting Default Description | |
**mail.debug** **False** SMTP debug level | ||
========================= =============== ===================== | ||
|
||
**Note:** SSL will only work with **pyramid_mailer** if you are using Python **2.6** or higher, as it uses the SSL additions to the ``smtplib`` package. While it may be possible to work around this if you have to use Python 2.5 or lower, **pyramid_mailer** does not support this out of the box. | ||
**Note:** SSL will only work with **pyramid_mailer** if you are using Python | ||
**2.6** or higher, as it uses the SSL additions to the ``smtplib`` | ||
package. While it may be possible to work around this if you have to use | ||
Python 2.5 or lower, **pyramid_mailer** does not support this out of the | ||
box. | ||
|
||
Transactions | ||
------------ | ||
|
||
If you are using transaction management with your Pyramid application then **pyramid_mailer** will only send the emails (or add them to the mail queue) when the transactions are committed. | ||
If you are using transaction management with your Pyramid application then | ||
**pyramid_mailer** will only send the emails (or add them to the mail queue) | ||
when the transactions are committed. | ||
|
||
For example:: | ||
|
||
|
@@ -147,7 +205,8 @@ committed, and mail will be sent. | |
Attachments | ||
----------- | ||
|
||
Attachments are added using the :class:`pyramid_mailer.message.Attachment` class:: | ||
Attachments are added using the :class:`pyramid_mailer.message.Attachment` | ||
class:: | ||
|
||
from pyramid_mailer.message import Attachment | ||
from pyramid_mailer.message import Message | ||
|
@@ -159,7 +218,8 @@ Attachments are added using the :class:`pyramid_mailer.message.Attachment` class | |
|
||
message.attach(attachment) | ||
|
||
You can pass the data either as a string or file object, so the above code could be rewritten:: | ||
You can pass the data either as a string or file object, so the above code | ||
could be rewritten:: | ||
|
||
from pyramid_mailer.message import Attachment | ||
from pyramid_mailer.message import Message | ||
|
@@ -176,28 +236,38 @@ You can pass the data either as a string or file object, so the above code could | |
Unit tests | ||
---------- | ||
|
||
When running unit tests you probably don't want to actually send any emails inadvertently. However it's still useful to keep track of what emails would be sent in your tests. | ||
When running unit tests you probably don't want to actually send any emails | ||
inadvertently. However it's still useful to keep track of what emails would | ||
be sent in your tests. | ||
|
||
Another case is if your site is in development and you want to avoid accidental sending of any emails to customers. | ||
Another case is if your site is in development and you want to avoid | ||
accidental sending of any emails to customers. | ||
|
||
In either case, the :class:`pyramid_mailer.mailer.DummyMailer` can be used:: | ||
In either case, ``config.include('pyramid_mailer.testing')`` can be used to | ||
make the current mailer an instance of the | ||
:class:`pyramid_mailer.mailer.DummyMailer`:: | ||
|
||
from pyramid import testing | ||
|
||
class TestViews(unittest.TestCase): | ||
def setUp(self): | ||
self.config = testing.setUp() | ||
self.config.include('pyramid_mailer.testing') | ||
|
||
def tearDown(self): | ||
testing.tearDown() | ||
|
||
def test_some_view(self): | ||
from pyramid.config import Configurator | ||
from pyramid.testing import DummyRequest | ||
from pyramid_mailer.mailer import DummyMailer | ||
|
||
config = Configurator() | ||
mailer = DummyMailer() | ||
config.registry['mailer'] = mailer | ||
|
||
request = DummyRequest() | ||
mailer = get_mailer(request) | ||
response = some_view(request) | ||
|
||
The ``DummyMailer`` instance keeps track of emails "sent" in two properties: `queue` for emails send via :meth:`pyramid_mailer.mailer.Mailer.send_to_queue` and `outbox` for emails sent via :meth:`pyramid_mailer.mailer.Mailer.send`. Each stores the individual ``Message`` instances:: | ||
The ``DummyMailer`` instance keeps track of emails "sent" in two properties: | ||
`queue` for emails send via | ||
:meth:`pyramid_mailer.mailer.Mailer.send_to_queue` and `outbox` for emails | ||
sent via :meth:`pyramid_mailer.mailer.Mailer.send`. Each stores the | ||
individual ``Message`` instances:: | ||
|
||
self.assertEqual(len(mailer.outbox) == 1) | ||
self.assertEqual(mailer.outbox[0].subject == "hello world") | ||
|
@@ -210,12 +280,13 @@ Queue | |
|
||
When you send mail to a queue via | ||
:meth:`pyramid_mailer.Mailer.send_to_queue`, the mail will be placed into a | ||
``maildir`` directory specified by the ``queue_path`` parameter or setting to :class:`pyramid_mailer.mailer.Mailer`. A | ||
separate process will need to be launched to monitor this maildir and take | ||
actions based on its state. Such a program comes as part of | ||
`repoze_sendmail`_ (a dependency of the ``pyramid_mailer`` package). It is | ||
known as ``qp``. ``qp`` will be installed into your Python (or virtualenv) | ||
``bin`` or ``Scripts`` directory when you install ``repoze_sendmail``. | ||
``maildir`` directory specified by the ``queue_path`` parameter or setting to | ||
:class:`pyramid_mailer.mailer.Mailer`. A separate process will need to be | ||
launched to monitor this maildir and take actions based on its state. Such a | ||
program comes as part of `repoze_sendmail`_ (a dependency of the | ||
``pyramid_mailer`` package). It is known as ``qp``. ``qp`` will be | ||
installed into your Python (or virtualenv) ``bin`` or ``Scripts`` directory | ||
when you install ``repoze_sendmail``. | ||
|
||
You'll need to arrange for ``qp`` to be a long-running process that monitors | ||
the maildir state.:: | ||
|
@@ -235,6 +306,8 @@ API | |
|
||
.. autofunction:: mailer_factory_from_settings | ||
|
||
.. autofunction:: get_mailer | ||
|
||
.. module:: pyramid_mailer.mailer | ||
|
||
.. autoclass:: Mailer | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
from zope.interface import Interface | ||
|
||
class IMailer(Interface): | ||
pass | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.