Skip to content

Commit

Permalink
Merge 9c9ba1f into 8b917e9
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael Howitz committed Apr 3, 2019
2 parents 8b917e9 + 9c9ba1f commit f14095e
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 4 deletions.
3 changes: 2 additions & 1 deletion CHANGES.rst
Expand Up @@ -4,7 +4,8 @@ Changelog
4.4 (unreleased)
----------------

- Nothing changed yet.
- Add ability to disable sending of queued mails. Details see README.rst.
(`#14 <https://github.com/zopefoundation/Products.MailHost/issues/14>`_)


4.3 (2019-03-08)
Expand Down
12 changes: 11 additions & 1 deletion README.rst
Expand Up @@ -8,10 +8,13 @@ An optional character set can be specified to automatically encode unicode
input, and perform appropriate RFC 2822 header and body encoding for the
specified character set. Full python email.Message.Message objects may be sent.

Email can optionally be encoded using Base64 or Quoted-Printable encoding
Email can optionally be encoded using Base64 or Quoted-Printable encoding
(though automatic body encoding will be applied if a character set is
specified).

Usage
-----

MailHost provides integration with the Zope transaction system and optional
support for asynchronous mail delivery. Asynchronous mail delivery is
implemented using a queue and a dedicated thread processing the queue. The
Expand All @@ -21,3 +24,10 @@ manage_restartQueueThread?action=start method through HTTP. There is currently
no possibility to start the thread at Zope startup time.

Supports TLS/SSL encryption (requires Python compiled with SSL support).

Configuration
-------------

To force MailHost to only queue mails without sending them, activate queuing
in the ZMI and set the environment variable ``MAILHOST_QUEUE_ONLY=1``.
This could be helpful in a staging environment where mails should not be sent.
1 change: 1 addition & 0 deletions buildout.cfg
Expand Up @@ -10,6 +10,7 @@ parts =

[versions]
Products.MailHost =
zope.sendmail =

[interpreter]
recipe = zc.recipe.egg
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Expand Up @@ -62,7 +62,7 @@ def _read(fname):
'Zope >= 4.0b4',
'zope.deferredimport',
'zope.interface',
'zope.sendmail',
'zope.sendmail >= 5',
],
extras_require={
'genericsetup': ['Products.GenericSetup >= 2.0b1'],
Expand Down
4 changes: 3 additions & 1 deletion src/Products/MailHost/MailHost.py
Expand Up @@ -22,6 +22,7 @@
from email.utils import getaddresses
from email.utils import parseaddr
import logging
import os
from os.path import realpath
import re
import six
Expand Down Expand Up @@ -318,7 +319,8 @@ def _send(self, mfrom, mto, messageText, immediate=False):
else:
if self.smtp_queue:
# Start queue processor thread, if necessary
self._startQueueProcessorThread()
if not os.environ.get('MAILHOST_QUEUE_ONLY', False):
self._startQueueProcessorThread()
delivery = QueuedMailDelivery(self.smtp_queue_directory)
else:
delivery = DirectMailDelivery(self._makeMailer())
Expand Down
64 changes: 64 additions & 0 deletions src/Products/MailHost/tests/testMailHost.py
Expand Up @@ -14,8 +14,13 @@
"""

from email import message_from_string
import os.path
import shutil
import six
import tempfile
import transaction
import unittest
import zope.sendmail.maildir

from Products.MailHost.MailHost import MailHost
from Products.MailHost.MailHost import MailHostError, _mungeHeaders
Expand Down Expand Up @@ -636,3 +641,62 @@ def testSendMultiPartMixedMessage(self):
# (TypeError: expected string or buffer)
mailhost.send(msg, charset='utf-8')
self.assertEqual(mailhost.sent, msg)


class QueueingDummyMailHost(MailHost):
"""Dummy mail host implementation which supports queueing."""

meta_type = 'Queueing Dummy Mail Host'

def __init__(self, id, smtp_queue_directory):
self.id = id
self.smtp_queue = True
self.smtp_queue_directory = smtp_queue_directory
self.started_queue_processor_thread = False

def _startQueueProcessorThread(self):
self.started_queue_processor_thread = True


class TestMailHostQueuing(unittest.TestCase):

smtp_queue_directory = None

def _getTargetClass(self):
return QueueingDummyMailHost

def _makeOne(self, *args):
self.tmpdir = tempfile.mkdtemp(suffix='MailHostTests')
self.smtp_queue_directory = os.path.join(self.tmpdir, 'queue')
return self._getTargetClass()(
*args, smtp_queue_directory=self.smtp_queue_directory)

def _callFUT(self):
mh = self._makeOne('MailHost')
mh.send(
'Nice to see you!',
mto='user@example.com',
mfrom='zope@example.com',
subject='Hello world')
transaction.commit()
return mh

def tearDown(self):
super(TestMailHostQueuing, self).tearDown()
shutil.rmtree(self.tmpdir, ignore_errors=True)

def testStartQueueProcessorThread(self):
mh = self._callFUT()
self.assertTrue(mh.started_queue_processor_thread)
md = zope.sendmail.maildir.Maildir(self.smtp_queue_directory)
self.assertEqual(len(list(md)), 1)

def testNotStartQueueProcessorThread(self):
os.environ['MAILHOST_QUEUE_ONLY'] = '1'
try:
mh = self._callFUT()
finally:
del os.environ['MAILHOST_QUEUE_ONLY']
self.assertFalse(mh.started_queue_processor_thread)
md = zope.sendmail.maildir.Maildir(self.smtp_queue_directory)
self.assertEqual(len(list(md)), 1)

0 comments on commit f14095e

Please sign in to comment.