Welcome to EasyNewsletter’s documentation!¶
What is it?¶
EasyNewsletter is a simple but powerful newsletter/mailing product for Plone.
Features¶
- Support Text and HTML Newsletter (including images)
- Support manual written Newsletters/Mailings
- Flexible (can use Plone’s Collections to collect content)
- Variable templates to generate newsletter content
- Subscribing / Unsubscribing and can use Plone Members/Groups as receivers (works also with Membrane)
- support for external subscriber sources (configured through a Zope utility)
- support for external delivery services (other than Plone MailHost)
- TTW customizeable output Templates to generate nice HTML Newsletter
- Support personalized mails
- Mass import/export subscribers via csv
- Support external filtering/manipulation (filter out or add more subscribers) plugins
- Support for creating and sending a daily issue
- Support for decoupled sendout
Requirements¶
- Plone 4.3, 5.0 and 5.1 (tested)
- Archetypes
- ATContentTypes (base profile only)
Optional:
inqbus.plone.fastmemberproperties
speeds up access of member properties. UseProducts.EasyNewsletter[fmp]
extra in your buildouts eggs list.collective.taskqueue
for asynchronous sendout. Use eitherProducts.EasyNewsletter[taskqueue]
orProducts.EasyNewsletter[taskqueue_redis]
extra. Configure a named task queueProducts.EasyNewsletter.queue
. Read carefully the documentation ofcollective.taskqueue
.collective.zamqp
for asynchronous sendout. Configure a queue namedProducts.EasyNewsletter.queue
.- For asynchronous sendout use the one or the other, both together will crash Plone.
collective.taskqueue
is recommended unless you know why you want to use AMQP.
Installation¶
- Add Products.EasyNewsletter to your buildout
- Run your buildout script
- Restart Zope
- Install EasyNewsletter via Plone Management Interface
- Add an “Newsletter Subscriber” portlet and select the EasyNewsletter (To this newsletter the subscribers will be added).
Usage¶
General¶
You can use EasyNewsletter to manually create mailings/newsletters or you can use the collection criteria to collect content.
EasyNewsletter can use multible Collections to aggregate content for a newsletter issue.
Once the content is generated one can edit the text as usual in Plone. But it’s not recommented, because TinyMCE is not very helpful with email markup.
You can create your own templates to structure the selected content. Please refer to the provided templates to see how it works.
Step by step¶
- Add a EasyNewsletter instance, fill in the form and save it.
- If you want to write a simple manual mailing, you can add an Issue and fill it out with your text.
- Or if you want to use collections to aggregate your content first, select some existing Collection in
Content aggregation sources
on the Newsletter and finally add an Issue. - You can select more than one Collection to build categories like news, events and pictures in your newsletter. Empty Collections will be ignored in default aggregations templates.
- Go to the view tab and call
Aggregate body content
from the action or Newsletter menu (>= Plone 5) menu. - You can also select Content aggregation sources` on Issue level. Then only the issue Collections are used.
- Go to Send tab or Send action in Newsletter menu (>=Plone 5) and push
Test Newsletter
. - If your Newsletter/Mailing is finished, you can activate the send button by clicking on
Enable send button
. Then you can click onSend newsletter
to send the Newsletter to all subscribers or selected groups and users.
Issue workflow information¶
There are now four workflow states for an issue, which are draft, sending, sent and master. If an issue is created, it’s initial state is draft.
Only issues with state draft can be send.
If a sendout is started, the state will move to sending.
After an issue is sent, it’s state is sent and it will appear in the newsletter archive.
In addition a master can be made out of an issue with the state draft or sent using the actions menu. The master acts as a blueprint, which can be reedited and copied as a new draft.
Images in HTML mails¶
- All images with relative urls in
src
attribute, like the ones added by TinyMCE, are included and attached to the mail. - All images with absolute urls in
src
attribute are not attached but included in HTML with the originalsrc
url.
Elements for mails only¶
If you want some elements, let’s say a logo only in mails but not in the public view, you can put it inside a div tag with a class “mailonly”. All div elements with class “mailonly” are filtered out in the public view.
Asyncronous sendout¶
Products.EasyNewsletter supports asyncronous sendout using collective.zamqp. Look at the self contained buildout or https://pypi.python.org/pypi/collective.zamqp and add Products.EasyNewsletter[zamqp] to your eggs section. If you have configured your buildout according accordingly, Products.EasyNewsletter will automatically delegate the sendout to your worker instance.
Sending a daily issue automatically¶
EasyNewsletter can create and send daily issues, using the default template and default criteria. Beside those, you just need to configure your crontab (or clock server) to send a POST on @@daily-issue view. Eg:
#Sends a newsletter, from Mon to Fri, at 0:00AM
0 0 * * 1-5 curl -X POST http://user:passwd@example.org/mynewsletter/@@daily-issue
@@daily-issue returns a HTTP status code indicating what just happened (you can also test it with a GET, instead). In the table below, you can check the responses codes.
@@daily-issue responses | |||
---|---|---|---|
Method/Precondition | Not yet sent | Empty | Already Sent |
GET | 100 | 204 | 200 |
POST | 200 [*] | 204 | 409 |
[*] | It sends the issue first. |
Using cron4plone to send it out¶
You can now use cron4plone to call the new trigger @@trigger-daily-issue
which will make a POST request to the @@daily-issue
.
Filtering Users, Groups and Receivers¶
EasyNewsletter provide a flexible way to filter the Plone members, Plone groups and the recivers list. You can provide smal funtion in your add-on and register it as IReceiversMemberFilter, IReceiversGroupFilter or IReceiversPostSendingFilter. The filter get the list and can filter out some entries or even add some entries.
Interface: Products.EasyNewsletter.interfaces.IReceiversMemberFilter
The IReceiversMemberFilter filters can be used to filter the list of Plone members which a user can select in newsletters and issues.
class ReceiversMemberFilterNoPloneMember(object):
""" filters all members out of newsletter receivers selection list,
which are default plone members. This is usefull if you whant
only membrane members but not the default plone user as receivers.
receivers: [(id, {'email': 'info@example.com',...})]
"""
def __init__(self, context):
self.context = context
def filter(self, receivers):
portal = getSite()
query = {}
query['portal_type'] = ['Contact',]
contacts = portal.membrane_tool.search(query)
whitelist = [contact.getUserId for contact in contacts]
receivers = [receiver for receiver in receivers
if receiver[0] in whitelist]
return receivers
This filter should be registered as follow:
<subscriber zcml:condition="installed my.package"
for="Products.EasyNewsletter.interfaces.IEasyNewsletter"
factory="my.package.newsletter.ReceiversMemberFilterNoPloneMember"
provides="Products.EasyNewsletter.interfaces.IReceiversMemberFilter" />
Interface: Products.EasyNewsletter.interfaces.IReceiversGroupFilter
The IReceiversGroupFilter filters can be used to filter the list of Plone groups which a user can select in newsletters and issues.
class ReceiversGroupFilterInactiveOrganizations(object):
""" Filter all inactive organizations, out of the group selection list.
receivers: [(id, {'email': 'info@example.com',...})]
"""
def __init__(self, context):
self.context = context
def filter(self, receivers):
portal = getSite()
query = {}
query['portal_type'] = ['Organization']
query['review_state'] = ['inactive', 'internal', 'pending', 'former_member']
inactive_groups = portal.membrane_tool.search(query)
blacklist = [black.getGroupId for black in inactive_groups]
receivers = [receiver for receiver in receivers
if receiver[0] not in blacklist]
return receivers
This filter should be registered as follow:
<subscriber zcml:condition="installed my.package"
for="Products.EasyNewsletter.interfaces.IEasyNewsletter"
factory="my.package.newsletter.ReceiversGroupFilterInactiveOrganizations"
provides="Products.EasyNewsletter.interfaces.IReceiversGroupFilter" />
Interface: Products.EasyNewsletter.interfaces.IReceiversMemberFilter
The IReceiversPostSendingFilter can be used to filter the list of reveivers before sending emails to all receivers.
class ReceiversPostSendingFilterNoNewsletter(object):
""" Filter all contacts that has not set the receive_newsletter
flag, out of receivers email list. But only if the Newsletter provide
IReceiversMemberFilterNoNewsletter.
receivers: [{'email': 'info@example.com',...}]
"""
def __init__(self, context):
self.context = context
def filter(self, receivers):
newsletter_object = self.context
if IReceiversMemberFilterNoNewsletter.providedBy(newsletter_object):
portal = getSite()
query = {}
query['portal_type'] = ['Contact']
query['getReceive_newsletter'] = False
no_enl_contacts = portal.membrane_tool.search(query)
blacklist = [black.getUserId for black in no_enl_contacts]
receivers = [receiver for receiver in receivers
if receiver['email'] not in blacklist]
return receivers
This filter should be registered as follow:
<subscriber zcml:condition="installed my.package"
for="Products.EasyNewsletter.interfaces.IEasyNewsletter"
factory="my.package.newsletter.ReceiversPostSendingFilterNoNewsletter"
provides="Products.EasyNewsletter.interfaces.IReceiversPostSendingFilter" />
Configuring external subscriber sources¶
An external subscriber sources provides (additional) subscriber to a newsletter instance.
You configure an external subscriber source as a Zope 3 utility providing ISubscriberSource (here’s an example where subscriptions are managed externally through MongoDB):
class NewsletterSource(object):
implements(ISubscriberSource)
def getSubscribers(self, newsletter):
""" return all subscribers for the given newsletter
from the MyInfo user database. Newsletter subscriptions
are referenced inside MyInfo through UIDs.
"""
uid = newsletter.UID()
# find MyInfo subscribers
myinfo = getUtility(IMyInfo)
subscribers = list()
for user in myinfo.accounts.find({'data.newsletters': uid, 'state': 'active'}):
subscribers.append(dict(email=user['email'], fullname=user['username']))
return subscribers
The utility must be registered using ZCML:
<utility zcml:condition="installed Products.EasyNewsletter"
name="MyInfo subscribers"
factory=".newsletter.NewsletterSource"
/>
Inside the Edit
view of the instance under the External
tab you should find
MyInfo subscribers
under the option External subscriber source
.
Allowed placeholders¶
The following placeholder can be used in the header, body and footer fields or the aggregation and output templates:
{{SUBSCRIBER_SALUTATION}}
example: Dear Ms.{{salutation}}
example: Ms.{{unsubscribe}}
unsubscribe link to be included in emails{{receiver}}
example:{'salutation': 'Guten Tag', 'nl_language': 'de', 'fullname': 'Test Member', 'email': 'maik@planetcrazy.de'}
{{language}}
example: de{{fullname}}
{{issue_title}}
{{issue_description}}
{{banner_src}}
Banner src url{{logo_src}}
Logo src url{{date}}
example: 30.05.2017{{month}}
example: 5{{year}}
example: 2017
Aggregation templates¶
We provide some content aggregation templates, but you can add more. A aggregation template has to be global available template. The default templates are in the skins folder. They have to be registered in the Plone registry, see below for an example how to do that with GenericSetup.
You can add your aggregation templates TTW in /portal_skins/custom/manage_main and add them to the registry in /portal_registry.
Search there for EasyNewsletter, you will find Products EasyNewsletter content_aggregation_templates
where you can add your templates.
To do it with your addon product, add this to your registry.xml in your profiles.
<record name="Products.EasyNewsletter.content_aggregation_templates">
<field type="plone.registry.field.Dict">
<title>ENL Content aggregation templates</title>
<key_type type="plone.registry.field.TextLine" />
<value_type type="plone.registry.field.TextLine" />
</field>
<value purge="false">
<element key="aggregation_fancy_pictures">Fancy pictures listing</element>
</value>
</record>
Output templates¶
We provide some output templates, but you can add more. A output template has to be global available template. The default templates are in the skins folder. They have to be registered in the Plone registry, see below for an example how to do that with GenericSetup.
You can add your output templates TTW in /portal_skins/custom/manage_main and add them to the registry in /portal_registry.
Search there for EasyNewsletter, you will find Products EasyNewsletter output_templates
where you can add your templates.
To do it with your addon product, add this to your registry.xml in your profiles.
<record name="Products.EasyNewsletter.output_templates">
<field type="plone.registry.field.Dict">
<title>ENL Output templates</title>
<key_type type="plone.registry.field.TextLine" />
<value_type type="plone.registry.field.TextLine" />
</field>
<value purge="false">
<element key="output_green_energy">Green energy output template</element>
</value>
</record>
Documentation¶
For more documentation please visit: http://packages.python.org/Products.EasyNewsletter/
Source Code¶
Authors¶
- initial release: Kai Dieffenbach
- Maik Derstappen
- Andreas Jung
- Philip Bauer
- Timo Stollenwerk
- Dinu Gherman
- Jens Klein
- Peter Holzer
Contents: