Send emails to users to remind them of expiring content
On state-change of the (custom) workflow to 'public', the following script (python) sets the ExpirationDate:
object = state_change.object
object.setExpirationDate(DateTime() + 31)
Given that we want to let our users know that the item will expire, we will send them an email. The ability to do that requires:
- A scheduling capability in Zope/Plone. I have chosen to use PloneMaintenance. Get it from http://plone.org/products/plonemaintenance and install in the normal way. PloneMaintenance allows you to schedule tasks that can then be activated by visiting a URL on the site. Because it will only run tasks that were sheduled to run anyway, there is no security issue.
- A script in PloneMaintenance. Go to portal_maintenance tool in the ZMI, to the 'scripts' tab and add a Script (Python). Replace the contents of the default script with the following, changing the details to suit your situation:
portal_url = context.portal_url
portal = portal_url.getPortalObject()
portal_catalog = context.portal_catalog
expired = []
# Notify all members of 'event-notification' 7 days and a second time 1 day ahead.
NotifyDaysAhead = 7,1
mtool = context.portal_membership
site_properties = context.portal_properties.site_properties
envelope_from = site_properties.email_from_address
# Change the following message to suit your use case
mMsg = """
Your item: %s, will expire as of %s.
If you no longer require this listing beyond that date, no action is required.
The listing will be deleted after a further 31 days.\n
If you wish to keep this listing on the site for a further 31 days, you can click the <relist> button on the listing.
You will need to log in to see the <relist> button. Your listing is at:
%s
%s.
"""
today = DateTime().Date() # returns a string yyyy/mm/dd
today = DateTime(today) # converts the string back to a date object
for days in NotifyDaysAhead:
# query portal catalog index for expiring items with a date range of 1 day
# and review_state='public' (this state is peculiar to my workflow)
# You will need to change the object type in the query to suit
query = {'portal_type':'IBItem',
'expires': {'query': (today+days,today+days+1),
'range': 'min:max'},
'review_state': 'public',
}
expired_brains = portal_catalog(query)
for brain in expired_brains:
obj = brain.getObject()
if obj is None:
continue
title = obj.Title()
owner = obj.Creator()
expiry = obj.ExpirationDate()
userObj = mtool.getMemberById(owner)
addressee = {'member':userObj,
'id':userObj.getId(),
'fullname':userObj.getProperty('fullname', 'Fullname missing'),
'email':userObj.getProperty('email', None)}
# This gives you a fullname too, so you could say "Dear Joe Bloggs" if you didn't think it cheesy...
if addressee['email'] != "":
mTo = addressee['email']
mFrom = "info@yourhost.com" #change this
mSubj = "Your item will expire"
obj_url = obj.absolute_url()
comments = "\n\nThank you for your support,\nWeb Site Administration"
message = mMsg % (title, expiry, obj_url, comments)
context.MailHost.simple_send(body=message, mto=mTo, mfrom=mFrom, subject=mSubj)
return 0- Create a 'task' in portal_maintenance. It will run at any time after it was scheduled to run. So if it is scheduled for 01:00 and cron runs every hour, it may run at 01:00 or 02:00. So probably best set it for 12:55 in this instance.
- Create a cron job to invoke the PloneMaintenance URL http://mysite.com/runMaintenanceTasks. See instructions from within the portal_maintenance tool - they are quite clear. You can run the cron job say hourly, and the script will only fire after it was due to be run anyway. I'm sure that using Windows Scheduler to go to http://mysite.com/runMaintenanceTasks will work equally well. Note that the URL in the email is relative to the referring URL, so don't use http://localhost:8080/mysite.runMaintenanceTasks, or your users will not be able to click the link.
- Test and enjoy.
- I have provided a 'relist' button on the items that gives the item another 31 days. This way I keep content fresh and don't inconvenience my users too much.
I'll post that here just for completeness sake:
In the form (in the 'custom' folder within portal_skins):
<div class="formControls">
<form action="update_expiration_date" method="get"
tal:condition="python: user.has_permission('Add portal content', here)
and (wtool.getInfoFor(here, 'review_state') =='public')">
<input class="standalone"
type="submit"
name="form.button.relist"
value="Relist"
i18n:attributes="value label_relist;" />
</form>
</div>
Calling a script (python) called update_expiration_date:
from Products.CMFPlone import PloneMessageFactory as _
request=context.REQUEST
if hasattr(request, 'form.button.relist'):
context.setExpirationDate(DateTime() + 31)
context.plone_utils.addPortalMessage(_(u'Item has been relisted'))
return request.RESPONSE.redirect(context.absolute_url() +'/view')

Author: