Commit fe855654 authored by Barry Warsaw's avatar Barry Warsaw

- Test welcome message notifications.

- welcome.txt is no longer inserted into subscribeack.txt.  This latter is
  renamed to welcome.txt as the default welcome message.
parent 15ffdccf
......@@ -27,15 +27,23 @@ __all__ = [
import logging
from email.utils import formataddr
from lazr.config import as_boolean
from urllib2 import URLError
from zope.component import getUtility
from mailman.config import config
from mailman.core.i18n import _
from import OwnerNotification, UserNotification
from mailman.interfaces.member import DeliveryMode
from mailman.interfaces.templates import ITemplateLoader
from mailman.utilities.i18n import make
from mailman.utilities.string import wrap
from mailman.utilities.string import expand, wrap
log = logging.getLogger('mailman.error')
......@@ -50,12 +58,20 @@ def send_welcome_message(mlist, address, language, delivery_mode, text=''):
:param address: The address to respond to
:type address: string
:param language: the language of the response
:type language: string
:type language: ILanguage
:param delivery_mode: the type of delivery the subscriber is getting
:type delivery_mode: DeliveryMode
if mlist.welcome_message_uri:
welcome = wrap(mlist.welcome_message_uri) + '\n'
welcome_message = getUtility(ITemplateLoader).get(
except URLError:
log.exception('Welcome message URI not found ({0}): {1}'.format(
mlist.fqdn_listname, mlist.welcome_message_uri))
welcome = ''
welcome = wrap(welcome_message)
welcome = ''
# Find the IMember object which is subscribed to the mailing list, because
......@@ -63,16 +79,15 @@ def send_welcome_message(mlist, address, language, delivery_mode, text=''):
member = mlist.members.get_member(address)
options_url = member.options_url
# Get the text from the template.
text += make('subscribeack.txt',
text = expand(welcome, dict(
if delivery_mode is not DeliveryMode.regular:
digmode = _(' (Digest mode)')
......@@ -52,7 +52,7 @@ class MailmanHandler(urllib2.BaseHandler):
# Parse the full requested URL and be sure it's something we handle.
original_url = req.get_full_url()
parsed = urlparse(original_url)
assert(parsed.scheme == 'mailman')
assert parsed.scheme == 'mailman'
# The path can contain one, two, or three components. Since no empty
# path components are legal, filter them out.
parts = filter(None, parsed.path.split('/'))
# Copyright (C) 2012 by the Free Software Foundation, Inc.
# This file is part of GNU Mailman.
# GNU Mailman is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
# You should have received a copy of the GNU General Public License along with
# GNU Mailman. If not, see <>.
"""Test notifications."""
from __future__ import absolute_import, print_function, unicode_literals
__metaclass__ = type
__all__ = [
import os
import shutil
import tempfile
import unittest
from zope.component import getUtility
from import create_list
from import add_member
from import send_welcome_message
from mailman.config import config
from mailman.interfaces.languages import ILanguageManager
from mailman.interfaces.member import DeliveryMode
from mailman.testing.helpers import get_queue_messages
from mailman.testing.layers import ConfigLayer
class TestNotifications(unittest.TestCase):
"""Test notifications."""
layer = ConfigLayer
def setUp(self):
self._mlist = create_list('[email protected]')
self._mlist.welcome_message_uri = 'mailman:///welcome.txt'
self._mlist.real_name = 'Test List'
self.var_dir = tempfile.mkdtemp()
config.push('template config', """\
template_dir: {0}/templates
# Populate the template directories with a few fake templates.
path = os.path.join(self.var_dir, 'templates', 'site', 'en')
with open(os.path.join(path, 'welcome.txt'), 'w') as fp:
Welcome to the $list_name mailing list.
Posting address: $fqdn_listname
Help and other requests: $list_requests
Your name: $user_name
Your address: $user_address
Your options: $user_options_uri""", file=fp)
def tearDown(self):
config.pop('template config')
def test_welcome_message(self):
en = getUtility(ILanguageManager).get('en')
add_member(self._mlist, '[email protected]', 'Anne Person',
'password', DeliveryMode.regular, 'en')
send_welcome_message(self._mlist, '[email protected]', en,
# Now there's one message in the virgin queue.
messages = get_queue_messages('virgin')
self.assertEqual(len(messages), 1)
message = messages[0].msg
'Welcome to the "Test List" mailing list')
eq = self.assertMultiLineEqual
except AttributeError:
# Python 2.6
eq = self.assertEqual
eq(message.get_payload(), """\
Welcome to the Test List mailing list.
Posting address: [email protected]
Help and other requests: [email protected]
Your name: Anne Person
Your address: [email protected]
Your options:[email protected]
......@@ -541,6 +541,7 @@ The subscription can also be accepted. This subscribes the address to the
mailing list.
>>> mlist.send_welcome_message = True
>>> mlist.welcome_message_uri = 'mailman:///welcome.txt'
>>> id_4 = moderator.hold_subscription(mlist,
... '[email protected]', 'Frank Person',
... 'abcxyz', DeliveryMode.regular, 'en')
......@@ -99,7 +99,7 @@ all the writable attributes in one request.
... collapse_alternatives=False,
... reply_goes_to_list='point_to_list',
... send_welcome_message=False,
... welcome_message_uri='Welcome!',
... welcome_message_uri='mailman:///welcome.txt',
... default_member_action='hold',
... default_nonmember_action='discard',
... generic_nonmember_action=2,
......@@ -148,7 +148,7 @@ These values are changed permanently.
send_welcome_message: False
welcome_message_uri: Welcome!
welcome_message_uri: mailman:///welcome.txt
If you use ``PUT`` to change a list's configuration, all writable attributes
must be included. It is an error to leave one or more out...
Welcome to the "$real_name" mailing list!
Welcome to the "$list_name" mailing list!
To post to this list, send your email to:
General information about the mailing list is at:
If you ever want to unsubscribe or change your options (eg, switch to or
from digest mode, change your password, etc.), visit your subscription
page at:
You can also make such adjustments via email by sending a message to:
with the word 'help' in the subject or body (don't include the quotes), and
you will get back a message with instructions. You will need your password to
......@@ -58,20 +58,20 @@ def search(template_file, mlist=None, language=None):
"""Generator that provides file system search order.
This is Mailman's internal template search algorithm. The first locations
searched are within the $var_dir/templates directory, allowing a site to
searched are within the $template_dir directory, allowing a site to
override a template for a specific mailing list, all the mailing lists in
a domain, or site-wide.
The <language> path component is variable, and described below.
* The list-specific language directory
* The domain-specific language directory
* The site-wide language directory
The <language> path component is calculated as follows, in this order:
......@@ -86,21 +86,21 @@ def search(template_file, mlist=None, language=None):
is 'de' and the `language` parameter is 'it', these locations are searched
in order:
* <var_dir>/templates/lists/[email protected]/it/foo.txt
* <var_dir>/templates/domains/
* <var_dir>/templates/site/it/foo.txt
* $template_dir/lists/[email protected]/it/foo.txt
* $template_dir/domains/
* $template_dir/site/it/foo.txt
* <var_dir>/templates/lists/[email protected]/de/foo.txt
* <var_dir>/templates/domains/
* <var_dir>/templates/site/de/foo.txt
* $template_dir/lists/[email protected]/de/foo.txt
* $template_dir/domains/
* $template_dir/site/de/foo.txt
* <var_dir>/templates/lists/[email protected]/fr/foo.txt
* <var_dir>/templates/domains/
* <var_dir>/templates/site/fr/foo.txt
* $template_dir/lists/[email protected]/fr/foo.txt
* $template_dir/domains/
* $template_dir/site/fr/foo.txt
* <var_dir>/templates/lists/[email protected]/en/foo.txt
* <var_dir>/templates/domains/
* <var_dir>/templates/site/en/foo.txt
* $template_dir/lists/[email protected]/en/foo.txt
* $template_dir/domains/
* $template_dir/site/en/foo.txt
After all those paths are searched, the final fallback is the English
template within the Mailman source tree.
......@@ -114,13 +114,13 @@ def search(template_file, mlist=None, language=None):
if language is not None:
# The non-language qualified $var_dir paths in search order.
paths = [os.path.join(config.VAR_DIR, 'templates', 'site')]
# The non-language qualified $template_dir paths in search order.
paths = [os.path.join(config.TEMPLATE_DIR, 'site')]
if mlist is not None:
config.VAR_DIR, 'templates', 'domains', mlist.mail_host))
config.TEMPLATE_DIR, 'domains', mlist.mail_host))
config.VAR_DIR, 'templates', 'lists', mlist.fqdn_listname))
config.TEMPLATE_DIR, 'lists', mlist.fqdn_listname))
for language, path in product(languages, paths):
yield os.path.join(path, language, template_file)
......@@ -197,7 +197,7 @@ def wrap(text, column=70, honor_leading_ws=True):
add_paragraph_break = False
paragraph_text = EMPTYSTRING.join(paragraph)
# Just copy the blank lines to the final set of paragraphs.
if paragraph == NL:
if len(paragraph) == 0 or paragraph == NL:
# Choose the wrapper based on whether the paragraph is indented or
# not. Also, do not wrap indented paragraphs if honor_leading_ws is
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment