Sending email

Description

How to programmatically send email in Plone

Introduction

This document tells how to send email from Plone.

Email can be sent:

  • manually, by calling MailHost;
  • using a Content Rule (content rules have an email-out action by default) which can be activated by a workflow transition, for example;
  • triggering email-based password reset.

Configuring MailHost for a mail queue

Products.MailHost supports asynchronous sending in a separate thread via a mail queue.

Note

Using a mail queue is recommended for production sites.

To enable the queue, go to the Management Interface and the MailHost tool. Here, check the “Use mail queue” setting and set the “Queue directory”. The queue directory is given as an absolute path on your server, must have a maildir layout (it needs the directories ‘cur’, new’ and ‘tmp’ in it) and must be writeable by the system user, under which the Zope thread runs.

Manually calling MailHost

After your mail_text is prepared, sending it is as simple as:

from plone import api

try:
    mail_host = api.portal.get_tool(name='MailHost')
    # The ``immediate`` parameter causes an email to be sent immediately
    # (if any error is raised) rather than sent at the transaction
    # boundary or queued for later delivery.
    return mail_host.send(mail_text, immediate=True)
except SMTPRecipientsRefused:
    # Don't disclose email address on failure
    raise SMTPRecipientsRefused('Recipient address rejected by server')

Preparing mail text

mail_text can be generated by calling a page template (.pt) with keyword arguments. The values are accessed in the template as option/keyword. For example, take a sample template:

<tal:root define="lt string:&lt;;
                  gt string:&gt;;
                  dummy python:request.RESPONSE.setHeader('Content-Type', 'text/plain;; charset=%s' % options['charset']);
                  member python:options['member'];"
>From: "<span tal:replace="python:here.email_from_name" />" <span tal:replace="structure lt"/><span tal:replace="python:here.email_from_address" /><span tal:replace="structure gt"/>
To: <span tal:replace="python:member.getProperty('email')" />
Subject: <span i18n:domain="yourproduct" i18n:translate="yoursubjectline" tal:omit-tag="">Subject Line</span>
Content-Type: text/plain; charset=<span tal:replace="python:options['charset']" />
Dear <span tal:replace="member/getFullname" />:
You can now log in as <span tal:replace="member/getId" /> at <span tal:replace="python:options['portal_url']" />
Cheers!
The website team
</tal:root>

This can be called with a member object and the portal_url:

mail_template = portal.mail_template_id
mail_text = mail_template(member=member,
                          portal_url=portal.absolute_url(),
                          charset=email_charset,
                          request=REQUEST)

For more complete examples (with i18n support, etc.) see the password reset modules (particularly Products.remember.tools.registration).

Note

If you don’t need to have third parties to override your email templates it might be cleaned to use Python string templates, as XML based TAL templates are not designed for plain text templating.

Graceful failing

In the case SMTP server rejects the connection. etc. don’t abort the current transaction (which is the default behavior)