diff options
Diffstat (limited to 'Mailman/docs/hold.txt')
| -rw-r--r-- | Mailman/docs/hold.txt | 362 |
1 files changed, 0 insertions, 362 deletions
diff --git a/Mailman/docs/hold.txt b/Mailman/docs/hold.txt deleted file mode 100644 index a93953435..000000000 --- a/Mailman/docs/hold.txt +++ /dev/null @@ -1,362 +0,0 @@ -Holding messages -================ - -One of the most important functions of Mailman is to moderate messages by -holding some for approval before they will post to the mailing list. Messages -are held when they meet any of a number of criteria. - - >>> import os - >>> import errno - >>> from Mailman.Handlers.Hold import process - >>> from Mailman.queue import Switchboard - >>> from Mailman.configuration import config - >>> mlist = config.db.list_manager.create(u'_xtest@example.com') - >>> mlist.preferred_language = u'en' - >>> mlist.real_name = u'_XTest' - >>> # XXX This will almost certainly change once we've worked out the web - >>> # space layout for mailing lists now. - >>> mlist.web_page_url = u'http://lists.example.com/' - -Here's a helper function used when we don't care about what's in the virgin -queue or in the pending database. - - >>> switchboard = Switchboard(config.VIRGINQUEUE_DIR) - >>> def clear(): - ... for filebase in switchboard.files: - ... msg, msgdata = switchboard.dequeue(filebase) - ... switchboard.finish(filebase) - ... for holdfile in os.listdir(config.DATA_DIR): - ... if holdfile.startswith('heldmsg-'): - ... os.unlink(os.path.join(config.DATA_DIR, holdfile)) - ... try: - ... os.unlink(os.path.join(config.DATA_DIR, 'pending.db')) - ... except OSError, e: - ... if e.errno <> errno.ENOENT: - ... raise - - -Short circuiting ----------------- - -If the message metadata indicates that the message is pre-approved, then the -handler returns immediately. - - >>> msg = message_from_string("""\ - ... From: aperson@example.com - ... - ... An important message. - ... """) - >>> msgdata = {'approved': True} - >>> process(mlist, msg, msgdata) - >>> print msg.as_string() - From: aperson@example.com - <BLANKLINE> - An important message. - <BLANKLINE> - >>> msgdata - {'approved': True} - - -Administrivia -------------- - -Mailman scans parts of the message for administrivia, meaning text that looks -like an email command. This is to prevent people sending 'help' or -'subscribe' message, etc. to the list members. First, we enable the scanning -of administrivia for the list. - - >>> mlist.administrivia = True - >>> msg = message_from_string("""\ - ... From: aperson@example.com - ... Subject: unsubscribe - ... - ... """) - >>> process(mlist, msg, {}) - Traceback (most recent call last): - ... - Administrivia - >>> clear() - - -Maximum number of recipients ----------------------------- - -Mailman will hold messages that have more than a specified number of explicit -recipients. - - >>> mlist.max_num_recipients = 5 - >>> msg = message_from_string("""\ - ... From: aperson@example.com - ... To: _xtest@example.com, bperson@example.com - ... Cc: cperson@example.com - ... Cc: dperson@example.com (Dan Person) - ... To: Elly Q. Person <eperson@example.com> - ... - ... Hey folks! - ... """) - >>> process(mlist, msg, {}) - Traceback (most recent call last): - ... - TooManyRecipients - >>> clear() - - -Implicit destination --------------------- - -Mailman will hold messages that have implicit destination, meaning that the -mailing list's posting address isn't included in the explicit recipients. - - >>> mlist.require_explicit_destination = True - >>> mlist.acceptable_aliases = u'' - >>> msg = message_from_string("""\ - ... From: aperson@example.org - ... Subject: An implicit message - ... - ... """) - >>> process(mlist, msg, {}) - Traceback (most recent call last): - ... - ImplicitDestination - >>> clear() - -A message gated from NNTP will obviously have an implicit destination. Such -gated messages will not be held for implicit destination because it's assumed -that Mailman pulled it from the appropriate news group. - - >>> msgdata = {'fromusenet': True} - >>> process(mlist, msg, msgdata) - >>> print msg.as_string() - From: aperson@example.org - Subject: An implicit message - Message-ID: ... - X-Message-ID-Hash: ... - <BLANKLINE> - <BLANKLINE> - >>> print msgdata - {'fromusenet': True} - - -Suspicious headers ------------------- - -Suspicious headers are a way for Mailman to hold messages that match a -particular regular expression. This mostly historical feature is fairly -confusing to users, and the list attribute that controls this is misnamed. - - >>> mlist.bounce_matching_headers = u'From: .*person@(blah.)?example.com' - >>> msg = message_from_string("""\ - ... From: aperson@example.com - ... To: _xtest@example.com - ... Subject: An implicit message - ... - ... """) - >>> process(mlist, msg, {}) - Traceback (most recent call last): - ... - SuspiciousHeaders - >>> clear() - -But if the header doesn't match the regular expression, it'll get posted just -fine. This one comes from a .org address. - - >>> msg = message_from_string("""\ - ... From: aperson@example.org - ... To: _xtest@example.com - ... Subject: An implicit message - ... - ... """) - >>> msgdata = {} - >>> process(mlist, msg, msgdata) - >>> print msgdata - {} - -Just a bit of clean up. - - >>> mlist.bounce_matching_headers = None - - -Message size ------------- - -Mailman can hold messages that are bigger than a given size. Generally this -is used to prevent huge attachments from getting posted to the list. This -value is calculated in terms of KB (1024 bytes). - - >>> mlist.max_message_size = 1 - >>> one_line = 'x' * 79 - >>> big_body = '\n'.join([one_line] * 15) - >>> msg = message_from_string("""\ - ... From: aperson@example.com - ... To: _xtest@example.com - ... - ... """ + big_body) - >>> process(mlist, msg, {}) - Traceback (most recent call last): - ... - MessageTooBig - >>> clear() - - -Hold Notifications ------------------- - -Whenever Mailman holds a message, it sends notifications both to the list -owner and to the original sender, as long as it is configured to do so. We -can show this by first holding a message. - - >>> mlist.respond_to_post_requests = True - >>> mlist.admin_immed_notify = True - >>> msg = message_from_string("""\ - ... From: aperson@example.com - ... - ... """) - >>> process(mlist, msg, {}) - Traceback (most recent call last): - ... - ImplicitDestination - -There should be two messages in the virgin queue, one to the list owner and -one to the original author. - - >>> len(switchboard.files) - 2 - >>> qfiles = {} - >>> for filebase in switchboard.files: - ... qmsg, qdata = switchboard.dequeue(filebase) - ... switchboard.finish(filebase) - ... qfiles[qmsg['to']] = qmsg, qdata - >>> qmsg, qdata = qfiles['_xtest-owner@example.com'] - >>> print qmsg.as_string() - Subject: _xtest post from aperson@example.com requires approval - From: _xtest-owner@example.com - To: _xtest-owner@example.com - MIME-Version: 1.0 - Content-Type: multipart/mixed; boundary="..." - Message-ID: ... - Date: ... - Precedence: bulk - <BLANKLINE> - --... - Content-Type: text/plain; charset="us-ascii" - MIME-Version: 1.0 - Content-Transfer-Encoding: 7bit - <BLANKLINE> - As list administrator, your authorization is requested for the - following mailing list posting: - <BLANKLINE> - List: _xtest@example.com - From: aperson@example.com - Subject: (no subject) - Reason: Message has implicit destination - <BLANKLINE> - At your convenience, visit: - <BLANKLINE> - http://lists.example.com/admindb/_xtest@example.com - <BLANKLINE> - to approve or deny the request. - <BLANKLINE> - --... - Content-Type: message/rfc822 - MIME-Version: 1.0 - <BLANKLINE> - From: aperson@example.com - Message-ID: ... - X-Message-ID-Hash: ... - <BLANKLINE> - <BLANKLINE> - --... - Content-Type: message/rfc822 - MIME-Version: 1.0 - <BLANKLINE> - Content-Type: text/plain; charset="us-ascii" - MIME-Version: 1.0 - Content-Transfer-Encoding: 7bit - Subject: confirm ... - Sender: _xtest-request@example.com - From: _xtest-request@example.com - Date: ... - Message-ID: ... - <BLANKLINE> - If you reply to this message, keeping the Subject: header intact, - Mailman will discard the held message. Do this if the message is - spam. If you reply to this message and include an Approved: header - with the list password in it, the message will be approved for posting - to the list. The Approved: header can also appear in the first line - of the body of the reply. - --... - >>> sorted(qdata.items()) - [('_parsemsg', False), ('listname', u'_xtest@example.com'), - ('nodecorate', True), ('received_time', ...), - ('recips', [u'_xtest-owner@example.com']), - ('reduced_list_headers', True), - ('tomoderators', 1), ('version', 3)] - >>> qmsg, qdata = qfiles['aperson@example.com'] - >>> print qmsg.as_string() - MIME-Version: 1.0 - Content-Type: text/plain; charset="us-ascii" - Content-Transfer-Encoding: 7bit - Subject: Your message to _xtest awaits moderator approval - From: _xtest-bounces@example.com - To: aperson@example.com - Message-ID: ... - Date: ... - Precedence: bulk - <BLANKLINE> - Your mail to '_xtest' with the subject - <BLANKLINE> - (no subject) - <BLANKLINE> - Is being held until the list moderator can review it for approval. - <BLANKLINE> - The reason it is being held: - <BLANKLINE> - Message has implicit destination - <BLANKLINE> - Either the message will get posted to the list, or you will receive - notification of the moderator's decision. If you would like to cancel - this posting, please visit the following URL: - <BLANKLINE> - http://lists.example.com/confirm/_xtest@example.com/... - <BLANKLINE> - <BLANKLINE> - >>> sorted(qdata.items()) - [('_parsemsg', False), ('listname', u'_xtest@example.com'), - ('nodecorate', True), ('received_time', ...), - ('recips', [u'aperson@example.com']), - ('reduced_list_headers', True), ('version', 3)] - -In addition, the pending database is holding the original messages, waiting -for them to be disposed of by the original author or the list moderators. The -database is essentially a dictionary, with the keys being the randomly -selected tokens included in the urls and the values being a 2-tuple where the -first item is a type code and the second item is a message id. - - >>> import re - >>> cookie = None - >>> qmsg, qdata = qfiles['aperson@example.com'] - >>> for line in qmsg.get_payload().splitlines(): - ... mo = re.search('confirm/[^/]+/(?P<cookie>.*)$', line) - ... if mo: - ... cookie = mo.group('cookie') - ... break - >>> data = config.db.pendings.confirm(cookie) - >>> sorted(data.items()) - [(u'id', ...), (u'type', u'held message')] - -The message itself is held in the message store. - - >>> rkey, rdata = config.db.requests.get_list_requests(mlist).get_request( - ... data['id']) - >>> msg = config.db.message_store.get_message_by_id( - ... rdata['_mod_message_id']) - >>> print msg.as_string() - From: aperson@example.com - Message-ID: ... - X-Message-ID-Hash: ... - <BLANKLINE> - <BLANKLINE> - -Clean up. - - >>> clear() |
