gs.content.email.base
¶
Author: | Michael JasonSmith |
---|---|
Contact: | Michael JasonSmith <mpj17@onlinegroups.net> |
Date: | 2015-07-24 |
Organization: | GroupServer.org |
Copyright: | This document is licensed under a Creative Commons Attribution-Share Alike 4.0 International License by OnlineGroups.Net. |
Contents:
Skinning¶
For GroupServer installations with only one site then skinning is simple: the email messages will be skinned using the same skin-name as is used on the web (see the documentation on configuring a web proxy and GroupServer).
See also
GroupServer ships with two alternate skins by default gs.skin.blue and gs.skin.green.
Skinning is more difficult for complex installs where multiple sites with different skins are handled by the same server. Below we discuss the problem and the solution.
The problem¶
The problem is that email comes into one site, so the request
object for all email uses the skin for that site. This is fine if
all sites in the GroupServer install use the same skin. However,
this is an issue if different sites use different skins, as the
email messages will look like they are from the wrong site.
The solution¶
The solution is to label the site with the skin-name. This skin
is then retrieved and applied to the request
object. (The
zope.traversing
subsystem does this for web-requests.)
The skin-name is recorded in the emailSkin
property of the
DivisionConfig
object, or the GlobalConfiguration
object
(the former over-rides the latter). Set this property to the skin
name, such as gs_green
for the GroupServer green skin, or
gs_blue
for the blue skin. (The default is grey.) While you
could use a different skin from that used on the web, this is
discourage because it is likely to confuse the members of your
site.
gs.content.email.base
API¶
There are two main parts to the API for
gs.content.email.base
. The notifiers coordinate the
rendering and sending of the message, while the message bodies
(plural) define it.
Notifiers¶
All the notifiers inherit from the NotifierABC
abstract
base-class. However, if a notification is going to someone who
does not have a profile (they are anonymous) then an anonymous
notifier is used.
Anonymous notifier¶
The anonymous notifier provides some methods that are useful for creating an email message that is sent to someone that has no profile.
Examples¶
The Digest on notifier
(gs.group.member.email.settings.notifier.DigestOnNotifier
)
first inherits from the abstract base-class and defines the names
of the two pages that will render the HTML and plain-text
versions of the pages.
The notify
method defines the subject (which is translated
using zope.i18n.translate()
) and then renders the
plain-text and HTML versions of the email body.
Finally, the gs.profile.notify.MessageSender
class is
used to send the notification to the relevant person. It is this
class that actually constructs the email message out of the two
bodies, and the subject, before sending it off. Finally the
Content-type
is reset.
class DigestOnNotifier(GroupNotifierABC):
htmlTemplateName = 'gs-group-member-email-settings-digest-on.html'
textTemplateName = 'gs-group-member-email-settings-digest-on.txt'
def notify(self, userInfo):
subject = _('digest-on-subject',
'Topic digests from ${groupName}',
mapping={'groupName': self.groupInfo.name})
translatedSubject = translate(subject)
text = self.textTemplate()
html = self.htmlTemplate()
sender = MessageSender(self.context, userInfo)
sender.send_message(translatedSubject, text, html)
self.reset_content_type()
The Not a member notification
(gs.group.member.leave.notifier.NotMemberNotifier
) is
sent to someone when he or she tries to leave a group but they
are not a member. Initially it is very similar to a standard
notification, except the From
address is generated. Also more
values are passed to the templates because they are less able to
use the context to determine the values. Then
AnonymousNotifierABC.createMessage()
is used to generate
the method, before the message is sent using
gs.email.send_email()
.
class NotMemberNotifier(AnonymousNotifierABC):
htmlTemplateName = 'gs-group-member-leave-not-a-member.html'
textTemplateName = 'gs-group-member-leave-not-a-member.txt'
def notify(self, groupInfo, toEmailAddress):
fromAddr = self.fromAddr(groupInfo.siteInfo)
subject = _('leave-request-problem-subject',
'Request to leave ${groupName}',
mapping={'groupName': groupInfo.name})
translatedSubject = translate(subject)
html = self.htmlTemplate(emailAddress=toEmailAddress,
groupName=groupInfo.name,
groupURL=groupInfo.url)
text = self.textTemplate(emailAddress=toEmailAddress,
groupName=groupInfo.name,
groupURL=groupInfo.url)
message = self.create_message(toEmailAddress, fromAddr,
translatedSubject, text, html)
send_email(groupInfo.siteInfo.get_support_email(),
toEmailAddress, message)
self.reset_content_type()
Message bodies¶
There are two views. Site email is analogous to the
SitePage
[1], while group email is the
email-equivalent of GroupPage
[2]. However, both
views over-write the __call__
method.
The __call__
method of a page is called to produce the
rendered form of the view. Both views defined here take the
output from the super-class and run it through
premailer.transform
[3] before returning it. This
results in HTML that can be sent as a MIME-attachment.
Site email¶
The SiteEmail
class is used by messages made from
outside the Group context. For example:
<browser:page
name="notification.html"
for="Products.GSContent.interfaces.IGSSiteFolder"
class="gs.content.email.base.SiteEmail"
template="browser/templates/notification.pt"
permission="zope2.View"/>
Group email¶
The GroupEmail
class is a subclass of
SiteEmail
that is used by messages made from within the
Group context. For example:
<browser:page
name="notification.html"
for="gs.group.base.interfaces.IGSGroupMarker"
class="gs.content.email.base.GroupEmail"
template="browser/templates/notification.pt"
permission="zope2.View"/>
In addition to the siteInfo
attribute, this class defines the
groupInfo
attribute, which contains the name, URL, and ID of
the current group.
Text bodies¶
The plain-text version of the email bodies are supported by a mixin.
Example¶
The Left notification is sent to a group administrator when a
member leaves a group. It is, for the most-part, simple except
for the get_support_email()
method.
Notifications typically end with a link to email the support
group. This mailto:
normally fills the Subject
(providing
a standard topic in the support-group) and body of the message
(providing information that the person seeking support may forget
to provide). The Subject
and body
are translated using
zope.i18n.translate()
, and assembled into a mailto:
URI
using the SiteEmail.mailto()
method.
class LeftHTMLNotification(GroupEmail):
'The notification to the administrator that a member has left'
def __init__(self, group, request):
super(LeftHTMLNotification, self).__init__(group, request)
self.group = group
def get_support_email(self, user, admin):
subject = _('support-notification-member-left-subject',
'A member left my group')
translatedSubject = translate(subject)
uu = '{}{}'.format(self.siteInfo.url, user.url)
au = '{}{}'.format(self.siteInfo.url, admin.url)
body = _('support-notification-member-left-body',
'Hello,\n\nA member left my group, ${groupName}, and...'
'\n\n--\nThese links may be useful:\n'
' Group ${groupUrl}\n'
' Me ${adminUrl}\n'
' Member ${userUrl}\n',
mapping={'groupName': self.groupInfo.name,
'groupUrl': self.groupInfo.url,
'adminUrl': au, 'userUrl': uu})
translatedBody = translate(body)
retval = self.mailto(self.siteInfo.get_support_email(),
translatedSubject, translatedBody)
return retval
The plain-text version of the same body is provided by the
TextMixin
class. It does little other than generating a
filename for the page, and setting the correct header.
class LeftTXTNotification(LeftHTMLNotification, TextMixin):
def __init__(self, group, request):
super(LeftTXTNotification, self).__init__(group, request)
filename = 'left-{0}-{1}.txt'.format(self.siteInfo.id,
self.groupInfo.id)
self.set_header(filename)
[1] | See <https://github.com/groupserver/gs.content.base/> |
[2] | See <https://github.com/groupserver/gs.group.base/> |
[3] | See <https://pypi.python.org/pypi/premailer/> |
Changelog¶
2.3.4 (2015-12-11)¶
- Fixing the unit-tests
2.3.3 (2015-10-16)¶
- Using
gs.core.mailto
to construct the mailto
2.3.2 (2015-09-21)¶
- Using
subject
rather thanSubject
inmailto:
URIs
2.3.1 (2015-09-17)¶
- Fixing the colour codes for IBM Notes, based on a hack by Eli Dickinson
2.3.0 (2015-09-16)¶
- Extending the look up of the skin name — so it uses the
GlobalConfiguration
object as well as theDivisionConfiguration
object
2.2.0 (2015-07-24)¶
- Improving support for GroupServer installs with multiple sites,
by looking up the skin name in the
emailSkin
property of theDivisionConfig
object
2.1.3 (2015-06-02)¶
- Keeping the CSS classes when processing the notification
2.1.2 (2015-04-23)¶
- Dropping the
lxml
dependency, as I now understand that the style element sometimes appears for the styles that cannot be in-lined
2.1.1 (2014-11-10)¶
- Changing the logging-level for
cssutils
toCRITICAL
, thanks to the answer by Felix Carmona on Stack Overflow
2.1.0 (2014-09-15)¶
- Added some Sphinx documentation
- Added the abstract base-classes for the notifiers:
NotifierABC
GroupNotifierABC
AnonymousNotifierABC
- Added
SiteEmail.mailto()
2.0.0 (2014-05-29)¶
- Added unit tests
- Switched to Unicode literals
- Fixed the code for generating
<base>
element inSiteEmail
1.1.2 (2014-02-20)¶
- Fixing the HTTP headers when viewing the plain text notification
- Following
to_unicode_or_bust
togs.core
1.1.1 (2013-10-23)¶
- Fixing the arguments and keyword arguments to the page template
1.1.0 (2013-10-10)¶
- Added the
TextMixin
class - Pass the arguments and keyword arguments to the super-class
- Better handling of plain-text and Unicode
1.0.0 (2013-08-26)¶
- Initial version
This product — in combination with the
gs.content.email.layout
and gs.content.email.css
—
provides support for HTML-formatted email messages going out from
GroupServer. The HTML in the page templates fills in areas
defined by the layout
module. The page is then styled by the
css
module. This module coordinates the process, providing
the code to processes the resulting HTML and CSS into a message
that can be sent by email. (The actual sending is done by either
the gs.email.send_email()
function, or the
gs.profile.notify.MessageSender
class.)
Resources¶
- Documentation: https://groupserver.readthedocs.org/projects/gscontentemailbase/
- Code repository: https://github.com/groupserver/gs.content.email.base/
- Questions and comments to http://groupserver.org/groups/development
- Report bugs at https://redmine.iopen.net/projects/groupserver