diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/mailman/commands/cli_inject.py | 13 | ||||
| -rw-r--r-- | src/mailman/commands/cli_members.py | 21 | ||||
| -rw-r--r-- | src/mailman/commands/docs/members.txt | 37 | ||||
| -rw-r--r-- | src/mailman/config/schema.cfg | 15 | ||||
| -rw-r--r-- | src/mailman/mta/connection.py | 5 | ||||
| -rw-r--r-- | src/mailman/mta/docs/connection.txt | 41 |
6 files changed, 121 insertions, 11 deletions
diff --git a/src/mailman/commands/cli_inject.py b/src/mailman/commands/cli_inject.py index 025dcb036..8b7570e0a 100644 --- a/src/mailman/commands/cli_inject.py +++ b/src/mailman/commands/cli_inject.py @@ -60,13 +60,12 @@ class Inject: help=_('Show a list of all available queue names and exit.')) command_parser.add_argument( '-f', '--filename', - type='string', help=_(""" + type=unicode, help=_(""" Name of file containing the message to inject. If not given, or - '-' (without the quotes) standard input is used. - """)) + '-' (without the quotes) standard input is used.""")) # Required positional argument. command_parser.add_argument( - 'listname', metavar='LISTNAME', nargs='?', + 'listname', metavar='LISTNAME', nargs=1, help=_("""\ The 'fully qualified list name', i.e. the posting address of the mailing list to inject the message into.""")) @@ -97,7 +96,11 @@ class Inject: self.parser.error(_('No such queue: $queue')) return if args.filename in (None, '-'): - message_text = sys.stdin.read() + try: + message_text = sys.stdin.read() + except KeyboardInterrupt: + print 'Interrupted' + sys.exit(1) else: with open(args.filename) as fp: message_text = fp.read() diff --git a/src/mailman/commands/cli_members.py b/src/mailman/commands/cli_members.py index b26216785..213bb7a2c 100644 --- a/src/mailman/commands/cli_members.py +++ b/src/mailman/commands/cli_members.py @@ -37,7 +37,7 @@ from mailman.config import config from mailman.core.i18n import _ from mailman.interfaces.command import ICLISubCommand from mailman.interfaces.listmanager import IListManager -from mailman.interfaces.member import DeliveryMode +from mailman.interfaces.member import AlreadySubscribedError, DeliveryMode @@ -53,8 +53,10 @@ class Members: command_parser.add_argument( '-a', '--add', dest='filename', - help=_('Add all member addresses in FILENAME. FILENAME can be ' - "'-' to indicate standard input.")) + help=_("""\ + Add all member addresses in FILENAME. FILENAME can be '-' to + indicate standard input. Blank lines and lines That start with a + '#' are ignored.""")) # Required positional argument. command_parser.add_argument( 'listname', metavar='LISTNAME', nargs=1, @@ -78,14 +80,23 @@ class Members: fp = codecs.open(args.filename, 'r', 'utf-8') try: for line in fp: + # Ignore blank lines and lines that start with a '#'. + if line.startswith('#') or len(line.strip()) == 0: + continue real_name, email = parseaddr(line) # If not given in the input data, parseaddr() will return the # empty string, as opposed to the empty unicode. We need a # unicode real name here. if real_name == '': real_name = u'' - add_member(mlist, email, real_name, None, - DeliveryMode.regular, mlist.preferred_language.code) + try: + add_member(mlist, email, real_name, None, + DeliveryMode.regular, + mlist.preferred_language.code) + except AlreadySubscribedError: + # It's okay if the address is already subscribed, just + # print a warning and continue. + print 'Already subscribed (skipping):', email, real_name finally: if fp is not sys.stdin: fp.close() diff --git a/src/mailman/commands/docs/members.txt b/src/mailman/commands/docs/members.txt index 9872b9ff0..aea76dad8 100644 --- a/src/mailman/commands/docs/members.txt +++ b/src/mailman/commands/docs/members.txt @@ -57,3 +57,40 @@ taken from standard input. >>> sorted(address.address for address in mlist.members.addresses) [u'aperson@example.com', u'bperson@example.com', u'cperson@example.com', u'dperson@example.com', u'eperson@example.com', u'fperson@example.com'] + +Blank lines and lines that begin with '#' are ignored. + + >>> with open(path, 'w') as fp: + ... for address in ('gperson@example.com', + ... '# hperson@example.com', + ... ' ', + ... '', + ... 'iperson@example.com', + ... ): + ... print >> fp, address + + >>> args.filename = path + >>> command.process(args) + >>> sorted(address.address for address in mlist.members.addresses) + [u'aperson@example.com', u'bperson@example.com', u'cperson@example.com', + u'dperson@example.com', u'eperson@example.com', u'fperson@example.com', + u'gperson@example.com', u'iperson@example.com'] + +Addresses which are already subscribed are ignored, although a warning is +printed. + + >>> with open(path, 'w') as fp: + ... for address in ('gperson@example.com', + ... 'aperson@example.com', + ... 'jperson@example.com', + ... ): + ... print >> fp, address + + >>> command.process(args) + Already subscribed (skipping): gperson@example.com + Already subscribed (skipping): aperson@example.com + + >>> sorted(address.address for address in mlist.members.addresses) + [u'aperson@example.com', u'bperson@example.com', u'cperson@example.com', + u'dperson@example.com', u'eperson@example.com', u'fperson@example.com', + u'gperson@example.com', u'iperson@example.com', u'jperson@example.com'] diff --git a/src/mailman/config/schema.cfg b/src/mailman/config/schema.cfg index 00df3849b..36e736345 100644 --- a/src/mailman/config/schema.cfg +++ b/src/mailman/config/schema.cfg @@ -21,6 +21,13 @@ # options. See <https://launchpad.net/lazr.config> for details. [mailman] +# Setting devmode to true enables certain safeguards and other behavior +# changes that make developing Mailman easier. For example, it forces the +# SMTP RCPT TO recipients to be a test address so that no messages are +# accidentally sent to real addresses. All devmode variables in other +# sections begin with 'devmode_' for easy searching. +devmode: false + # This address is the "site owner" address. Certain messages which must be # delivered to a human, but which can't be delivered to a list owner (e.g. a # bounce from a list owner), will be sent to this address. It should point to @@ -261,10 +268,16 @@ chain: hold [mta] +# Set this to an address to force the SMTP RCPT TO recipents when devmode is +# enabled. This way messages can't be accidentally sent to real addresses. +devmode_recipient: + # The class defining the interface to the incoming mail transport agent. incoming: mailman.mta.postfix.LMTP -# The class defining the interface to the outgoing mail transport agent. +# The callable implementing delivery to the outgoing mail transport agent. +# This must accept three arguments, the mailing list, the message, and the +# message metadata dictionary. outgoing: mailman.mta.deliver.deliver # How to connect to the outgoing MTA. diff --git a/src/mailman/mta/connection.py b/src/mailman/mta/connection.py index 105d25afb..36af7a06e 100644 --- a/src/mailman/mta/connection.py +++ b/src/mailman/mta/connection.py @@ -28,6 +28,7 @@ __all__ = [ import logging import smtplib +from lazr.config import as_boolean from mailman.config import config @@ -66,6 +67,10 @@ class Connection: def sendmail(self, envsender, recips, msgtext): """Mimic `smtplib.SMTP.sendmail`.""" + if as_boolean(config.mailman.devmode): + # Force the recipients to the specified address, but still deliver + # to the same number of recipients. + recips = [config.mta.devmode_recipient] * len(recips) if self._connection is None: self._connect() try: diff --git a/src/mailman/mta/docs/connection.txt b/src/mailman/mta/docs/connection.txt index 8924826c8..c79120eba 100644 --- a/src/mailman/mta/docs/connection.txt +++ b/src/mailman/mta/docs/connection.txt @@ -155,3 +155,44 @@ the server. >>> smtpd.get_connection_count() 1 + + +Development mode +================ + +By putting Mailman into development mode, you can force the recipients to a +given hard-coded address. This allows you to test Mailman without worrying +about accidental deliveries to unintended recipients. + + >>> config.push('devmode', """ + ... [mailman] + ... devmode: true + ... [mta] + ... devmode_recipient: zperson@example.com + ... """) + + >>> smtpd.clear() + >>> connection.sendmail( + ... 'anne@example.com', + ... ['bart@example.com', 'cate@example.com'], """\ + ... From: anne@example.com + ... To: bart@example.com + ... Subject: aardvarks + ... + ... """) + {} + + >>> messages = list(smtpd.messages) + >>> len(messages) + 1 + >>> print messages[0].as_string() + From: anne@example.com + To: bart@example.com + Subject: aardvarks + X-Peer: ... + X-MailFrom: anne@example.com + X-RcptTo: zperson@example.com, zperson@example.com + <BLANKLINE> + <BLANKLINE> + + >>> config.pop('devmode') |
