diff options
| -rw-r--r-- | src/mailman/database/schema/postgres.sql | 8 | ||||
| -rw-r--r-- | src/mailman/database/schema/sqlite.sql | 8 | ||||
| -rw-r--r-- | src/mailman/docs/NEWS.rst | 14 | ||||
| -rw-r--r-- | src/mailman/interfaces/mailinglist.py | 171 | ||||
| -rw-r--r-- | src/mailman/model/mailinglist.py | 8 | ||||
| -rw-r--r-- | src/mailman/mta/docs/decorating.rst | 33 | ||||
| -rw-r--r-- | src/mailman/pipeline/decorate.py | 39 | ||||
| -rw-r--r-- | src/mailman/pipeline/docs/decorate.rst | 108 | ||||
| -rw-r--r-- | src/mailman/runners/digest.py | 43 | ||||
| -rw-r--r-- | src/mailman/styles/default.py | 19 | ||||
| -rw-r--r-- | src/mailman/templates/en/footer-generic.txt | 4 |
11 files changed, 349 insertions, 106 deletions
diff --git a/src/mailman/database/schema/postgres.sql b/src/mailman/database/schema/postgres.sql index 206f8f76f..b0a30bb78 100644 --- a/src/mailman/database/schema/postgres.sql +++ b/src/mailman/database/schema/postgres.sql @@ -48,8 +48,8 @@ CREATE TABLE mailinglist ( default_member_action INTEGER, default_nonmember_action INTEGER, description TEXT, - digest_footer TEXT, - digest_header TEXT, + digest_footer_uri TEXT, + digest_header_uri TEXT, digest_is_default BOOLEAN, digest_send_periodic BOOLEAN, digest_size_threshold REAL, @@ -59,12 +59,14 @@ CREATE TABLE mailinglist ( emergency BOOLEAN, encode_ascii_prefixes BOOLEAN, first_strip_reply_to BOOLEAN, + footer_uri TEXT, forward_auto_discards BOOLEAN, gateway_to_mail BOOLEAN, gateway_to_news BOOLEAN, generic_nonmember_action INTEGER, goodbye_message_uri TEXT, header_matches BYTEA, + header_uri TEXT, hold_these_nonmembers BYTEA, info TEXT, linked_newsgroup TEXT, @@ -74,8 +76,6 @@ CREATE TABLE mailinglist ( member_moderation_notice TEXT, mime_is_default_digest BOOLEAN, moderator_password TEXT, - msg_footer TEXT, - msg_header TEXT, new_member_options INTEGER, news_moderation INTEGER, news_prefix_subject_too BOOLEAN, diff --git a/src/mailman/database/schema/sqlite.sql b/src/mailman/database/schema/sqlite.sql index d5ef06f0f..ae5145d7a 100644 --- a/src/mailman/database/schema/sqlite.sql +++ b/src/mailman/database/schema/sqlite.sql @@ -144,8 +144,8 @@ CREATE TABLE mailinglist ( default_member_action INTEGER, default_nonmember_action INTEGER, description TEXT, - digest_footer TEXT, - digest_header TEXT, + digest_footer_uri TEXT, + digest_header_uri TEXT, digest_is_default BOOLEAN, digest_send_periodic BOOLEAN, digest_size_threshold FLOAT, @@ -155,12 +155,14 @@ CREATE TABLE mailinglist ( emergency BOOLEAN, encode_ascii_prefixes BOOLEAN, first_strip_reply_to BOOLEAN, + footer_uri TEXT, forward_auto_discards BOOLEAN, gateway_to_mail BOOLEAN, gateway_to_news BOOLEAN, generic_nonmember_action INTEGER, goodbye_message_uri TEXT, header_matches BLOB, + header_uri TEXT, hold_these_nonmembers BLOB, info TEXT, linked_newsgroup TEXT, @@ -170,8 +172,6 @@ CREATE TABLE mailinglist ( member_moderation_notice TEXT, mime_is_default_digest BOOLEAN, moderator_password TEXT, - msg_footer TEXT, - msg_header TEXT, new_member_options INTEGER, news_moderation INTEGER, news_prefix_subject_too BOOLEAN, diff --git a/src/mailman/docs/NEWS.rst b/src/mailman/docs/NEWS.rst index c1fdc948d..588642085 100644 --- a/src/mailman/docs/NEWS.rst +++ b/src/mailman/docs/NEWS.rst @@ -26,16 +26,21 @@ Architecture mailing list. The in-tree English templates are used only as a last fallback. * Support downloading templates by URI, including mailman:// URIs. This is - used in welcome and goodbye messages, and supports both language and - mailing list specifications. E.g. mailman:///test@example.com/it/welc.txt + used in welcome and goodbye messages, as well as regular and digest headers + and footers, and supports both language and mailing list specifications. + E.g. mailman:///test@example.com/it/welcome.txt Database -------- * Schema changes: - - welcome_msg -> welcome_message_uri - - goodbye_msg -> goodbye_message_uri + - welcome_msg -> welcome_message_uri + - goodbye_msg -> goodbye_message_uri - send_welcome_msg -> send_welcome_message - send_goodbye_msg -> send_goodbye_message + - msg_header -> header_uri + - msg_footer -> footer_uri + - digest_header -> digest_header_uri + - digest_footer -> digest_footer_uri REST ---- @@ -59,6 +64,7 @@ Interfaces argument to narrow the search for the given request. * New `ITemplateLoader` utility. * `ILanguageManager.add()` returns the `ILanguage` object just created. + * `IMailinglist.decorators` removed; it was unused Commands -------- diff --git a/src/mailman/interfaces/mailinglist.py b/src/mailman/interfaces/mailinglist.py index a7a964a06..4bd47a180 100644 --- a/src/mailman/interfaces/mailinglist.py +++ b/src/mailman/interfaces/mailinglist.py @@ -306,11 +306,6 @@ class IMailingList(Interface): digest recipients are cleared. """) - decorators = Attribute( - """An iterator over all the IDecorators associated with this digest. - When a digest is being sent, each decorator may modify the final - digest text.""") - # Web access. scheme = Attribute( @@ -334,24 +329,6 @@ class IMailingList(Interface): 'location' attribute. """ - # Notifications. - - admin_immed_notify = Attribute( - """Flag controlling immediate notification of requests. - - List moderators normally get daily notices about pending - administrative requests. This flag controls whether moderators also - receive immediate notification of such pending requests. - """) - - admin_notify_mchanges = Attribute( - """Flag controlling notification of joins and leaves. - - List moderators can receive notifications for every member that joins - or leaves their mailing lists. This flag controls those - notifications. - """) - # Autoresponses. autoresponse_grace_period = Attribute( @@ -518,13 +495,29 @@ class IMailingList(Interface): # Notifications. + admin_immed_notify = Attribute( + """Flag controlling immediate notification of requests. + + List moderators normally get daily notices about pending + administrative requests. This flag controls whether moderators also + receive immediate notification of such pending requests. + """) + + admin_notify_mchanges = Attribute( + """Flag controlling notification of joins and leaves. + + List moderators can receive notifications for every member that joins + or leaves their mailing lists. This flag controls those + notifications. + """) + send_welcome_message = Attribute( """Flag indicating whether a welcome message should be sent.""") welcome_message_uri = Attribute( """URI for the list's welcome message. - This can be any URI supported by `httplib2` with the addition of + This can be any URI supported by `urllib2` with the addition of `mailman:` URIs, which reference internal default resources. This is a template which can include the following placeholders: @@ -551,14 +544,14 @@ class IMailingList(Interface): goodbye_message_uri = Attribute( """URI for the list's goodbye message. - This can be any URI supported by `httplib2` with the addition of + This can be any URI supported by `urllib2` with the addition of `mailman:` URIs, which reference internal default resources. This is a template which can include the following placeholders: $listname - the FQDN list name for this mailing list. $language - the language code, usually the list's preferred language. - The resource will be downloaded and cached whenever the welcome + The resource will be downloaded and cached whenever the goodbye message is sent. The resource at this URI can contain the following placeholders, which are also filled in through values on the mailing list: @@ -572,6 +565,132 @@ class IMailingList(Interface): $user_options_uri - the URI to this member's options page. """) + # Decorators. + + header_uri = Attribute( + """URI for the header decorator on regular delivery messages. + + This can be any URI supported by `urllib2` with the addition of + `mailman:` URIs, which reference internal default resources. This is + a template which can include the following placeholders: + + $listname - the FQDN list name for this mailing list. + $language - the language code, usually the list's preferred language. + + The resource will be downloaded and cached whenever the decorator is + needed. The resource at this URI can contain the following + placeholders, which are also filled in through values on the mailing + list: + + $fqdn_listname - the FQDN list name for this mailing list. + $list_name - the human readable name for the mailing list. + $host_name - the mailing list's host name + $listinfo_uri - the URI to the list's information page. + $list_requests - the address to the list's `-request` address. + $description - the mailing list's description + $info - additional mailing list's information + + Personalized messages will also have these placeholders available: + + $user_name - the name of the subscribing user. + $user_address - the email address of the subscribing user. + $user_options_uri - the URI to this member's options page. + """ + ) + + footer_uri = Attribute( + """URI for the footer decorator on regular delivery messages. + + This can be any URI supported by `urllib2` with the addition of + `mailman:` URIs, which reference internal default resources. This is + a template which can include the following placeholders: + + $listname - the FQDN list name for this mailing list. + $language - the language code, usually the list's preferred language. + + The resource will be downloaded and cached whenever the decorator is + needed. The resource at this URI can contain the following + placeholders, which are also filled in through values on the mailing + list: + + $fqdn_listname - the FQDN list name for this mailing list. + $list_name - the human readable name for the mailing list. + $host_name - the mailing list's host name + $listinfo_uri - the URI to the list's information page. + $list_requests - the address to the list's `-request` address. + $description - the mailing list's description + $info - additional mailing list's information + + Personalized messages will also have these placeholders available: + + $user_name - the name of the subscribing user. + $user_address - the email address of the subscribing user. + $user_options_uri - the URI to this member's options page. + """ + ) + + digest_header_uri = Attribute( + """URI for the header decorator on digest messages. + + This can be any URI supported by `urllib2` with the addition of + `mailman:` URIs, which reference internal default resources. This is + a template which can include the following placeholders: + + $listname - the FQDN list name for this mailing list. + $language - the language code, usually the list's preferred language. + + The resource will be downloaded and cached whenever the decorator is + needed. The resource at this URI can contain the following + placeholders, which are also filled in through values on the mailing + list: + + $fqdn_listname - the FQDN list name for this mailing list. + $list_name - the human readable name for the mailing list. + $host_name - the mailing list's host name + $listinfo_uri - the URI to the list's information page. + $list_requests - the address to the list's `-request` address. + $description - the mailing list's description + $info - additional mailing list's information + + Personalized messages will also have these placeholders available: + + $user_name - the name of the subscribing user. + $user_address - the email address of the subscribing user. + $user_options_uri - the URI to this member's options page. + """ + ) + + digest_footer_uri = Attribute( + """URI for the footer decorator on digest messages. + + This can be any URI supported by `urllib2` with the addition of + `mailman:` URIs, which reference internal default resources. This is + a template which can include the following placeholders: + + $listname - the FQDN list name for this mailing list. + $language - the language code, usually the list's preferred language. + + The resource will be downloaded and cached whenever the decorator is + needed. The resource at this URI can contain the following + placeholders, which are also filled in through values on the mailing + list: + + $fqdn_listname - the FQDN list name for this mailing list. + $list_name - the human readable name for the mailing list. + $host_name - the mailing list's host name + $listinfo_uri - the URI to the list's information page. + $list_requests - the address to the list's `-request` address. + $description - the mailing list's description + $info - additional mailing list's information + + Personalized messages will also have these placeholders available: + + $user_name - the name of the subscribing user. + $user_address - the email address of the subscribing user. + $user_options_uri - the URI to this member's options page. + """ + ) + class IAcceptableAlias(Interface): diff --git a/src/mailman/model/mailinglist.py b/src/mailman/model/mailinglist.py index fd7410465..16596e6d2 100644 --- a/src/mailman/model/mailinglist.py +++ b/src/mailman/model/mailinglist.py @@ -132,8 +132,8 @@ class MailingList(Model): default_member_action = Enum(Action) default_nonmember_action = Enum(Action) description = Unicode() - digest_footer = Unicode() - digest_header = Unicode() + digest_footer_uri = Unicode() + digest_header_uri = Unicode() digest_is_default = Bool() digest_send_periodic = Bool() digest_size_threshold = Float() @@ -143,12 +143,14 @@ class MailingList(Model): emergency = Bool() encode_ascii_prefixes = Bool() first_strip_reply_to = Bool() + footer_uri = Unicode() forward_auto_discards = Bool() gateway_to_mail = Bool() gateway_to_news = Bool() generic_nonmember_action = Int() goodbye_message_uri = Unicode() header_matches = Pickle() + header_uri = Unicode() hold_these_nonmembers = Pickle() info = Unicode() linked_newsgroup = Unicode() @@ -158,8 +160,6 @@ class MailingList(Model): member_moderation_notice = Unicode() mime_is_default_digest = Bool() moderator_password = Unicode() - msg_footer = Unicode() - msg_header = Unicode() new_member_options = Int() news_moderation = Enum(NewsModeration) news_prefix_subject_too = Bool() diff --git a/src/mailman/mta/docs/decorating.rst b/src/mailman/mta/docs/decorating.rst index 05196eb78..44559edb3 100644 --- a/src/mailman/mta/docs/decorating.rst +++ b/src/mailman/mta/docs/decorating.rst @@ -21,20 +21,39 @@ Decorations Decorations are added when the mailing list had a header and/or footer defined, and the decoration handler is told to do personalized decorations. +We start by writing the site-global header and footer template. :: - >>> mlist = create_list('test@example.com') - >>> mlist.msg_header = """\ + >>> import os, tempfile + >>> template_dir = tempfile.mkdtemp() + >>> site_dir = os.path.join(template_dir, 'site', 'en') + >>> os.makedirs(site_dir) + >>> config.push('templates', """ + ... [paths.testing] + ... template_dir: {0} + ... """.format(template_dir)) + + >>> myheader_path = os.path.join(site_dir, 'myheader.txt') + >>> with open(myheader_path, 'w') as fp: + ... print >> fp, """\ ... Delivery address: $user_address ... Subscribed address: $user_delivered_to ... """ - - >>> mlist.msg_footer = """\ + >>> myfooter_path = os.path.join(site_dir, 'myfooter.txt') + >>> with open(myfooter_path, 'w') as fp: + ... print >> fp, """\ ... User name: $user_name ... Password: $user_password ... Language: $user_language ... Options: $user_optionsurl ... """ + +Then create a mailing list which will use this header and footer. Because +these are site-global templates, we can use a shorted URL. + + >>> mlist = create_list('test@example.com') + >>> mlist.header_uri = 'mailman:///myheader.txt' + >>> mlist.footer_uri = 'mailman:///myfooter.txt' >>> transaction.commit() @@ -201,3 +220,9 @@ into the message metadata. <BLANKLINE> This is a test. ---------- + +.. Clean up + + >>> config.pop('templates') + >>> import shutil + >>> shutil.rmtree(template_dir) diff --git a/src/mailman/pipeline/decorate.py b/src/mailman/pipeline/decorate.py index e7d011f84..a8fc340f8 100644 --- a/src/mailman/pipeline/decorate.py +++ b/src/mailman/pipeline/decorate.py @@ -29,12 +29,14 @@ import re import logging from email.mime.text import MIMEText +from urllib2 import URLError from zope.component import getUtility from zope.interface import implements from mailman.core.i18n import _ from mailman.email.message import Message from mailman.interfaces.handler import IHandler +from mailman.interfaces.templates import ITemplateLoader from mailman.interfaces.usermanager import IUserManager from mailman.utilities.string import expand @@ -66,8 +68,16 @@ def process(mlist, msg, msgdata): d['user_optionsurl'] = member.options_url # These strings are descriptive for the log file and shouldn't be i18n'd d.update(msgdata.get('decoration-data', {})) - header = decorate(mlist, mlist.msg_header, d) - footer = decorate(mlist, mlist.msg_footer, d) + try: + header = decorate(mlist, mlist.header_uri, d) + except URLError: + log.exception('Header decorator URI not found ({0}): {1}'.format( + mlist.fqdn_listname, mlist.header_uri)) + try: + footer = decorate(mlist, mlist.footer_uri, d) + except URLError: + log.exception('Footer decorator URI not found ({0}): {1}'.format( + mlist.fqdn_listname, mlist.footer_uri)) # Escape hatch if both the footer and header are empty if not header and not footer: return @@ -195,19 +205,28 @@ def process(mlist, msg, msgdata): -def decorate(mlist, template, extradict=None): +def decorate(mlist, uri, extradict=None): """Expand the decoration template.""" + if uri is None: + return '' + # Get the decorator template. + loader = getUtility(ITemplateLoader) + template_uri = expand(uri, dict( + listname=mlist.fqdn_listname, + language=mlist.preferred_language.code, + )) + template = loader.get(template_uri) # Create a dictionary which includes the default set of interpolation # variables allowed in headers and footers. These will be augmented by # any key/value pairs in the extradict. substitutions = dict( - real_name = mlist.real_name, - list_name = mlist.list_name, - fqdn_listname = mlist.fqdn_listname, - host_name = mlist.mail_host, - listinfo_page = mlist.script_url('listinfo'), - description = mlist.description, - info = mlist.info, + fqdn_listname = mlist.fqdn_listname, + list_name = mlist.real_name, + host_name = mlist.mail_host, + listinfo_uri = mlist.script_url('listinfo'), + list_requests = mlist.request_address, + description = mlist.description, + info = mlist.info, ) if extradict is not None: substitutions.update(extradict) diff --git a/src/mailman/pipeline/docs/decorate.rst b/src/mailman/pipeline/docs/decorate.rst index 1c94cff1e..e24e1e252 100644 --- a/src/mailman/pipeline/docs/decorate.rst +++ b/src/mailman/pipeline/docs/decorate.rst @@ -36,19 +36,42 @@ decorations are added for digest messages. Here is a message. -Decorating simple text messages -=============================== +Simple decorations +================== -Text messages that have no declared content type character set are by default, -encoded in us-ascii. When the mailing list's preferred language is ``en`` -(i.e. English), the character set of the mailing list and of the message will -match. In this case, and when the header and footer have no interpolation -placeholder variables, the message's payload will be prepended by the verbatim -header, and appended with the verbatim footer. +Message decorations are specified by URI and can be specialized by the mailing +list and language. Internal Mailman decorations can be referenced by using +the ``mailman://`` URL scheme. Here we create a simple English header and +footer for all mailing lists in our site. +:: + + >>> import os, tempfile + >>> template_dir = tempfile.mkdtemp() + >>> site_dir = os.path.join(template_dir, 'site', 'en') + >>> os.makedirs(site_dir) + >>> config.push('templates', """ + ... [paths.testing] + ... template_dir: {0} + ... """.format(template_dir)) + + >>> myheader_path = os.path.join(site_dir, 'myheader.txt') + >>> with open(myheader_path, 'w') as fp: + ... print >> fp, 'header' + >>> myfooter_path = os.path.join(site_dir, 'myfooter.txt') + >>> with open(myfooter_path, 'w') as fp: + ... print >> fp, 'footer' + +Setting these attributes on the mailing list causes it to use these +templates. Since these are site-global templates, we can use a shorter path. + + >>> mlist.header_uri = 'mailman:///myheader.txt' + >>> mlist.footer_uri = 'mailman:///myfooter.txt' + +Text messages that have no declared content type are, by default encoded in +ASCII. When the mailing list's preferred language is ``en`` (i.e. English), +the character set of the mailing list and of the message will match, allowing +Mailman to simply prepend the header and append the footer verbatim. - >>> msg = message_from_string(msg_text) - >>> mlist.msg_header = 'header\n' - >>> mlist.msg_footer = 'footer' >>> mlist.preferred_language = 'en' >>> process(mlist, msg, {}) >>> print msg.as_string() @@ -63,10 +86,14 @@ Mailman supports a number of interpolation variables, placeholders in the header and footer for information to be filled in with mailing list specific data. An example of such information is the mailing list's `real name` (a short descriptive name for the mailing list). +:: + + >>> with open(myheader_path, 'w') as fp: + ... print >> fp, '$list_name header' + >>> with open(myfooter_path, 'w') as fp: + ... print >> fp, '$list_name footer' >>> msg = message_from_string(msg_text) - >>> mlist.msg_header = '$real_name header\n' - >>> mlist.msg_footer = '$real_name footer' >>> mlist.real_name = 'XTest' >>> process(mlist, msg, {}) >>> print msg.as_string() @@ -78,10 +105,14 @@ short descriptive name for the mailing list). You can't just pick any interpolation variable though; if you do, the variable will remain in the header or footer unchanged. +:: + + >>> with open(myheader_path, 'w') as fp: + ... print >> fp, '$dummy header' + >>> with open(myfooter_path, 'w') as fp: + ... print >> fp, '$dummy footer' >>> msg = message_from_string(msg_text) - >>> mlist.msg_header = '$dummy header\n' - >>> mlist.msg_footer = '$dummy footer' >>> process(mlist, msg, {}) >>> print msg.as_string() From: aperson@example.org @@ -103,14 +134,18 @@ display in a proportional font. When Mailman sees text/plain messages with such RFC 3676 parameters, it preserves these parameters when it concatenates headers and footers to the message payload. +:: + + >>> with open(myheader_path, 'w') as fp: + ... print >> fp, 'header' + >>> with open(myfooter_path, 'w') as fp: + ... print >> fp, 'footer' - >>> mlist.msg_header = 'header' - >>> mlist.msg_footer = 'footer' >>> mlist.preferred_language = 'en' >>> msg = message_from_string("""\ ... From: aperson@example.org ... Content-Type: text/plain; format=flowed; delsp=no - ... + ... ... Here is a message\x20 ... with soft line breaks. ... """) @@ -120,14 +155,18 @@ message payload. >>> # message' line will be retained in the output. >>> print msg['content-type'] text/plain; format="flowed"; delsp="no"; charset="us-ascii" - >>> [line for line in msg.get_payload().splitlines()] - ['header', 'Here is a message ', 'with soft line breaks.', 'footer'] + >>> for line in msg.get_payload().splitlines(): + ... print '>{0}<'.format(line) + >header< + >Here is a message < + >with soft line breaks.< + >footer< Decorating mixed-charset messages ================================= -When a message has no explicit character set, it is assumed to be us-ascii. +When a message has no explicit character set, it is assumed to be ASCII. However, if the mailing list's preferred language has a different character set, Mailman will still try to concatenate the header and footer, but it will convert the text to utf-8 and base-64 encode the message payload. @@ -135,8 +174,11 @@ convert the text to utf-8 and base-64 encode the message payload. # 'ja' = Japanese; charset = 'euc-jp' >>> mlist.preferred_language = 'ja' - >>> mlist.msg_header = '$description header' - >>> mlist.msg_footer = '$description footer' + + >>> with open(myheader_path, 'w') as fp: + ... print >> fp, '$description header' + >>> with open(myfooter_path, 'w') as fp: + ... print >> fp, '$description footer' >>> mlist.description = '\u65e5\u672c\u8a9e' >>> from email.message import Message @@ -154,15 +196,19 @@ convert the text to utf-8 and base-64 encode the message payload. Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 <BLANKLINE> - 5pel5pys6KqeIGhlYWRlcgpGcmFuw6dhaXNlCuaXpeacrOiqniBmb290ZXI= + 5pel5pys6KqeIGhlYWRlcgpGcmFuw6dhaXNlCuaXpeacrOiqniBmb290ZXIK Sometimes the message even has an unknown character set. In this case, Mailman has no choice but to decorate the original message with MIME attachments. +:: >>> mlist.preferred_language = 'en' - >>> mlist.msg_header = 'header' - >>> mlist.msg_footer = 'footer' + >>> with open(myheader_path, 'w') as fp: + ... print >> fp, 'header' + >>> with open(myfooter_path, 'w') as fp: + ... print >> fp, 'footer' + >>> msg = message_from_string("""\ ... From: aperson@example.org ... Content-Type: text/plain; charset=unknown @@ -170,6 +216,7 @@ attachments. ... ... Here is a message. ... """) + >>> process(mlist, msg, {}) >>> msg.set_boundary('BOUNDARY') >>> print msg.as_string() @@ -211,9 +258,6 @@ When the outer part is ``multipart/mixed``, the header and footer can have a ``Content-Disposition`` of ``inline`` so that MUAs can display these headers as if they were simply concatenated. - >>> mlist.preferred_language = 'en' - >>> mlist.msg_header = 'header' - >>> mlist.msg_footer = 'footer' >>> part_1 = message_from_string("""\ ... From: aperson@example.org ... @@ -296,3 +340,9 @@ so that the header and footer can be added as attachments. <BLANKLINE> footer --BOUNDARY-- + +.. Clean up + + >>> config.pop('templates') + >>> import shutil + >>> shutil.rmtree(template_dir) diff --git a/src/mailman/runners/digest.py b/src/mailman/runners/digest.py index 82895be98..2730fc427 100644 --- a/src/mailman/runners/digest.py +++ b/src/mailman/runners/digest.py @@ -26,6 +26,7 @@ __all__ = [ import re +import logging # cStringIO doesn't support unicode. from StringIO import StringIO @@ -37,6 +38,7 @@ from email.mime.message import MIMEMessage from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from email.utils import formatdate, getaddresses, make_msgid +from urllib2 import URLError from mailman.config import config from mailman.core.errors import DiscardMessage @@ -50,6 +52,9 @@ from mailman.utilities.mailbox import Mailbox from mailman.utilities.string import oneline, wrap +log = logging.getLogger('mailman.error') + + class Digester: """Base digester class.""" @@ -85,7 +90,14 @@ class Digester: got_owner_email=mlist.owner_address, ) # Set things up for the table of contents. - self._header = decorate(mlist, mlist.digest_header) + if mlist.digest_header_uri is not None: + try: + self._header = decorate(mlist, mlist.digest_header_uri) + except URLError: + log.exception( + 'Digest header decorator URI not found ({0}): {1}'.format( + mlist.fqdn_listname, mlist.digest_header_uri)) + self._header = '' self._toc = StringIO() print >> self._toc, _("Today's Topics:\n") @@ -144,6 +156,7 @@ class Digester: + class MIMEDigester(Digester): """A MIME digester.""" @@ -154,7 +167,7 @@ class MIMEDigester(Digester): masthead['Content-Description'] = self._subject self._message.attach(masthead) # Add the optional digest header. - if mlist.digest_header: + if mlist.digest_header_uri is not None: header = MIMEText(self._header.encode(self._charset), _charset=self._charset) header['Content-Description'] = _('Digest Header') @@ -184,8 +197,16 @@ class MIMEDigester(Digester): def finish(self): """Finish up the digest, producing the email-ready copy.""" - if self._mlist.digest_footer: - footer_text = decorate(self._mlist, self._mlist.digest_footer) + if self._mlist.digest_footer_uri is not None: + try: + footer_text = decorate( + self._mlist, self._mlist.digest_footer_uri) + except URLError: + log.exception( + 'Digest footer decorator URI not found ({0}): {1}'.format( + self._mlist.fqdn_listname, + self._mlist.digest_footer_uri)) + footer_text = '' footer = MIMEText(footer_text.encode(self._charset), _charset=self._charset) footer['Content-Description'] = _('Digest Footer') @@ -211,7 +232,7 @@ class RFC1153Digester(Digester): print >> self._text, self._masthead print >> self._text # Add the optional digest header. - if mlist.digest_header: + if mlist.digest_header_uri is not None: print >> self._text, self._header print >> self._text # Calculate the set of headers we're to keep in the RFC1153 digest. @@ -262,8 +283,16 @@ class RFC1153Digester(Digester): def finish(self): """Finish up the digest, producing the email-ready copy.""" - if self._mlist.digest_footer: - footer_text = decorate(self._mlist, self._mlist.digest_footer) + if self._mlist.digest_footer_uri is not None: + try: + footer_text = decorate( + self._mlist, self._mlist.digest_footer_uri) + except URLError: + log.exception( + 'Digest footer decorator URI not found ({0}): {1}'.format( + self._mlist.fqdn_listname, + self._mlist.digest_footer_uri)) + footer_text = '' # This is not strictly conformant RFC 1153. The trailer is only # supposed to contain two lines, i.e. the "End of ... Digest" line # and the row of asterisks. If this screws up MUAs, the solution diff --git a/src/mailman/styles/default.py b/src/mailman/styles/default.py index 8d4ef83df..623bf1bc1 100644 --- a/src/mailman/styles/default.py +++ b/src/mailman/styles/default.py @@ -106,13 +106,9 @@ from: .*@uplinkpro.com mlist.mime_is_default_digest = False mlist.digest_size_threshold = 30 # KB mlist.digest_send_periodic = True - mlist.digest_header = '' - mlist.digest_footer = """\ -_______________________________________________ -$real_name mailing list -$fqdn_listname -${listinfo_page} -""" + mlist.digest_header_uri = None + mlist.digest_footer_uri = ( + 'mailman:///$listname/$language/footer-generic.txt') mlist.digest_volume_frequency = DigestFrequency.monthly mlist.next_digest_number = 1 mlist.nondigestable = True @@ -137,13 +133,8 @@ ${listinfo_page} # 2-tuple of the date of the last autoresponse and the number of # autoresponses sent on that date. mlist.subject_prefix = _('[$mlist.real_name] ') - mlist.msg_header = '' - mlist.msg_footer = """\ -_______________________________________________ -$real_name mailing list -$fqdn_listname -${listinfo_page} -""" + mlist.header_uri = None + mlist.footer_uri = 'mailman:///$listname/$language/footer-generic.txt' # Set this to Never if the list's preferred language uses us-ascii, # otherwise set it to As Needed. if mlist.preferred_language.charset == 'us-ascii': diff --git a/src/mailman/templates/en/footer-generic.txt b/src/mailman/templates/en/footer-generic.txt new file mode 100644 index 000000000..ef76e4986 --- /dev/null +++ b/src/mailman/templates/en/footer-generic.txt @@ -0,0 +1,4 @@ +_______________________________________________ +$list_name mailing list +$fqdn_listname +${listinfo_uri} |
