===================
Using MailTemplates
===================

MailTemplates provide full access to Python's email package and
allow the body of messages to be generated using Zope's Page
Template technology. They work in both a Zope environment and a CMF
environment. That includes software based on the CMF such as Plone
and CPS.

In addition, the MailTemplates product contains security
assertions that make all of Python's email package available for
use in "untrusted" Zope code such as Script (Python) objects.

MailTemplates are callable objects that, when
called, render the body of a mail message and either return that
as an object that may have further parts added to it or actually
uses a configured MailHost object to send the message.
 
Creating Mail Templates
-----------------------

Mail Templates can be created either by adding a Mail Template
using the menu in Zope's management information or by adding a
file with a .mt extension in a folder pointed to by a File System
Directory View.

Various attributes of the generated mail, such as headers,
charcater encoding and MIME encoding are controlled by a
combination of properties on the Mail Template and parameters
passed to the Mail Template when it is called.

Properties
----------

The following properties can be added to a Mail Template using the
Properties tab, or an accompanying :file:`.metadata` file for skin-based
MailTemplates:

.. attribute:: mailhost

  For ZODB-based Mail Templates, this is set using the drop-down
  on the edit screen. For skin-based Mail Templates, this is
  specified in the :file:`.metadata` file associated with the Mail Template.
      
  In either case, it ends up being a slash-seperated path that is
  used to traverse to the MailHost object which will be used to
  send email.
      
.. attribute:: content_type

  As well as influencing the ZPT engine, the property is also used
  as the content type for the email generated by this Mail
  Template.

.. attribute:: mfrom

  This should be a string property and should contain the
  address which will be used to generate the ``From`` header for any
  mail sent from this Mail Template.
   
.. attribute:: mto

  This should be a string property, for a single address, or a
  lines property for multiple addresses, and should contain the
  address(es) to which any mail generated using this MailTemplate
  will be sent. It is also used to generate the ``To`` header.
   
.. attribute:: mcc
  
  This should be a string property, for a single address, or a
  lines property for multiple addresses, and should contain the
  address(es) which will be used to generate the 'CC' header for any
  mail sent from this Mail Template.
   
.. attribute:: mbcc

  This should be a string property, for a single address, or a
  lines property for multiple addresses, and should contain the
  address(es) which will be used to generate the 'BCC' header for any
  mail sent from this Mail Template.
   
.. attribute:: subject

  This should be a string property and its value will be used to
  generate the 'Subject' header for any mail sent from this Mail
  Template. 
   
.. attribute:: headers 

  This should be a lines property and each line should be of the
  form::
      
    HeaderName: value-to-set

  The headers specified in this property will be added to any mail
  generated by this Mail Template.

.. attribute:: encoding

  This should be a string property and controls the character set
  used to encode any mail generated by this Mail Template. It is
  used for both the character set supplied in the MIME encoding
  and for encoding the results of rendering the template. See the
  section on Unicode and Encoded Strings below for more
  information. 

  The default value is that specifed in the
  ``default_zpublisher_encoding`` setting in :file:`zope.conf`, if
  avaiable, or ``iso-8859-15`` otherwise. 

Methods
-------

In addition to being directly callable, MailTemplates have the
following methods. Directly calling a Mail Template is an alias
for calling the :meth:`send` method described below. The parameters to
both methods are described in the Parameters section further down
in this document.


.. method:: send(**params)

  This method renders the email and sends it using the configured
  MailHost. 

.. method:: as_message(**params)

  This method is used when you want to build multi-part emails
  such as those with both text and html versions and those with
  attached files.

  It renders the body of the MailTemplate as an :class:`email.mime.text.MIMEText`
  object, creates a :class:`~Products.MailTemplates.MTMultipart`
  object containing the headers for the rendered email, attaches the
  body to it and returns it.

  In addition to the parameters described below, the following
  keyword parameters can also optionally be used to control
  aspects of the multi-part message creation:

  :param subtype:
 
        This is a string argument specifying the subtype to use for
        the content type of the multi part message. The default is
        calculated to be something sensible but could, for example, be
        set to ``alternative`` to give a ``multipart/alternative`` message.

  :param boundary:

        This is a string specifying the boundary to use for multi-part
        messages. In general, this should not be specified, but can be
        handy when writing unit tests.

Parameters
----------

The following parameter may optionally be passed as keyword
arguments to both the :meth:`send` and :meth:`as_message` methods:

.. attribute:: mfrom

      This should be a string and should contain the address which
      will be used to generate the ``From`` header for the message being
      generated or sent.
   
.. attribute:: mto

      This should be a string, for a single address, or a sequence of
      strings, for multiple addresses and should contain the
      address(es) to which the message will be sent. It is also used
      to generate the ``To`` header. 
   
.. attribute:: mcc
   
      This should be a string, for a single address, or a sequence of
      strings, for multiple addresses and should contain the
      address(es) which will be used to generate the ``CC`` header for
      the mail currently being generated or sent.
   
.. attribute:: mbcc
 
      This should be a string, for a single address, or a sequence of
      strings, for multiple addresses and should contain the
      address(es) which will be used to generate the ``BCC`` header for
      the mail currently being generated or sent.
   
.. attribute:: subject

      This should be a string and will be used to generate the
      ``Subject`` header for the mail currently being generated or
      sent. 
   
.. attribute:: headers 

      This should be a dictionary mapping header names to header
      values. Both the names and values should be strings.

      The headers specified in this dictionary will be added to the
      mail currently being generated or sent. 
   
.. attribute:: encoding

      This parameter controls the character set used to encode the mail
      currently being generated or sent. It is used for both the
      character set supplied in the MIME encoding and for encoding the
      results of rendering non-html emails. See the section on Unicode
      and Encoded Strings below for more information.

      The default value is that specifed in the
      ``default_zpublisher_encoding`` of :file:`zope.conf` if
      avaiable, or `iso-8859-15` otherwise. 

Precedence During Generation
----------------------------

When generating an email, headers and the charset, mto and mfrom
parameters can come from several places; the parameters passed to
the send or as_message method, the properties of the Mail Template
itself, or the headers parameter or property. The order lookup is
as follows:

1. The parameters passed to the send or as_message method

2. For headers only, the content of the headers parameter passed
   to the send or as_message method.

3. The properties of the MailTemplate object

4. For headers only, the content of the headers property of the
   Mail Template object.

Required Parameters
-------------------

In order for a Mail Template to be successfully rendered, the
following parameters must be obtained through one of the four
options listed above:

- mto

- mfrom

- subject

If any of the above parameters cannot be obtained, an exception
will be raised.    

MTMultiPart obects
------------------

An MTMultipart object is identical to an :class:`email.mime.multipart.MIMEMultipart`
object except that is has two additional methods:

.. method:: MTMultiPart.send()

  This sends a rendered version of the message described by the
  MTMultipart object using the MailHost configured in the MailTemplate
  that created it.
      
.. method:: MTMultiPart.add_file(theFile=None,data=None,filename=None,content_type=None)

  This method is used to add attachments to the message.
  It can take either one argument or two keyword parameters. 
  In either case, an optional ``content_type`` keyword parameter 
  can be specified.

  If one parameter is passed, the it should be a Zope File or Image
  object, ZPublisher FileUpload object or a python file object. 

  If two keyword parameters are passed, they should be ``data``
  and ``filename``. ``data`` should be a string containing the body
  of the attachment. ``filename`` should be the file name to use
  for the attachment.

  In all cases, the ``content_type`` parameter can be used to
  override any guesswork in setting the content type for the
  attachment.

Unicode and Encoded Strings
---------------------------

Please note that you can run into problems with Mail Templates in
exactly the same way as for normal Page Templates.

All string-like data inserted into the Mail Template during
rendering should be in the form of unicode objects or strings encoded
with the same encoding specified in the MailTemplate's parameters.

Here is a bad example to illustrate incorrect
usage. While :attr:`encoding` is passed as a parameter here, you may
find it more convenient to set as a property or by specifying the
``default_zpublisher_encoding`` in your :file:`zope.conf` file.

Mail Template with :attr:`content_type` set to ``text/html``::

  Your currency is <tal:x replace="options/currency"/>

Script (Python)::
  
   return container.test_mt(currency=u''.encode('utf-8'),
                            encoding='latin-1')

Should have been::

  Your currency is <tal:x replace="options/currency"/>

Script (Python)::
  
   return container.test_mt(currency=u'',
                            encoding='latin-1')

Examples
--------

The following are some simple contrived examples to show some of
the possible uses of MailTemplates. If you wish to test with
these, you will need to change the :attr:`mto` addresses.

Simple Example
~~~~~~~~~~~~~~

This example sends a simple templated mail to a specific
address.

Add the following to a MailTemplate called ``my_mt``::

      <tal:body xmlns:tal="http://xml.zope.org/namespaces/tal"
          xmlns:metal="http://xml.zope.org/namespaces/metal"
      >Dear <tal:x replace="options/mto"/>,
 
      <tal:x replace="user/getId"/> would like to thank you for 
      your interest in:
      <tal:x replace="root/absolute_url"/>
 
      <tal:x replace="options/message"/>
 
      cheers,

      The Web Team
      </tal:body> 

Now add a Script (Python) in the same folder containing the
following::

      container.my_mt(
          mfrom='webmaster@example.com',
          mto='user@example.com',
          subject='This is a test!',
          message='This is a test!'
      )

      return 'Mail Sent!'

Finally, hit the Test tab of the Script (Python)!

File System Directory View Example
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

This example sends a simple templated mail to all the members of
a CMF portal. Please make sure your portal has at least one
member before you try this or you won't get any output!

Add a file called :file:`my_mt.mt` to a filesystem directory that is
mapped though to an FSDV containing the following::

      <tal:body xmlns:tal="http://xml.zope.org/namespaces/tal"
          xmlns:metal="http://xml.zope.org/namespaces/metal"
      >Dear <tal:x replace="options/member/getUserName"/>,
     
      Thankyou for you interest in our portal!

      cheers,

      The Web Team
      </tal:body>
   
Now add a file called :file:`my_mt.mt.metadata` in the same directory
containing the following::

      [default]
      mailhost=MailHost
      mfrom=webmaster@example.com
      subject=Thankyou for your interest!

Finally, add a file called :file:`send_mails.py` in the same directory
containing the following::

      for member in context.portal_membership.listMembers():
        context.my_mt(
          member=member,
          mto=member.getProperty('email')
          )

Then, to test, visit your equivalent of the following while
logged in as a Manager::

  http://localhost:8080/myportal/send_mails

Attachment Example
~~~~~~~~~~~~~~~~~~
  
This example sends a simple templated mail with a file attached
to it to a specific address.

Add a Mail Template called ``my_mt`` containing the following::

      <tal:body xmlns:tal="http://xml.zope.org/namespaces/tal"
          xmlns:metal="http://xml.zope.org/namespaces/metal"
      >Dear <tal:x replace="options/mto"/>,
 
      Please find attached the file you requested.
 
      cheers,

      The Web Team
      </tal:body>

Now add a Zope File object containing the file of your choice
but called ``myfile.bin``.

Finally add a Script (Python) called ``send_mail`` containing the
following::

      msg = container.my_mt.as_message(
            mfrom='from@example.com',
            mto='to1@example.com',
            subject='Your requested file',
            )
      msg.add_file(container['myfile.bin'])
      msg.send()
      return 'Mail Sent!'

When you test this Script (Python), the two addresses in the
:attr:`mto` parameter will receive a multi-part MIME-encoded email with
your file attached.

Dynamic Subject Line Example
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

This example shows how to use a templated subject line.

Add the following to a Mail Template called ``my_mt``::

      <tal:body xmlns:tal="http://xml.zope.org/namespaces/tal"
          xmlns:metal="http://xml.zope.org/namespaces/metal"
      >Dear <tal:x replace="options/mto"/>,
 
      Welcome to our site!
 
      cheers,

      The Web Team
      </tal:body>

Add a string property called :attr:`subject` containing
``Welcome to %s``, and a string property called :attr:`mfrom`
containing ``webmaster@example.com``, to the ``my_mt`` MailTemplate.

Now add a Script (Python) in the same folder containing the
following::

      container.my_mt(
          mto='user@example.com',
          subject=container.my_mt.subject % container.absolute_url()
      )

      return 'Mail Sent!'

Finally, hit the Test tab of the Script (Python)!
