Index: /vendor/Products.MailHost/2.13.1/CHANGES.txt
===================================================================
--- /vendor/Products.MailHost/2.13.1/CHANGES.txt	(revision 3357)
+++ /vendor/Products.MailHost/2.13.1/CHANGES.txt	(revision 3357)
@@ -0,0 +1,12 @@
+Changelog
+=========
+
+2.13.1 (2010-09-25)
+-------------------
+
+- LP #642728: Fixed TypeError on nested multi part messages in MailHost.
+
+2.13.0 (2010-07-13)
+-------------------
+
+- Released as separate package.
Index: /vendor/Products.MailHost/2.13.1/COPYRIGHT.txt
===================================================================
--- /vendor/Products.MailHost/2.13.1/COPYRIGHT.txt	(revision 3357)
+++ /vendor/Products.MailHost/2.13.1/COPYRIGHT.txt	(revision 3357)
@@ -0,0 +1,1 @@
+Zope Foundation and Contributors
Index: /vendor/Products.MailHost/2.13.1/LICENSE.txt
===================================================================
--- /vendor/Products.MailHost/2.13.1/LICENSE.txt	(revision 3357)
+++ /vendor/Products.MailHost/2.13.1/LICENSE.txt	(revision 3357)
@@ -0,0 +1,44 @@
+Zope Public License (ZPL) Version 2.1
+
+A copyright notice accompanies this license document that identifies the
+copyright holders.
+
+This license has been certified as open source. It has also been designated as
+GPL compatible by the Free Software Foundation (FSF).
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions in source code must retain the accompanying copyright
+notice, this list of conditions, and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the accompanying copyright
+notice, this list of conditions, and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+3. Names of the copyright holders must not be used to endorse or promote
+products derived from this software without prior written permission from the
+copyright holders.
+
+4. The right to distribute this software or to use it for any purpose does not
+give you the right to use Servicemarks (sm) or Trademarks (tm) of the
+copyright
+holders. Use of them is covered by separate agreement with the copyright
+holders.
+
+5. If any files are modified, you must cause the modified files to carry
+prominent notices stating that you changed the files and the date of any
+change.
+
+Disclaimer
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED
+OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Index: /vendor/Products.MailHost/2.13.1/README.txt
===================================================================
--- /vendor/Products.MailHost/2.13.1/README.txt	(revision 3357)
+++ /vendor/Products.MailHost/2.13.1/README.txt	(revision 3357)
@@ -0,0 +1,23 @@
+Overview
+========
+
+The MailHost product provides support for sending email from within the Zope
+environment using MailHost objects.
+
+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, Quoted-Printable or UUEncode
+encoding (though automatic body encoding will be applied if a character set is
+specified).
+
+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
+thread is (re)-started automatically when sending an email. The thread can be
+started manually (in case of restart) by calling its
+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).
Index: /vendor/Products.MailHost/2.13.1/bootstrap.py
===================================================================
--- /vendor/Products.MailHost/2.13.1/bootstrap.py	(revision 3357)
+++ /vendor/Products.MailHost/2.13.1/bootstrap.py	(revision 3357)
@@ -0,0 +1,121 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Bootstrap a buildout-based project
+
+Simply run this script in a directory containing a buildout.cfg.
+The script accepts buildout command-line options, so you can
+use the -c option to specify an alternate configuration file.
+
+$Id: bootstrap.py 108946 2010-02-12 02:40:18Z yusei $
+"""
+
+import os, shutil, sys, tempfile, urllib2
+from optparse import OptionParser
+
+tmpeggs = tempfile.mkdtemp()
+
+is_jython = sys.platform.startswith('java')
+
+# parsing arguments
+parser = OptionParser()
+parser.add_option("-v", "--version", dest="version",
+                          help="use a specific zc.buildout version")
+parser.add_option("-d", "--distribute",
+                   action="store_true", dest="distribute", default=False,
+                   help="Use Distribute rather than Setuptools.")
+
+parser.add_option("-c", None, action="store", dest="config_file",
+                   help=("Specify the path to the buildout configuration "
+                         "file to be used."))
+
+options, args = parser.parse_args()
+
+# if -c was provided, we push it back into args for buildout' main function
+if options.config_file is not None:
+    args += ['-c', options.config_file]
+
+if options.version is not None:
+    VERSION = '==%s' % options.version
+else:
+    VERSION = ''
+
+USE_DISTRIBUTE = options.distribute
+args = args + ['bootstrap']
+
+to_reload = False
+try:
+    import pkg_resources
+    if not hasattr(pkg_resources, '_distribute'):
+        to_reload = True
+        raise ImportError
+except ImportError:
+    ez = {}
+    if USE_DISTRIBUTE:
+        exec urllib2.urlopen('http://python-distribute.org/distribute_setup.py'
+                         ).read() in ez
+        ez['use_setuptools'](to_dir=tmpeggs, download_delay=0, no_fake=True)
+    else:
+        exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
+                             ).read() in ez
+        ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
+
+    if to_reload:
+        reload(pkg_resources)
+    else:
+        import pkg_resources
+
+if sys.platform == 'win32':
+    def quote(c):
+        if ' ' in c:
+            return '"%s"' % c # work around spawn lamosity on windows
+        else:
+            return c
+else:
+    def quote (c):
+        return c
+
+cmd = 'from setuptools.command.easy_install import main; main()'
+ws  = pkg_resources.working_set
+
+if USE_DISTRIBUTE:
+    requirement = 'distribute'
+else:
+    requirement = 'setuptools'
+
+if is_jython:
+    import subprocess
+
+    assert subprocess.Popen([sys.executable] + ['-c', quote(cmd), '-mqNxd',
+           quote(tmpeggs), 'zc.buildout' + VERSION],
+           env=dict(os.environ,
+               PYTHONPATH=
+               ws.find(pkg_resources.Requirement.parse(requirement)).location
+               ),
+           ).wait() == 0
+
+else:
+    assert os.spawnle(
+        os.P_WAIT, sys.executable, quote (sys.executable),
+        '-c', quote (cmd), '-mqNxd', quote (tmpeggs), 'zc.buildout' + VERSION,
+        dict(os.environ,
+            PYTHONPATH=
+            ws.find(pkg_resources.Requirement.parse(requirement)).location
+            ),
+        ) == 0
+
+ws.add_entry(tmpeggs)
+ws.require('zc.buildout' + VERSION)
+import zc.buildout.buildout
+zc.buildout.buildout.main(args)
+shutil.rmtree(tmpeggs)
Index: /vendor/Products.MailHost/2.13.1/buildout.cfg
===================================================================
--- /vendor/Products.MailHost/2.13.1/buildout.cfg	(revision 3357)
+++ /vendor/Products.MailHost/2.13.1/buildout.cfg	(revision 3357)
@@ -0,0 +1,12 @@
+[buildout]
+develop = .
+parts = interpreter test
+
+[interpreter]
+recipe = zc.recipe.egg
+interpreter = python
+eggs = Products.MailHost
+
+[test]
+recipe = zc.recipe.testrunner
+eggs = Products.MailHost
Index: /vendor/Products.MailHost/2.13.1/setup.py
===================================================================
--- /vendor/Products.MailHost/2.13.1/setup.py	(revision 3357)
+++ /vendor/Products.MailHost/2.13.1/setup.py	(revision 3357)
@@ -0,0 +1,35 @@
+##############################################################################
+#
+# Copyright (c) 2010 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+from setuptools import setup, find_packages
+
+setup(name='Products.MailHost',
+      version = '2.13.1',
+      url='http://pypi.python.org/pypi/Products.MailHost',
+      license='ZPL 2.1',
+      description="zope.sendmail integration for Zope 2.",
+      author='Zope Foundation and Contributors',
+      author_email='zope-dev@zope.org',
+      long_description=open('README.txt').read() + '\n' +
+                       open('CHANGES.txt').read(),
+      packages=find_packages('src'),
+      namespace_packages=['Products'],
+      package_dir={'': 'src'},
+      install_requires=[
+        'setuptools',
+        'Zope2 >= 2.13.0a1',
+      ],
+      include_package_data=True,
+      zip_safe=False,
+      )
Index: /vendor/Products.MailHost/2.13.1/src/Products/MailHost/MailHost.py
===================================================================
--- /vendor/Products.MailHost/2.13.1/src/Products/MailHost/MailHost.py	(revision 3357)
+++ /vendor/Products.MailHost/2.13.1/src/Products/MailHost/MailHost.py	(revision 3357)
@@ -0,0 +1,530 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Foundation and Contributors.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""SMTP mail objects
+"""
+import logging
+from os.path import realpath
+import re
+from cStringIO import StringIO
+from copy import deepcopy
+from email.Header import Header
+from email.Charset import Charset
+from email import message_from_string
+from email.Message import Message
+from email import Encoders
+try:
+    import email.utils as emailutils
+except ImportError:
+    import email.Utils as emailutils
+import email.Charset
+# We import from a private module here because the email module
+# doesn't provide a good public address list parser
+import uu
+
+from threading import Lock
+import time
+
+from AccessControl.class_init import InitializeClass
+from AccessControl.SecurityInfo import ClassSecurityInfo
+from AccessControl.Permissions import change_configuration, view
+from AccessControl.Permissions import use_mailhost_services
+from Acquisition import Implicit
+from App.special_dtml import DTMLFile
+from DateTime.DateTime import DateTime
+from Persistence import Persistent
+from OFS.role import RoleManager
+from OFS.SimpleItem import Item
+
+from zope.interface import implements
+from zope.sendmail.mailer import SMTPMailer
+from zope.sendmail.maildir import Maildir
+from zope.sendmail.delivery import DirectMailDelivery, QueuedMailDelivery, \
+                            QueueProcessorThread
+
+from interfaces import IMailHost
+from decorator import synchronized
+
+queue_threads = {}  # maps MailHost path -> queue processor threada
+
+LOG = logging.getLogger('MailHost')
+
+# Encode utf-8 emails as Quoted Printable by default
+email.Charset.add_charset("utf-8", email.Charset.QP, email.Charset.QP, "utf-8")
+formataddr = emailutils.formataddr
+parseaddr = emailutils.parseaddr
+getaddresses = emailutils.getaddresses
+CHARSET_RE = re.compile('charset=[\'"]?([\w-]+)[\'"]?', re.IGNORECASE)
+
+
+class MailHostError(Exception):
+    pass
+
+manage_addMailHostForm = DTMLFile('dtml/addMailHost_form', globals())
+
+
+def manage_addMailHost(self,
+                       id,
+                       title='',
+                       smtp_host='localhost',
+                       localhost='localhost',
+                       smtp_port=25,
+                       timeout=1.0,
+                       REQUEST=None,
+                      ):
+    """ Add a MailHost into the system.
+    """
+    i = MailHost(id, title, smtp_host, smtp_port)
+    self._setObject(id, i)
+
+    if REQUEST is not None:
+        REQUEST['RESPONSE'].redirect(self.absolute_url()+'/manage_main')
+
+add = manage_addMailHost
+
+
+class MailBase(Implicit, Item, RoleManager):
+    """a mailhost...?"""
+
+    implements(IMailHost)
+
+    meta_type = 'Mail Host'
+    manage = manage_main = DTMLFile('dtml/manageMailHost', globals())
+    manage_main._setName('manage_main')
+    index_html = None
+    security = ClassSecurityInfo()
+    smtp_uid = '' # Class attributes for smooth upgrades
+    smtp_pwd = ''
+    smtp_queue = False
+    smtp_queue_directory = '/tmp'
+    force_tls = False
+    lock = Lock()
+
+    manage_options = (
+        (
+        {'icon': '', 'label': 'Edit',
+         'action': 'manage_main',
+         'help': ('MailHost', 'Mail-Host_Edit.stx')},
+        )
+        + RoleManager.manage_options
+        + Item.manage_options
+        )
+
+    def __init__(self,
+                 id='',
+                 title='',
+                 smtp_host='localhost',
+                 smtp_port=25,
+                 force_tls=False,
+                 smtp_uid='',
+                 smtp_pwd='',
+                 smtp_queue=False,
+                 smtp_queue_directory='/tmp',
+                ):
+        """Initialize a new MailHost instance.
+        """
+        self.id = id
+        self.title = title
+        self.smtp_host = str(smtp_host)
+        self.smtp_port = int(smtp_port)
+        self.smtp_uid = smtp_uid
+        self.smtp_pwd = smtp_pwd
+        self.force_tls = force_tls
+        self.smtp_queue = smtp_queue
+        self.smtp_queue_directory = smtp_queue_directory
+
+
+    # staying for now... (backwards compatibility)
+    def _init(self, smtp_host, smtp_port):
+        self.smtp_host = smtp_host
+        self.smtp_port = smtp_port
+
+    security.declareProtected(change_configuration, 'manage_makeChanges')
+    def manage_makeChanges(self,
+                           title,
+                           smtp_host,
+                           smtp_port,
+                           smtp_uid='',
+                           smtp_pwd='',
+                           smtp_queue=False,
+                           smtp_queue_directory='/tmp',
+                           force_tls=False,
+                           REQUEST=None,
+                          ):
+        """Make the changes.
+        """
+        title = str(title)
+        smtp_host = str(smtp_host)
+        smtp_port = int(smtp_port)
+
+        self.title = title
+        self.smtp_host = smtp_host
+        self.smtp_port = smtp_port
+        self.smtp_uid = smtp_uid
+        self.smtp_pwd = smtp_pwd
+        self.force_tls = force_tls
+        self.smtp_queue = smtp_queue
+        self.smtp_queue_directory = smtp_queue_directory
+
+        # restart queue processor thread
+        if self.smtp_queue:
+            self._stopQueueProcessorThread()
+            self._startQueueProcessorThread()
+        else:
+            self._stopQueueProcessorThread()
+
+
+        if REQUEST is not None:
+            msg = 'MailHost %s updated' % self.id
+            return self.manage_main(self, REQUEST, manage_tabs_message=msg)
+
+    security.declareProtected(use_mailhost_services, 'sendTemplate')
+    def sendTemplate(trueself,
+                     self,
+                     messageTemplate,
+                     statusTemplate=None,
+                     mto=None,
+                     mfrom=None,
+                     encode=None,
+                     REQUEST=None,
+                     immediate=False,
+                     charset=None,
+                     msg_type=None,
+                    ):
+        """Render a mail template, then send it...
+        """
+        mtemplate = getattr(self, messageTemplate)
+        messageText = mtemplate(self, trueself.REQUEST)
+        trueself.send(messageText, mto=mto, mfrom=mfrom,
+                      encode=encode, immediate=immediate,
+                      charset=charset, msg_type=msg_type)
+
+        if not statusTemplate:
+            return "SEND OK"
+        try:
+            stemplate = getattr(self, statusTemplate)
+            return stemplate(self, trueself.REQUEST)
+        except:
+            return "SEND OK"
+
+    security.declareProtected(use_mailhost_services, 'send')
+    def send(self,
+             messageText,
+             mto=None,
+             mfrom=None,
+             subject=None,
+             encode=None,
+             immediate=False,
+             charset=None,
+             msg_type=None,
+            ):
+        messageText, mto, mfrom = _mungeHeaders(messageText, mto, mfrom,
+                                                subject, charset, msg_type)
+        # This encode step is mainly for BBB, encoding should be
+        # automatic if charset is passed.  The automated charset-based
+        # encoding will be preferred if both encode and charset are
+        # provided.
+        messageText = _encode(messageText, encode)
+        self._send(mfrom, mto, messageText, immediate)
+
+    # This is here for backwards compatibility only. Possibly it could
+    # be used to send messages at a scheduled future time, or via a mail queue?
+    security.declareProtected(use_mailhost_services, 'scheduledSend')
+    scheduledSend = send
+
+    security.declareProtected(use_mailhost_services, 'simple_send')
+    def simple_send(self, mto, mfrom, subject, body, immediate=False):
+        body = "From: %s\nTo: %s\nSubject: %s\n\n%s" % (
+            mfrom, mto, subject, body)
+
+        self._send(mfrom, mto, body, immediate)
+
+
+    def _makeMailer(self):
+        """ Create a SMTPMailer """
+        return SMTPMailer(hostname=self.smtp_host,
+                          port=int(self.smtp_port),
+                          username=self.smtp_uid or None,
+                          password=self.smtp_pwd or None,
+                          force_tls=self.force_tls)
+
+    security.declarePrivate('_getThreadKey')
+    def _getThreadKey(self):
+        """ Return the key used to find our processor thread.
+        """
+        return realpath(self.smtp_queue_directory)
+
+    @synchronized(lock)
+    def _stopQueueProcessorThread(self):
+        """ Stop thread for processing the mail queue.
+        """
+        key = self._getThreadKey()
+        if key in queue_threads:
+            thread = queue_threads[key]
+            thread.stop()
+            while thread.isAlive():
+                # wait until thread is really dead
+                time.sleep(0.3)
+            del queue_threads[key]
+            LOG.info('Thread for %s stopped' % key)
+
+    @synchronized(lock)
+    def _startQueueProcessorThread(self):
+        """ Start thread for processing the mail queue.
+        """
+        key = self._getThreadKey()
+        if key not in queue_threads:
+            thread = QueueProcessorThread()
+            thread.setMailer(self._makeMailer())
+            thread.setQueuePath(self.smtp_queue_directory)
+            thread.start()
+            queue_threads[key] = thread
+            LOG.info('Thread for %s started' % key)
+
+    security.declareProtected(view, 'queueLength')
+    def queueLength(self):
+        """ return length of mail queue """
+
+        try:
+            maildir = Maildir(self.smtp_queue_directory)
+            return len([item for item in maildir])
+        except ValueError:
+            return 'n/a - %s is not a maildir - please verify your ' \
+                   'configuration' % self.smtp_queue_directory
+
+
+    security.declareProtected(view, 'queueThreadAlive')
+    def queueThreadAlive(self):
+        """ return True/False is queue thread is working
+        """
+        th = queue_threads.get(self._getThreadKey())
+        if th:
+            return th.isAlive()
+        return False
+
+    security.declareProtected(change_configuration,
+                              'manage_restartQueueThread')
+    def manage_restartQueueThread(self, action='start', REQUEST=None):
+        """ Restart the queue processor thread """
+
+        if action == 'stop':
+            self._stopQueueProcessorThread()
+        elif action == 'start':
+            self._startQueueProcessorThread()
+        else:
+            raise ValueError('Unsupported action %s' % action)
+
+        if REQUEST is not None:
+            msg = 'Queue processor thread %s' % \
+                  (action == 'stop' and 'stopped' or 'started')
+            return self.manage_main(self, REQUEST, manage_tabs_message=msg)
+
+
+    security.declarePrivate('_send')
+    def _send(self, mfrom, mto, messageText, immediate=False):
+        """ Send the message """
+
+        if immediate:
+            self._makeMailer().send(mfrom, mto, messageText)
+        else:
+            if self.smtp_queue:
+                # Start queue processor thread, if necessary
+                self._startQueueProcessorThread()
+                delivery = QueuedMailDelivery(self.smtp_queue_directory)
+            else:
+                delivery = DirectMailDelivery(self._makeMailer())
+
+            delivery.send(mfrom, mto, messageText)
+
+InitializeClass(MailBase)
+
+
+class MailHost(Persistent, MailBase):
+    """persistent version"""
+
+
+def uu_encoder(msg):
+    """For BBB only, don't send uuencoded emails"""
+    orig = StringIO(msg.get_payload())
+    encdata = StringIO()
+    uu.encode(orig, encdata)
+    msg.set_payload(encdata.getvalue())
+
+# All encodings supported by mimetools for BBB
+ENCODERS = {
+    'base64': Encoders.encode_base64,
+    'quoted-printable': Encoders.encode_quopri,
+    '7bit': Encoders.encode_7or8bit,
+    '8bit': Encoders.encode_7or8bit,
+    'x-uuencode': uu_encoder,
+    'uuencode': uu_encoder,
+    'x-uue': uu_encoder,
+    'uue': uu_encoder,
+    }
+
+
+def _encode(body, encode=None):
+    """Manually sets an encoding and encodes the message if not
+    already encoded."""
+    if encode is None:
+        return body
+    mo = message_from_string(body)
+    current_coding = mo['Content-Transfer-Encoding']
+    if current_coding == encode:
+        # already encoded correctly, may have been automated
+        return body
+    if mo['Content-Transfer-Encoding'] not in ['7bit', None]:
+        raise MailHostError('Message already encoded')
+    if encode in ENCODERS:
+        ENCODERS[encode](mo)
+        if not mo['Content-Transfer-Encoding']:
+            mo['Content-Transfer-Encoding'] = encode
+        if not mo['Mime-Version']:
+            mo['Mime-Version'] = '1.0'
+    return mo.as_string()
+
+
+def _mungeHeaders(messageText, mto=None, mfrom=None, subject=None,
+                  charset=None, msg_type=None):
+    """Sets missing message headers, and deletes Bcc.
+       returns fixed message, fixed mto and fixed mfrom"""
+    # If we have been given unicode fields, attempt to encode them
+    if isinstance(messageText, unicode):
+        messageText = _try_encode(messageText, charset)
+    if isinstance(mto, unicode):
+        mto = _try_encode(mto, charset)
+    if isinstance(mfrom, unicode):
+        mfrom = _try_encode(mfrom, charset)
+    if isinstance(subject, unicode):
+        subject = _try_encode(subject, charset)
+
+    if isinstance(messageText, Message):
+        # We already have a message, make a copy to operate on
+        mo = deepcopy(messageText)
+    else:
+        # Otherwise parse the input message
+        mo = message_from_string(messageText)
+
+    if msg_type and not mo.get('Content-Type'):
+        # we don't use get_content_type because that has a default
+        # value of 'text/plain'
+        mo.set_type(msg_type)
+
+    charset = _set_recursive_charset(mo, charset=charset)
+
+    # Parameters given will *always* override headers in the messageText.
+    # This is so that you can't override or add to subscribers by adding
+    # them to # the message text.
+    if subject:
+        # remove any existing header otherwise we get two
+        del mo['Subject']
+        # Perhaps we should ignore errors here and pass 8bit strings
+        # on encoding errors
+        mo['Subject'] = Header(subject, charset, errors='replace')
+    elif not mo.get('Subject'):
+        mo['Subject'] = '[No Subject]'
+
+    if mto:
+        if isinstance(mto, basestring):
+            mto = [formataddr(addr) for addr in getaddresses((mto, ))]
+        if not mo.get('To'):
+            mo['To'] = ', '.join(str(_encode_address_string(e, charset))
+                                 for e in mto)
+    else:
+        # If we don't have recipients, extract them from the message
+        mto = []
+        for header in ('To', 'Cc', 'Bcc'):
+            v = ','.join(mo.get_all(header) or [])
+            if v:
+                mto += [formataddr(addr) for addr in getaddresses((v, ))]
+        if not mto:
+            raise MailHostError("No message recipients designated")
+
+    if mfrom:
+        # XXX: do we really want to override an explicitly set From
+        # header in the messageText
+        del mo['From']
+        mo['From'] = _encode_address_string(mfrom, charset)
+    else:
+        if mo.get('From') is None:
+            raise MailHostError("Message missing SMTP Header 'From'")
+        mfrom = mo['From']
+
+    if mo.get('Bcc'):
+        del mo['Bcc']
+
+    if not mo.get('Date'):
+        mo['Date'] = DateTime().rfc822()
+
+    return mo.as_string(), mto, mfrom
+
+
+def _set_recursive_charset(payload, charset=None):
+    """Set charset for all parts of an multipart message."""
+    def _set_payload_charset(payload, charset=None, index=None):
+        payload_from_string = False
+        if not isinstance(payload, Message):
+            payload = message_from_string(payload)
+            payload_from_string = True
+        charset_match = CHARSET_RE.search(payload['Content-Type'] or '')
+        if charset and not charset_match:
+            # Don't change the charset if already set
+            # This encodes the payload automatically based on the default
+            # encoding for the charset
+            if payload_from_string:
+                payload.get_payload()[index] = payload
+            else:
+                payload.set_charset(charset)
+        elif charset_match and not charset:
+            # If a charset parameter was provided use it for header encoding
+            # below, otherwise, try to use the charset provided in the message.
+            charset = charset_match.groups()[0]
+        return charset
+    if payload.is_multipart():
+        for index, payload in enumerate(payload.get_payload()):
+            if payload.get_filename() is None:
+                if not payload.is_multipart():
+                    charset = _set_payload_charset(payload,
+                                                   charset=charset,
+                                                   index=index)
+                else:
+                    _set_recursive_charset(payload, charset=charset)
+    else:
+        charset = _set_payload_charset(payload, charset=charset)
+    return charset
+
+
+def _try_encode(text, charset):
+    """Attempt to encode using the default charset if none is
+    provided.  Should we permit encoding errors?"""
+    if charset:
+        return text.encode(charset)
+    else:
+        return text.encode()
+
+
+def _encode_address_string(text, charset):
+    """Split the email into parts and use header encoding on the name
+    part if needed. We do this because the actual addresses need to be
+    ASCII with no encoding for most SMTP servers, but the non-address
+    parts should be encoded appropriately."""
+    header = Header()
+    name, addr = parseaddr(text)
+    try:
+        name.decode('us-ascii')
+    except UnicodeDecodeError:
+        if charset:
+            charset = Charset(charset)
+            name = charset.header_encode(name)
+    # We again replace rather than raise an error or pass an 8bit string
+    header.append(formataddr((name, addr)), errors='replace')
+    return header
Index: /vendor/Products.MailHost/2.13.1/src/Products/MailHost/SendMailTag.py
===================================================================
--- /vendor/Products.MailHost/2.13.1/src/Products/MailHost/SendMailTag.py	(revision 3357)
+++ /vendor/Products.MailHost/2.13.1/src/Products/MailHost/SendMailTag.py	(revision 3357)
@@ -0,0 +1,125 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Foundation and Contributors.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE
+#
+##############################################################################
+
+from DocumentTemplate.DT_Util import parse_params
+from DocumentTemplate.DT_Util import render_blocks
+from DocumentTemplate.DT_String import String
+
+from Products.MailHost.MailHost import MailBase, MailHostError
+
+
+class SendMailTag:
+    '''the send mail tag, used like thus:
+
+    <dtml-sendmail mailhost="someMailHostID">
+    to: person@their.machine.com
+    from: me@mymachine.net
+    subject: just called to say...
+
+    boy howdy!
+    </dtml-sendmail>
+
+    Text between the sendmail and /sendmail tags is processed
+    by the MailHost machinery and delivered.  There must be at least
+    one blank line seperating the headers (to/from/etc..) from the body
+    of the message.
+
+    Instead of specifying a MailHost, an smtphost may be specified
+    ala 'smtphost="mail.mycompany.com" port=25' (port defaults to 25
+    automatically).  Other parameters are
+
+    * mailto -- person (or comma-seperated list of persons) to send the
+    mail to.  If not specified, there **must** be a to: header in the
+    message.
+
+    * mailfrom -- person sending the mail (basically who the recipient can
+    reply to).  If not specified, there **must** be a from: header in the
+    message.
+
+    * subject -- optional subject.  If not specified, there **must** be a
+    subject: header in the message.
+
+    * encode -- optional encoding. Possible values are: 'base64',
+     'quoted-printable' and 'uuencode'.
+
+    '''
+
+    name='sendmail'
+    blockContinuations=()
+    encode=None
+
+    def __init__(self, blocks):
+        tname, args, section=blocks[0]
+        args=parse_params(args, mailhost=None, mailto=None, mailfrom=None,
+                          subject=None, smtphost=None, port='25',
+                          encode=None)
+
+        smtphost=None
+
+        has_key=args.has_key
+        if has_key('mailhost'):
+            mailhost = args['mailhost']
+        elif has_key('smtphost'):
+            mailhost = smtphost = args['smtphost']
+        elif has_key(''):
+            mailhost = args['mailhost'] = args['']
+        else:
+            raise MailHostError('No mailhost was specified in tag')
+
+        for key in ('mailto', 'mailfrom', 'subject', 'port'):
+            if not key in args:
+                args[key] = ''
+
+        if has_key('encode') and args['encode'] not in \
+        ('base64', 'quoted-printable', 'uuencode', 'x-uuencode',
+         'uue', 'x-uue'):
+            raise MailHostError(
+                'An unsupported encoding was specified in tag')
+
+        if not smtphost:
+            self.__name__=self.mailhost=mailhost
+            self.smtphost=None
+        else:
+            self.__name__=self.smtphost=smtphost
+            self.mailhost=None
+        self.section=section
+        self.args=args
+        self.mailto=args['mailto']
+        self.mailfrom=args['mailfrom']
+        self.subject=None or args['subject']
+        if args['port'] and type(args['port']) is type('s'):
+            self.port=args['port']=int(args['port'])
+        elif args['port']=='':
+            self.port=args['port']=25
+        else:
+            self.port=args['port']
+        if has_key('encode'):
+            self.encode=args['encode']
+        else:
+            self.encode=None
+
+    def render(self, md):
+        if self.mailhost:
+            mhost = md[self.mailhost]
+        elif self.smtphost:
+            mhost = MailBase(smtp_host=self.smtphost, smtp_port=self.port)
+
+        mhost.send(render_blocks(self.section.blocks, md),
+                   self.mailto, self.mailfrom,
+                   self.subject, self.encode)
+
+        return ' '
+
+    __call__ = render
+
+String.commands['sendmail'] = SendMailTag
Index: /vendor/Products.MailHost/2.13.1/src/Products/MailHost/__init__.py
===================================================================
--- /vendor/Products.MailHost/2.13.1/src/Products/MailHost/__init__.py	(revision 3357)
+++ /vendor/Products.MailHost/2.13.1/src/Products/MailHost/__init__.py	(revision 3357)
@@ -0,0 +1,28 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Foundation and Contributors.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE
+#
+##############################################################################
+
+import MailHost
+import SendMailTag
+
+
+def initialize(context):
+    context.registerClass(
+        MailHost.MailHost,
+        permission='Add MailHost objects',
+        constructors=(MailHost.manage_addMailHostForm,
+                      MailHost.manage_addMailHost),
+        icon='www/MailHost_icon.gif',
+    )
+
+    context.registerHelp()
+    context.registerHelpTitle('Zope Help')
Index: /vendor/Products.MailHost/2.13.1/src/Products/MailHost/decorator.py
===================================================================
--- /vendor/Products.MailHost/2.13.1/src/Products/MailHost/decorator.py	(revision 3357)
+++ /vendor/Products.MailHost/2.13.1/src/Products/MailHost/decorator.py	(revision 3357)
@@ -0,0 +1,29 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Foundation and Contributors.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+Decorator(s)
+"""
+
+
+def synchronized(lock):
+    """ Decorator for method synchronization. """
+
+    def wrapper(f):
+        def method(*args, **kw):
+            lock.acquire()
+            try:
+                return f(*args, **kw)
+            finally:
+                lock.release()
+        return method
+    return wrapper
Index: /vendor/Products.MailHost/2.13.1/src/Products/MailHost/dtml/addMailHost_form.dtml
===================================================================
--- /vendor/Products.MailHost/2.13.1/src/Products/MailHost/dtml/addMailHost_form.dtml	(revision 3357)
+++ /vendor/Products.MailHost/2.13.1/src/Products/MailHost/dtml/addMailHost_form.dtml	(revision 3357)
@@ -0,0 +1,71 @@
+<dtml-var manage_page_header>
+
+<dtml-var "manage_form_title(this(), _,
+           form_title='Add MailHost',
+           help_product='MailHost',
+           help_topic='Mail-Host_Add.stx'
+	   )">
+
+<p class="form-help">
+MailHost object provide a way to send email from Zope code in DTML or 
+Python Scripts. <em>SMTP host</em> is the name of the mail server machine.
+<em>SMTP port</em> is the port on which the mail server is running the 
+SMTP service.
+</p>
+
+<form action="manage_addMailHost" method="post">
+<table cellspacing="0" cellpadding="2" border="0">
+  <tr>
+    <td align="left" valign="top">
+    <div class="form-label">
+    Id
+    </div>
+    </td>
+    <td align="left" valign="top">
+    <input type="text" name="id" size="40" value="MailHost" />
+    </td>
+  </tr>
+  <tr>
+    <td align="left" valign="top">
+    <div class="form-optional">
+    Title
+    </div>
+    </td>
+    <td align="left" valign="top">
+    <input type="text" name="title" size="40" />
+    </td>
+  </tr>
+  <tr>
+    <td align="left" valign="top">
+    <div class="form-label">
+    SMTP Host
+    </div>
+    </td>
+    <td align="left" valign="top">
+    <input type="text" name="smtp_host" size="40" value="localhost" />
+    </td>
+  </tr>
+  <tr>
+    <td align="left" valign="top">
+    <div class="form-label">
+    SMTP Port
+    </div>
+    </td>
+    <td align="left" valign="top">
+    <input type="text" name="smtp_port:int" size="4" value="25" />
+    </td>
+  </tr>
+  <tr>
+    <td align="left" valign="top">
+    </td>
+    <td align="left" valign="top">
+    <div class="form-element">
+    <input class="form-element" type="submit" name="submit" 
+     value=" Add " /> 
+    </div>
+    </td>
+  </tr>
+</table>
+</form>
+
+<dtml-var manage_page_footer>
Index: /vendor/Products.MailHost/2.13.1/src/Products/MailHost/dtml/manageMailHost.dtml
===================================================================
--- /vendor/Products.MailHost/2.13.1/src/Products/MailHost/dtml/manageMailHost.dtml	(revision 3357)
+++ /vendor/Products.MailHost/2.13.1/src/Products/MailHost/dtml/manageMailHost.dtml	(revision 3357)
@@ -0,0 +1,176 @@
+<dtml-var manage_page_header>
+<dtml-var manage_tabs>
+
+<form action="manage_makeChanges" method="post">
+<table cellspacing="0" cellpadding="2" border="0">
+  <tr>
+    <td align="left" valign="top">
+    <div class="form-label">
+    Id
+    </div>
+    </td>
+    <td align="left" valign="top">
+    <div class="form-text">
+    &dtml-id;
+    </div>
+    </td>
+  </tr>
+  <tr>
+    <td align="left" valign="top">
+    <div class="form-optional">
+    Title
+    </div>
+    </td>
+    <td align="left" valign="top">
+    <input type="text" name="title" size="40" 
+     value="&dtml-title;"/>
+    </td>
+  </tr>
+  <tr>
+    <td align="left" valign="top">
+    <div class="form-label">
+    SMTP Host
+    </div>
+    </td>
+    <td align="left" valign="top">
+    <input type="text" name="smtp_host" size="40"
+     value="&dtml-smtp_host;"/>
+    </td>
+  </tr>
+  <tr>
+    <td align="left" valign="top">
+    <div class="form-label">
+    SMTP Port
+    </div>
+    </td>
+    <td align="left" valign="top">
+    <input type="text" name="smtp_port:int" size="4"
+     value="&dtml-smtp_port;"/>
+    </td>
+  </tr>
+  <tr>
+    <td align="left" valign="top">
+    <div class="form-label">
+    Username
+    </div>
+    </td>
+    <td align="left" valign="top">
+    <input type="text" name="smtp_uid" size="15"
+     value="&dtml.null-smtp_uid;"/>
+    </td>
+    <td>
+    <span class="form-help">(optional for SMTP AUTH)</span>
+    </td>
+  </tr>
+  <tr>
+    <td align="left" valign="top">
+    <div class="form-label">
+    Password
+    </div>
+    </td>
+    <td align="left" valign="top">
+    <input type="password" name="smtp_pwd" size="15"
+     value="&dtml.null-smtp_pwd;"/>
+    </td>
+    <td>
+    <span class="form-help">(optional for SMTP AUTH)</span>
+    </td>
+  </tr>
+  <tr>
+    <td align="left" valign="top">
+    <div class="form-label">
+    Force TLS
+    </div>
+    </td>
+    <td align="left" valign="top">
+    <input type="checkbox" name="force_tls:boolean" value="1"
+     <dtml-if "force_tls">checked</dtml-if>
+    </td>
+    <td>
+        <span class="form-help">(enforce the use of an encrypted connection 
+            to the SMTP server. Mail delivery fails if the SMTP server
+            does not support encryption)
+        </span>
+    </td>
+  </tr>
+  <tr>
+    <td align="left" valign="top">
+    <div class="form-label">
+    Use mail queue
+    </div>
+    </td>
+    <td align="left" valign="top">
+    <input type="checkbox" name="smtp_queue:boolean" value="1"
+     <dtml-if "smtp_queue">checked</dtml-if>
+    </td>
+    <td>
+    <span class="form-help">(asynchronous mail delivery if checked)</span>
+    </td>
+  </tr>
+  <tr>
+    <td align="left" valign="top">
+    <div class="form-label">
+    Queue directory<br/> 
+    </div>
+    </td>
+    <td align="left" valign="top">
+    <input type="text" name="smtp_queue_directory" size="30"
+     value="&dtml-smtp_queue_directory;"/>
+    </td>
+    <td>
+    <span class="form-help">(directory on the filesystem where the mails will be spooled. Only used if 'Use mail queue' is checked.)</span>
+    </td>
+  </tr>
+  <tr>
+    <td align="left" valign="top">
+    </td>
+    <td align="left" valign="top">
+    <div class="form-element">
+    <input class="form-element" type="submit" name="submit" 
+     value="Save Changes" /> 
+    </div>
+    </td>
+  </tr>
+</table>
+
+<dtml-if smtp_queue>
+    <br />
+    <table cellspacing="0" cellpadding="2" border="0">
+      <tr>
+        <td align="left" valign="top">
+        <div class="form-label">
+        Mails in queue <br/> 
+        </div>
+        </td>
+        <td align="left" valign="top">
+            <span class="form-help"><dtml-var queueLength></span>
+        </td>
+      </tr>
+      <tr>
+        <td align="left" valign="top">
+        <div class="form-label">
+        Status of queue processor thread<br/> 
+        </div>
+        </td>
+        <td align="left" valign="top">
+            <div class="form-help">
+
+                <dtml-if "queueThreadAlive()">
+                    Running
+                    <br/>
+                    <a href="manage_restartQueueThread?action=stop">Stop queue processor thread</a> (this may take some seconds)
+                </dtml-if>
+                <dtml-if "not queueThreadAlive()">
+                    Stopped
+                    <br/>
+                    <a href="manage_restartQueueThread?action=start">Start queue processor thread</a> (this may take some seconds)
+                </dtml-if>
+            </div>
+        </td>
+      </tr>
+    </table>
+</dtml-if>
+
+</form>
+
+<dtml-var manage_page_footer>
Index: /vendor/Products.MailHost/2.13.1/src/Products/MailHost/help/Mail-Host.stx
===================================================================
--- /vendor/Products.MailHost/2.13.1/src/Products/MailHost/help/Mail-Host.stx	(revision 3357)
+++ /vendor/Products.MailHost/2.13.1/src/Products/MailHost/help/Mail-Host.stx	(revision 3357)
@@ -0,0 +1,45 @@
+MailHost: Sends mail through an SMTP server.
+
+  MailHosts allow you to send mail via the Simple Mail Transfer
+  Protocol (SMTP).
+
+  This object can be used deliver mail by the <dtml-sendmail> tag
+  or via the send() and simple_send() methods.
+
+    'send(messageText, mto=None, mfrom=None, subject=None, encode=None)'
+
+      Sends an email message where the messageText is an rfc822 formatted
+      message. This allows you complete control over the message headers,
+      including setting any extra headers such as Cc: and Reply-To:.
+      The arguments are:
+
+        messageText -- The mail message. It can either be a rfc822
+        formed text with header fields, or just a body without any
+        header fields. The other arguments given will override the
+        header fields in the message, if they exist.
+
+        mto -- A commaseparated string or list of recipient(s) of the message.
+
+        mfrom -- The address of the message sender.
+
+        subject -- The subject of the message.
+
+        encode -- The rfc822 defined encoding of the message.  The
+        default of 'None' means no encoding is done.  Valid values
+        are 'base64', 'quoted-printable' and 'uuencode'.
+
+    'simple_send(self, mto, mfrom, subject, body)'
+
+      Sends a message. Only To:, From: and Subject: headers can be set.
+      Note that simple_send does not process or validate its arguments
+      in any way.
+      The arguments are:
+
+        mto -- A commaseparated string of recipient(s) of the message.
+
+        mfrom -- The address of the message sender.
+
+        subject -- The subject of the message.
+
+        body -- The body of the message.
+
Index: /vendor/Products.MailHost/2.13.1/src/Products/MailHost/help/Mail-Host_Add.stx
===================================================================
--- /vendor/Products.MailHost/2.13.1/src/Products/MailHost/help/Mail-Host_Add.stx	(revision 3357)
+++ /vendor/Products.MailHost/2.13.1/src/Products/MailHost/help/Mail-Host_Add.stx	(revision 3357)
@@ -0,0 +1,18 @@
+MailHost - Add: Create a new MailHost
+
+  Description
+
+    Create a new MailHost object.
+
+  Controls
+
+    'ID' -- The id of the MailHost object.
+
+    'Title' -- The title of the MailHost.
+
+    'SMTP host' -- The domain name or address of the SMTP mail server
+      to relay mail through.
+
+    'SMTP port' -- The port of the SMTP mail server to relay mail
+    through.
+
Index: /vendor/Products.MailHost/2.13.1/src/Products/MailHost/help/Mail-Host_Edit.stx
===================================================================
--- /vendor/Products.MailHost/2.13.1/src/Products/MailHost/help/Mail-Host_Edit.stx	(revision 3357)
+++ /vendor/Products.MailHost/2.13.1/src/Products/MailHost/help/Mail-Host_Edit.stx	(revision 3357)
@@ -0,0 +1,18 @@
+MailHost - Edit: Edit mail host properties
+  
+  Description
+
+    This view allows you edit the MailHost.
+
+ Controls
+
+    'ID' -- The id of the MailHost.
+
+    'Title' -- The title of the MailHost.
+
+    'SMTP host' -- The domain name or address of the SMTP mail server
+      to relay mail through.
+
+    'SMTP port' -- The port of the SMTP mail server to relay mail
+      through.
+
Index: /vendor/Products.MailHost/2.13.1/src/Products/MailHost/help/MailHost.py
===================================================================
--- /vendor/Products.MailHost/2.13.1/src/Products/MailHost/help/MailHost.py	(revision 3357)
+++ /vendor/Products.MailHost/2.13.1/src/Products/MailHost/help/MailHost.py	(revision 3357)
@@ -0,0 +1,70 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Foundation and Contributors.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE
+#
+##############################################################################
+
+def manage_addMailHost(id, title='', smtp_host=None,
+        localhost='localhost', smtp_port=25,
+        timeout=1.0):
+    """
+
+    Add a mailhost object to an ObjectManager.
+
+    """
+
+
+class MailHost:
+    """
+    MailHost objects work as adapters to Simple Mail Transfer Protocol
+    (SMTP) servers.  MailHosts are used by DTML 'sendmail' tags
+    to find the proper host to deliver mail to.
+    """
+
+    def send(messageText, mto=None, mfrom=None, subject=None,
+             encode=None):
+        """
+        Sends an email message where the messageText is an rfc822 formatted
+        message. This allows you complete control over the message headers,
+        including setting any extra headers such as Cc: and Reply-To:.
+        The arguments are:
+
+            messageText -- The mail message. It can either be a rfc822
+            formed text with header fields, or just a body without any
+            header fields. The other arguments given will override the
+            header fields in the message, if they exist.
+
+            mto -- A commaseparated string or list of recipient(s) of the message.
+
+            mfrom -- The address of the message sender.
+
+            subject -- The subject of the message.
+
+            encode -- The rfc822 defined encoding of the message.  The
+            default of 'None' means no encoding is done.  Valid values
+            are 'base64', 'quoted-printable' and 'uuencode'.
+
+        """
+
+    def simple_send(self, mto, mfrom, subject, body):
+        """
+        Sends a message. Only To:, From: and Subject: headers can be set.
+        Note that simple_send does not process or validate its arguments
+        in any way.
+        The arguments are:
+
+            mto -- A commaseparated string of recipient(s) of the message.
+
+            mfrom -- The address of the message sender.
+
+            subject -- The subject of the message.
+
+            body -- The body of the message.
+        """
Index: /vendor/Products.MailHost/2.13.1/src/Products/MailHost/interfaces.py
===================================================================
--- /vendor/Products.MailHost/2.13.1/src/Products/MailHost/interfaces.py	(revision 3357)
+++ /vendor/Products.MailHost/2.13.1/src/Products/MailHost/interfaces.py	(revision 3357)
@@ -0,0 +1,24 @@
+##############################################################################
+#
+# Copyright (c) 2005 Zope Foundation and Contributors.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""MailHost interfaces.
+"""
+
+from zope.interface import Interface
+
+
+class IMailHost(Interface):
+
+    def send(messageText, mto=None, mfrom=None, subject=None, encode=None,
+             charset=None, msg_type=None):
+        """Send mail.
+        """
Index: /vendor/Products.MailHost/2.13.1/src/Products/MailHost/mailer.py
===================================================================
--- /vendor/Products.MailHost/2.13.1/src/Products/MailHost/mailer.py	(revision 3357)
+++ /vendor/Products.MailHost/2.13.1/src/Products/MailHost/mailer.py	(revision 3357)
@@ -0,0 +1,7 @@
+import zope.deferredimport
+
+zope.deferredimport.deprecatedFrom(
+    "Import from zope.sendmail instead",
+    'zope.sendmail.mailer',
+    'SMTPMailer',
+    )
Index: /vendor/Products.MailHost/2.13.1/src/Products/MailHost/tests/__init__.py
===================================================================
--- /vendor/Products.MailHost/2.13.1/src/Products/MailHost/tests/__init__.py	(revision 3357)
+++ /vendor/Products.MailHost/2.13.1/src/Products/MailHost/tests/__init__.py	(revision 3357)
@@ -0,0 +1,13 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
Index: /vendor/Products.MailHost/2.13.1/src/Products/MailHost/tests/testMailHost.py
===================================================================
--- /vendor/Products.MailHost/2.13.1/src/Products/MailHost/tests/testMailHost.py	(revision 3357)
+++ /vendor/Products.MailHost/2.13.1/src/Products/MailHost/tests/testMailHost.py	(revision 3357)
@@ -0,0 +1,644 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Foundation and Contributors.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""MailHost unit tests.
+"""
+
+import unittest
+from email import message_from_string
+
+from Products.MailHost.MailHost import MailHost
+from Products.MailHost.MailHost import MailHostError, _mungeHeaders
+
+
+class DummyMailHost(MailHost):
+    meta_type = 'Dummy Mail Host'
+    def __init__(self, id):
+        self.id = id
+        self.sent = ''
+    def _send(self, mfrom, mto, messageText, immediate=False):
+        self.sent = messageText
+        self.immediate = immediate
+
+
+class FakeContent(object):
+    def __init__(self, template_name, message):
+        def template(self, context, REQUEST=None):
+            return message
+        setattr(self, template_name, template)
+
+    @staticmethod
+    def check_status(context, REQUEST=None):
+        return 'Message Sent'
+
+
+class TestMailHost(unittest.TestCase):
+
+    def _getTargetClass(self):
+        return DummyMailHost
+
+    def _makeOne(self, *args, **kw):
+        return self._getTargetClass()(*args, **kw)
+
+    def test_z3interfaces(self):
+        from Products.MailHost.interfaces import IMailHost
+        from zope.interface.verify import verifyClass
+
+        verifyClass(IMailHost, self._getTargetClass())
+
+    def testAllHeaders(self):
+        msg = """To: recipient@domain.com
+From: sender@domain.com
+Subject: This is the subject
+
+This is the message body."""
+        # No additional info
+        resmsg, resto, resfrom = _mungeHeaders(msg)
+        self.failUnless(resto == ['recipient@domain.com'])
+        self.failUnless(resfrom == 'sender@domain.com')
+
+        # Add duplicated info
+        resmsg, resto, resfrom = _mungeHeaders(msg, 'recipient@domain.com',
+                                  'sender@domain.com', 'This is the subject')
+        self.failUnlessEqual(resto, ['recipient@domain.com'])
+        self.failUnlessEqual(resfrom, 'sender@domain.com')
+
+        # Add extra info
+        resmsg, resto, resfrom = _mungeHeaders(msg, 'recipient2@domain.com',
+                            'sender2@domain.com', 'This is the real subject')
+        self.failUnlessEqual(resto, ['recipient2@domain.com'])
+        self.failUnlessEqual(resfrom, 'sender2@domain.com')
+
+    def testMissingHeaders(self):
+        msg = """X-Header: Dummy header
+
+This is the message body."""
+        # Doesn't specify to
+        self.failUnlessRaises(MailHostError, _mungeHeaders, msg,
+                              mfrom='sender@domain.com')
+        # Doesn't specify from
+        self.failUnlessRaises(MailHostError, _mungeHeaders, msg,
+                              mto='recipient@domain.com')
+
+    def testNoHeaders(self):
+        msg = """This is the message body."""
+        # Doesn't specify to
+        self.failUnlessRaises(MailHostError, _mungeHeaders, msg,
+                              mfrom='sender@domain.com')
+        # Doesn't specify from
+        self.failUnlessRaises(MailHostError, _mungeHeaders, msg,
+                              mto='recipient@domain.com')
+        # Specify all
+        resmsg, resto, resfrom = _mungeHeaders(msg, 'recipient2@domain.com',
+                             'sender2@domain.com', 'This is the real subject')
+        self.failUnlessEqual(resto, ['recipient2@domain.com'])
+        self.failUnlessEqual(resfrom, 'sender2@domain.com')
+
+    def testBCCHeader(self):
+        msg = "From: me@example.com\nBcc: many@example.com\n\nMessage text"
+        # Specify only the "Bcc" header.  Useful for bulk emails.
+        resmsg, resto, resfrom = _mungeHeaders(msg)
+        self.failUnlessEqual(resto, ['many@example.com'])
+        self.failUnlessEqual(resfrom, 'me@example.com')
+
+    def test__getThreadKey_uses_fspath(self):
+        mh1 = self._makeOne('mh1')
+        mh1.smtp_queue_directory = '/abc'
+        mh1.absolute_url = lambda self: 'http://example.com/mh1'
+        mh2 = self._makeOne('mh2')
+        mh2.smtp_queue_directory = '/abc'
+        mh2.absolute_url = lambda self: 'http://example.com/mh2'
+        self.assertEqual(mh1._getThreadKey(), mh2._getThreadKey())
+
+    def testAddressParser(self):
+        msg = """\
+To: "Name, Nick" <recipient@domain.com>, "Foo Bar" <foo@domain.com>
+CC: "Web, Jack" <jack@web.com>
+From: sender@domain.com
+Subject: This is the subject
+
+This is the message body."""
+
+        # Test Address-Parser for To & CC given in messageText
+
+        resmsg, resto, resfrom = _mungeHeaders(msg)
+        self.failUnlessEqual(resto, ['"Name, Nick" <recipient@domain.com>',
+                                  'Foo Bar <foo@domain.com>',
+                                  '"Web, Jack" <jack@web.com>'])
+        self.failUnlessEqual(resfrom, 'sender@domain.com')
+
+        # Test Address-Parser for a given mto-string
+
+        resmsg, resto, resfrom = _mungeHeaders(msg,
+            mto='"Public, Joe" <pjoe@domain.com>, Foo Bar <foo@domain.com>')
+
+        self.failUnlessEqual(resto, ['"Public, Joe" <pjoe@domain.com>',
+                                  'Foo Bar <foo@domain.com>'])
+        self.failUnlessEqual(resfrom, 'sender@domain.com')
+
+    def testSendMessageOnly(self):
+        msg = """\
+To: "Name, Nick" <recipient@domain.com>, "Foo Bar" <foo@domain.com>
+From: sender@domain.com
+Subject: This is the subject
+Date: Sun, 27 Aug 2006 17:00:00 +0200
+
+This is the message body."""
+
+        mailhost = self._makeOne('MailHost')
+        mailhost.send(msg)
+        self.assertEqual(mailhost.sent, msg)
+
+    def testSendWithArguments(self):
+        inmsg = """\
+Date: Sun, 27 Aug 2006 17:00:00 +0200
+
+This is the message body."""
+
+        outmsg = """\
+Date: Sun, 27 Aug 2006 17:00:00 +0200
+Subject: This is the subject
+To: "Name, Nick" <recipient@domain.com>, Foo Bar <foo@domain.com>
+From: sender@domain.com
+
+This is the message body."""
+
+        mailhost = self._makeOne('MailHost')
+        mailhost.send(messageText=inmsg,
+                      mto='"Name, Nick" <recipient@domain.com>, '
+                          '"Foo Bar" <foo@domain.com>',
+                      mfrom='sender@domain.com', subject='This is the subject')
+        self.assertEqual(mailhost.sent, outmsg)
+
+    def testSendWithMtoList(self):
+        inmsg = """\
+Date: Sun, 27 Aug 2006 17:00:00 +0200
+
+This is the message body."""
+
+        outmsg = """\
+Date: Sun, 27 Aug 2006 17:00:00 +0200
+Subject: This is the subject
+To: "Name, Nick" <recipient@domain.com>, Foo Bar <foo@domain.com>
+From: sender@domain.com
+
+This is the message body."""
+
+        mailhost = self._makeOne('MailHost')
+        mailhost.send(messageText=inmsg,
+                      mto=['"Name, Nick" <recipient@domain.com>',
+                           '"Foo Bar" <foo@domain.com>'],
+                      mfrom='sender@domain.com', subject='This is the subject')
+        self.assertEqual(mailhost.sent, outmsg)
+
+    def testSimpleSend(self):
+        outmsg = """\
+From: sender@domain.com
+To: "Name, Nick" <recipient@domain.com>, "Foo Bar" <foo@domain.com>
+Subject: This is the subject
+
+This is the message body."""
+
+        mailhost = self._makeOne('MailHost')
+        mailhost.simple_send(mto='"Name, Nick" <recipient@domain.com>, '
+                                 '"Foo Bar" <foo@domain.com>',
+                             mfrom='sender@domain.com',
+                             subject='This is the subject',
+                             body='This is the message body.')
+        self.assertEqual(mailhost.sent, outmsg)
+        self.assertEqual(mailhost.immediate, False)
+
+    def testSendImmediate(self):
+        outmsg = """\
+From: sender@domain.com
+To: "Name, Nick" <recipient@domain.com>, "Foo Bar" <foo@domain.com>
+Subject: This is the subject
+
+This is the message body."""
+
+        mailhost = self._makeOne('MailHost')
+        mailhost.simple_send(mto='"Name, Nick" <recipient@domain.com>, '
+                                 '"Foo Bar" <foo@domain.com>',
+                             mfrom='sender@domain.com',
+                             subject='This is the subject',
+                             body='This is the message body.',
+                             immediate=True)
+        self.assertEqual(mailhost.sent, outmsg)
+        self.assertEqual(mailhost.immediate, True)
+
+    def testSendBodyWithUrl(self):
+        # The implementation of rfc822.Message reacts poorly to
+        # message bodies containing ':' characters as in a url
+        msg = "Here's a nice link: http://www.zope.org/"
+
+        mailhost = self._makeOne('MailHost')
+        mailhost.send(messageText=msg,
+                      mto='"Name, Nick" <recipient@domain.com>, '
+                          '"Foo Bar" <foo@domain.com>',
+                      mfrom='sender@domain.com',
+                      subject='This is the subject')
+        out = message_from_string(mailhost.sent)
+        self.failUnlessEqual(out.get_payload(), msg)
+        self.failUnlessEqual(out['To'],
+            '"Name, Nick" <recipient@domain.com>, Foo Bar <foo@domain.com>')
+        self.failUnlessEqual(out['From'], 'sender@domain.com')
+
+    def testSendEncodedBody(self):
+        # If a charset is specified the correct headers for content
+        # encoding will be set if not already set.  Additionally, if
+        # there is a default transfer encoding for the charset, then
+        # the content will be encoded and the transfer encoding header
+        # will be set.
+        msg = "Here's some encoded t\xc3\xa9xt."
+        mailhost = self._makeOne('MailHost')
+        mailhost.send(messageText=msg,
+                      mto='"Name, Nick" <recipient@domain.com>, '
+                          '"Foo Bar" <foo@domain.com>',
+                      mfrom='sender@domain.com',
+                      subject='This is the subject',
+                      charset='utf-8')
+        out = message_from_string(mailhost.sent)
+        self.failUnlessEqual(out['To'],
+            '"Name, Nick" <recipient@domain.com>, Foo Bar <foo@domain.com>')
+        self.failUnlessEqual(out['From'], 'sender@domain.com')
+        # utf-8 will default to Quoted Printable encoding
+        self.failUnlessEqual(out['Content-Transfer-Encoding'],
+                             'quoted-printable')
+        self.failUnlessEqual(out['Content-Type'],
+                             'text/plain; charset="utf-8"')
+        self.failUnlessEqual(out.get_payload(),
+                             "Here's some encoded t=C3=A9xt.")
+
+    def testEncodedHeaders(self):
+        # Headers are encoded automatically, email headers are encoded
+        # piece-wise to ensure the adresses remain ASCII
+        mfrom = "Jos\xc3\xa9 Andr\xc3\xa9s <jose@example.com>"
+        mto = "Ferran Adri\xc3\xa0 <ferran@example.com>"
+        subject = "\xc2\xbfEsferificaci\xc3\xb3n?"
+        mailhost = self._makeOne('MailHost')
+        mailhost.send(messageText='A message.', mto=mto, mfrom=mfrom,
+                      subject=subject, charset='utf-8')
+        out = message_from_string(mailhost.sent)
+        self.failUnlessEqual(out['To'],
+                         '=?utf-8?q?Ferran_Adri=C3=A0?= <ferran@example.com>')
+        self.failUnlessEqual(out['From'],
+            '=?utf-8?q?Jos=C3=A9_Andr=C3=A9s?= <jose@example.com>')
+        self.failUnlessEqual(out['Subject'],
+            '=?utf-8?q?=C2=BFEsferificaci=C3=B3n=3F?=')
+        # utf-8 will default to Quoted Printable encoding
+        self.failUnlessEqual(out['Content-Transfer-Encoding'],
+                             'quoted-printable')
+        self.failUnlessEqual(out['Content-Type'],
+                             'text/plain; charset="utf-8"')
+        self.failUnlessEqual(out.get_payload(), "A message.")
+
+    def testAlreadyEncodedMessage(self):
+        # If the message already specifies encodings, it is
+        # essentially not altered this is true even if charset or
+        # msg_type is specified
+        msg = """\
+From: =?utf-8?q?Jos=C3=A9_Andr=C3=A9s?= <jose@example.com>
+To: =?utf-8?q?Ferran_Adri=C3=A0?= <ferran@example.com>
+Subject: =?utf-8?q?=C2=BFEsferificaci=C3=B3n=3F?=
+Date: Sun, 27 Aug 2006 17:00:00 +0200
+Content-Type: text/html; charset="utf-8"
+Content-Transfer-Encoding: base64
+MIME-Version: 1.0 (Generated by testMailHost.py)
+
+wqFVbiB0cnVjbyA8c3Ryb25nPmZhbnTDoXN0aWNvPC9zdHJvbmc+IQ=3D=3D
+"""
+        mailhost = self._makeOne('MailHost')
+        mailhost.send(messageText=msg)
+        self.failUnlessEqual(mailhost.sent, msg)
+        mailhost.send(messageText=msg, msg_type='text/plain')
+        # The msg_type is ignored if already set
+        self.failUnlessEqual(mailhost.sent, msg)
+
+    def testAlreadyEncodedMessageWithCharset(self):
+        # If the message already specifies encodings, it is
+        # essentially not altered this is true even if charset or
+        # msg_type is specified
+        msg = """\
+From: =?utf-8?q?Jos=C3=A9_Andr=C3=A9s?= <jose@example.com>
+To: =?utf-8?q?Ferran_Adri=C3=A0?= <ferran@example.com>
+Subject: =?utf-8?q?=C2=BFEsferificaci=C3=B3n=3F?=
+Date: Sun, 27 Aug 2006 17:00:00 +0200
+Content-Type: text/html; charset="utf-8"
+Content-Transfer-Encoding: base64
+MIME-Version: 1.0 (Generated by testMailHost.py)
+
+wqFVbiB0cnVjbyA8c3Ryb25nPmZhbnTDoXN0aWNvPC9zdHJvbmc+IQ=3D=3D
+"""
+        mailhost = self._makeOne('MailHost')
+        # Pass a different charset, which will apply to any explicitly
+        # set headers
+        mailhost.send(messageText=msg,
+                      subject='\xbfEsferificaci\xf3n?',
+                      charset='iso-8859-1', msg_type='text/plain')
+        # The charset for the body should remain the same, but any
+        # headers passed into the method will be encoded using the
+        # specified charset
+        out = message_from_string(mailhost.sent)
+        self.failUnlessEqual(out['Content-Type'], 'text/html; charset="utf-8"')
+        self.failUnlessEqual(out['Content-Transfer-Encoding'],
+                                 'base64')
+        # Headers set by parameter will be set using charset parameter
+        self.failUnlessEqual(out['Subject'],
+                             '=?iso-8859-1?q?=BFEsferificaci=F3n=3F?=')
+        # original headers will be unaltered
+        self.failUnlessEqual(out['From'],
+            '=?utf-8?q?Jos=C3=A9_Andr=C3=A9s?= <jose@example.com>')
+
+    def testUnicodeMessage(self):
+        # unicode messages and headers are decoded using the given charset
+        msg = unicode("Here's some unencoded <strong>t\xc3\xa9xt</strong>.",
+                      'utf-8')
+        mfrom = unicode('Ferran Adri\xc3\xa0 <ferran@example.com>', 'utf-8')
+        subject = unicode('\xc2\xa1Andr\xc3\xa9s!', 'utf-8')
+        mailhost = self._makeOne('MailHost')
+        mailhost.send(messageText=msg,
+                      mto='"Name, Nick" <recipient@domain.com>',
+                      mfrom=mfrom, subject=subject, charset='utf-8',
+                      msg_type='text/html')
+        out = message_from_string(mailhost.sent)
+        self.failUnlessEqual(out['To'],
+                         '"Name, Nick" <recipient@domain.com>')
+        self.failUnlessEqual(out['From'],
+            '=?utf-8?q?Ferran_Adri=C3=A0?= <ferran@example.com>')
+        self.failUnlessEqual(out['Subject'], '=?utf-8?q?=C2=A1Andr=C3=A9s!?=')
+        self.failUnlessEqual(out['Content-Transfer-Encoding'],
+                             'quoted-printable')
+        self.failUnlessEqual(out['Content-Type'], 'text/html; charset="utf-8"')
+        self.failUnlessEqual(out.get_payload(),
+            "Here's some unencoded <strong>t=C3=A9xt</strong>.")
+
+    def testUnicodeNoEncodingErrors(self):
+        # Unicode messages and headers raise errors if no charset is passed to
+        # send
+        msg = unicode("Here's some unencoded <strong>t\xc3\xa9xt</strong>.",
+                      'utf-8')
+        subject = unicode('\xc2\xa1Andr\xc3\xa9s!', 'utf-8')
+        mailhost = self._makeOne('MailHost')
+        self.assertRaises(UnicodeEncodeError,
+                          mailhost.send, msg,
+                          mto='"Name, Nick" <recipient@domain.com>',
+                          mfrom='Foo Bar <foo@domain.com>',
+                          subject=subject)
+
+    def testUnicodeDefaultEncoding(self):
+        # However if we pass unicode that can be encoded to the
+        # default encoding (generally 'us-ascii'), no error is raised.
+        # We include a date in the messageText to make inspecting the
+        # results more convenient.
+        msg = u"""\
+Date: Sun, 27 Aug 2006 17:00:00 +0200
+
+Here's some unencoded <strong>text</strong>."""
+        subject = u'Andres!'
+        mailhost = self._makeOne('MailHost')
+        mailhost.send(msg, mto=u'"Name, Nick" <recipient@domain.com>',
+                      mfrom=u'Foo Bar <foo@domain.com>', subject=subject)
+        out = mailhost.sent
+        # Ensure the results are not unicode
+        self.failUnlessEqual(out, """\
+Date: Sun, 27 Aug 2006 17:00:00 +0200
+Subject: Andres!
+To: "Name, Nick" <recipient@domain.com>
+From: Foo Bar <foo@domain.com>
+
+Here's some unencoded <strong>text</strong>.""")
+        self.failUnlessEqual(type(out), str)
+
+    def testSendMessageObject(self):
+        # send will accept an email.Message.Message object directly
+        msg = message_from_string("""\
+From: =?utf-8?q?Jos=C3=A9_Andr=C3=A9s?= <jose@example.com>
+To: =?utf-8?q?Ferran_Adri=C3=A0?= <ferran@example.com>
+Subject: =?utf-8?q?=C2=BFEsferificaci=C3=B3n=3F?=
+Date: Sun, 27 Aug 2006 17:00:00 +0200
+Content-Type: text/html; charset="utf-8"
+Content-Transfer-Encoding: base64
+MIME-Version: 1.1
+
+wqFVbiB0cnVjbyA8c3Ryb25nPmZhbnTDoXN0aWNvPC9zdHJvbmc+IQ=3D=3D
+""")
+        mailhost = self._makeOne('MailHost')
+        mailhost.send(msg)
+        out = message_from_string(mailhost.sent)
+        self.failUnlessEqual(out.as_string(), msg.as_string())
+
+        # we can even alter a from and subject headers without affecting the
+        # original object
+        mailhost.send(msg,
+                      mfrom='Foo Bar <foo@domain.com>', subject='Changed!')
+        out = message_from_string(mailhost.sent)
+
+        # We need to make sure we didn't mutate the message we were passed
+        self.failIfEqual(out.as_string(), msg.as_string())
+        self.failUnlessEqual(out['From'], 'Foo Bar <foo@domain.com>')
+        self.failUnlessEqual(msg['From'],
+            '=?utf-8?q?Jos=C3=A9_Andr=C3=A9s?= <jose@example.com>')
+        # The subject is encoded with the body encoding since no
+        # explicit encoding was specified
+        self.failUnlessEqual(out['Subject'], '=?utf-8?q?Changed!?=')
+        self.failUnlessEqual(msg['Subject'],
+                             '=?utf-8?q?=C2=BFEsferificaci=C3=B3n=3F?=')
+
+    def testExplicitUUEncoding(self):
+        # We can request a payload encoding explicitly, though this
+        # should probably be considered deprecated functionality.
+        mailhost = self._makeOne('MailHost')
+        # uuencoding
+        mailhost.send('Date: Sun, 27 Aug 2006 17:00:00 +0200\n\nA Message',
+                      mfrom='sender@domain.com',
+                      mto='Foo Bar <foo@domain.com>', encode='uue')
+        out = message_from_string(mailhost.sent)
+        self.failUnlessEqual(mailhost.sent, """\
+Date: Sun, 27 Aug 2006 17:00:00 +0200
+Subject: [No Subject]
+To: Foo Bar <foo@domain.com>
+From: sender@domain.com
+Content-Transfer-Encoding: uue
+Mime-Version: 1.0
+
+begin 666 -
+)02!-97-S86=E
+ 
+end
+""")
+
+    def testExplicitBase64Encoding(self):
+        mailhost = self._makeOne('MailHost')
+        mailhost.send('Date: Sun, 27 Aug 2006 17:00:00 +0200\n\nA Message',
+                      mfrom='sender@domain.com',
+                      mto='Foo Bar <foo@domain.com>', encode='base64')
+        out = message_from_string(mailhost.sent)
+        self.failUnlessEqual(mailhost.sent, """\
+Date: Sun, 27 Aug 2006 17:00:00 +0200
+Subject: [No Subject]
+To: Foo Bar <foo@domain.com>
+From: sender@domain.com
+Content-Transfer-Encoding: base64
+Mime-Version: 1.0
+
+QSBNZXNzYWdl""")
+
+    def testExplicit7bitEncoding(self):
+        mailhost = self._makeOne('MailHost')
+        mailhost.send('Date: Sun, 27 Aug 2006 17:00:00 +0200\n\nA Message',
+                      mfrom='sender@domain.com',
+                      mto='Foo Bar <foo@domain.com>', encode='7bit')
+        out = message_from_string(mailhost.sent)
+        self.failUnlessEqual(mailhost.sent, """\
+Date: Sun, 27 Aug 2006 17:00:00 +0200
+Subject: [No Subject]
+To: Foo Bar <foo@domain.com>
+From: sender@domain.com
+Content-Transfer-Encoding: 7bit
+Mime-Version: 1.0
+
+A Message""")
+
+    def testExplicit8bitEncoding(self):
+        mailhost = self._makeOne('MailHost')
+        # We pass an encoded string with unspecified charset, it should be
+        # encoded 8bit
+        mailhost.send('Date: Sun, 27 Aug 2006 17:00:00 +0200\n\n'
+                      'A M\xc3\xa9ssage',
+                      mfrom='sender@domain.com',
+                      mto='Foo Bar <foo@domain.com>', encode='8bit')
+        out = message_from_string(mailhost.sent)
+        self.failUnlessEqual(mailhost.sent, """\
+Date: Sun, 27 Aug 2006 17:00:00 +0200
+Subject: [No Subject]
+To: Foo Bar <foo@domain.com>
+From: sender@domain.com
+Content-Transfer-Encoding: 8bit
+Mime-Version: 1.0
+
+A M\xc3\xa9ssage""")
+
+    def testSendTemplate(self):
+        content = FakeContent('my_template', 'A Message')
+        mailhost = self._makeOne('MailHost')
+        result = mailhost.sendTemplate(content, 'my_template',
+                                       mto='Foo Bar <foo@domain.com>',
+                                       mfrom='sender@domain.com')
+        self.failUnlessEqual(result, 'SEND OK')
+        result = mailhost.sendTemplate(content, 'my_template',
+                                       mto='Foo Bar <foo@domain.com>',
+                                       mfrom='sender@domain.com',
+                                       statusTemplate='wrong_name')
+        self.failUnlessEqual(result, 'SEND OK')
+        result = mailhost.sendTemplate(content, 'my_template',
+                                       mto='Foo Bar <foo@domain.com>',
+                                       mfrom='sender@domain.com',
+                                       statusTemplate='check_status')
+        self.failUnlessEqual(result, 'Message Sent')
+
+    def testSendMultiPartAlternativeMessage(self):
+        msg = ("""\
+Content-Type: multipart/alternative; boundary="===============0490954888=="
+MIME-Version: 1.0
+Date: Sun, 27 Aug 2006 17:00:00 +0200
+Subject: My multipart email
+To: Foo Bar <foo@domain.com>
+From: sender@domain.com
+
+--===============0490954888==
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: quoted-printable
+
+This is plain text.
+
+--===============0490954888==
+Content-Type: multipart/related; boundary="===============2078950065=="
+MIME-Version: 1.0
+
+--===============2078950065==
+Content-Type: text/html; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: quoted-printable
+
+<p>This is html.</p>
+--===============2078950065==--
+--===============0490954888==--
+""")
+
+        mailhost = self._makeOne('MailHost')
+        # Specifying a charset for the header may have unwanted side
+        # effects in the case of multipart mails.
+        # (TypeError: expected string or buffer)
+        mailhost.send(msg, charset='utf-8')
+        self.assertEqual(mailhost.sent, msg)
+
+    def testSendMultiPartMixedMessage(self):
+        msg = ("""\
+Content-Type: multipart/mixed; boundary="XOIedfhf+7KOe/yw"
+Content-Disposition: inline
+MIME-Version: 1.0
+Date: Sun, 27 Aug 2006 17:00:00 +0200
+Subject: My multipart email
+To: Foo Bar <foo@domain.com>
+From: sender@domain.com
+
+--XOIedfhf+7KOe/yw
+Content-Type: text/plain; charset=us-ascii
+Content-Disposition: inline
+
+This is a test with as attachment OFS/www/new.gif.
+
+--XOIedfhf+7KOe/yw
+Content-Type: image/gif
+Content-Disposition: attachment; filename="new.gif"
+Content-Transfer-Encoding: base64
+
+R0lGODlhCwAQAPcAAP8A/wAAAFBQUICAgMDAwP8AAIAAQAAAoABAgIAAgEAAQP//AP//gACA
+gECAgP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAALABAAAAg7AAEIFKhgoEGC
+CwoeRKhwoYKEBhVIfLgg4UQAFCtqbJixYkOEHg9SHDmQJEmMEBkS/IiR5cKXMGPKDAgAOw==
+
+--XOIedfhf+7KOe/yw
+Content-Type: text/plain; charset=iso-8859-1
+Content-Disposition: attachment; filename="test.txt"
+Content-Transfer-Encoding: quoted-printable
+
+D=EDt =EFs =E9=E9n test
+
+--XOIedfhf+7KOe/yw--
+""")
+
+        mailhost = self._makeOne('MailHost')
+        # Specifying a charset for the header may have unwanted side
+        # effects in the case of multipart mails.
+        # (TypeError: expected string or buffer)
+        mailhost.send(msg, charset='utf-8')
+        self.assertEqual(mailhost.sent, msg)
+
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(TestMailHost))
+    return suite
Index: /vendor/Products.MailHost/2.13.1/src/Products/__init__.py
===================================================================
--- /vendor/Products.MailHost/2.13.1/src/Products/__init__.py	(revision 3357)
+++ /vendor/Products.MailHost/2.13.1/src/Products/__init__.py	(revision 3357)
@@ -0,0 +1,1 @@
+__import__('pkg_resources').declare_namespace(__name__)
