summaryrefslogtreecommitdiff
path: root/mailman/docs/requests.txt
diff options
context:
space:
mode:
Diffstat (limited to 'mailman/docs/requests.txt')
-rw-r--r--mailman/docs/requests.txt883
1 files changed, 0 insertions, 883 deletions
diff --git a/mailman/docs/requests.txt b/mailman/docs/requests.txt
deleted file mode 100644
index 87b835fb8..000000000
--- a/mailman/docs/requests.txt
+++ /dev/null
@@ -1,883 +0,0 @@
-Moderator requests
-==================
-
-Various actions will be held for moderator approval, such as subscriptions to
-closed lists, or postings by non-members. The requests database is the low
-level interface to these actions requiring approval.
-
-Here is a helper function for printing out held requests.
-
- >>> def show_holds(requests):
- ... for request in requests.held_requests:
- ... key, data = requests.get_request(request.id)
- ... print request.id, str(request.request_type), key
- ... if data is not None:
- ... for key in sorted(data):
- ... print ' {0}: {1}'.format(key, data[key])
-
-And another helper for displaying messages in the virgin queue.
-
- >>> virginq = config.switchboards['virgin']
- >>> def dequeue(whichq=None, expected_count=1):
- ... if whichq is None:
- ... whichq = virginq
- ... assert len(whichq.files) == expected_count, (
- ... 'Unexpected file count: %d' % len(whichq.files))
- ... filebase = whichq.files[0]
- ... qmsg, qdata = whichq.dequeue(filebase)
- ... whichq.finish(filebase)
- ... return qmsg, qdata
-
-
-Mailing list centric
---------------------
-
-A set of requests are always related to a particular mailing list, so given a
-mailing list you need to get its requests object.
-
- >>> from mailman.interfaces.requests import IListRequests, IRequests
- >>> from zope.interface.verify import verifyObject
- >>> verifyObject(IRequests, config.db.requests)
- True
- >>> mlist = config.db.list_manager.create(u'test@example.com')
- >>> requests = config.db.requests.get_list_requests(mlist)
- >>> verifyObject(IListRequests, requests)
- True
- >>> requests.mailing_list
- <mailing list "test@example.com" at ...>
-
-
-Holding requests
-----------------
-
-The list's requests database starts out empty.
-
- >>> requests.count
- 0
- >>> list(requests.held_requests)
- []
-
-At the lowest level, the requests database is very simple. Holding a request
-requires a request type (as an enum value), a key, and an optional dictionary
-of associated data. The request database assigns no semantics to the held
-data, except for the request type. Here we hold some simple bits of data.
-
- >>> from mailman.interfaces.requests import RequestType
- >>> id_1 = requests.hold_request(RequestType.held_message, u'hold_1')
- >>> id_2 = requests.hold_request(RequestType.subscription, u'hold_2')
- >>> id_3 = requests.hold_request(RequestType.unsubscription, u'hold_3')
- >>> id_4 = requests.hold_request(RequestType.held_message, u'hold_4')
- >>> id_1, id_2, id_3, id_4
- (1, 2, 3, 4)
-
-And of course, now we can see that there are four requests being held.
-
- >>> requests.count
- 4
- >>> requests.count_of(RequestType.held_message)
- 2
- >>> requests.count_of(RequestType.subscription)
- 1
- >>> requests.count_of(RequestType.unsubscription)
- 1
- >>> show_holds(requests)
- 1 RequestType.held_message hold_1
- 2 RequestType.subscription hold_2
- 3 RequestType.unsubscription hold_3
- 4 RequestType.held_message hold_4
-
-If we try to hold a request with a bogus type, we get an exception.
-
- >>> requests.hold_request(5, 'foo')
- Traceback (most recent call last):
- ...
- TypeError: 5
-
-We can hold requests with additional data.
-
- >>> data = dict(foo='yes', bar='no')
- >>> id_5 = requests.hold_request(RequestType.held_message, u'hold_5', data)
- >>> id_5
- 5
- >>> requests.count
- 5
- >>> show_holds(requests)
- 1 RequestType.held_message hold_1
- 2 RequestType.subscription hold_2
- 3 RequestType.unsubscription hold_3
- 4 RequestType.held_message hold_4
- 5 RequestType.held_message hold_5
- bar: no
- foo: yes
-
-
-Getting requests
-----------------
-
-We can ask the requests database for a specific request, by providing the id
-of the request data we want. This returns a 2-tuple of the key and data we
-originally held.
-
- >>> key, data = requests.get_request(2)
- >>> print key
- hold_2
-
-Because we did not store additional data with request 2, it comes back as None
-now.
-
- >>> print data
- None
-
-However, if we ask for a request that had data, we'd get it back now.
-
- >>> key, data = requests.get_request(5)
- >>> print key
- hold_5
- >>> dump_msgdata(data)
- bar: no
- foo: yes
-
-If we ask for a request that is not in the database, we get None back.
-
- >>> print requests.get_request(801)
- None
-
-
-Iterating over requests
------------------------
-
-To make it easier to find specific requests, the list requests can be iterated
-over by type.
-
- >>> requests.count_of(RequestType.held_message)
- 3
- >>> for request in requests.of_type(RequestType.held_message):
- ... assert request.request_type is RequestType.held_message
- ... key, data = requests.get_request(request.id)
- ... print request.id, key
- ... if data is not None:
- ... for key in sorted(data):
- ... print ' {0}: {1}'.format(key, data[key])
- 1 hold_1
- 4 hold_4
- 5 hold_5
- bar: no
- foo: yes
-
-
-Deleting requests
------------------
-
-Once a specific request has been handled, it will be deleted from the requests
-database.
-
- >>> requests.delete_request(2)
- >>> requests.count
- 4
- >>> show_holds(requests)
- 1 RequestType.held_message hold_1
- 3 RequestType.unsubscription hold_3
- 4 RequestType.held_message hold_4
- 5 RequestType.held_message hold_5
- bar: no
- foo: yes
- >>> print requests.get_request(2)
- None
-
-We get an exception if we ask to delete a request that isn't in the database.
-
- >>> requests.delete_request(801)
- Traceback (most recent call last):
- ...
- KeyError: 801
-
-For the next section, we first clean up all the current requests.
-
- >>> for request in requests.held_requests:
- ... requests.delete_request(request.id)
- >>> requests.count
- 0
-
-
-Application support
--------------------
-
-There are several higher level interfaces available in the mailman.app package
-which can be used to hold messages, subscription, and unsubscriptions. There
-are also interfaces for disposing of these requests in an application specific
-and consistent way.
-
- >>> from mailman.app import moderator
-
-
-Holding messages
-----------------
-
-For this section, we need a mailing list and at least one message.
-
- >>> mlist = config.db.list_manager.create(u'alist@example.com')
- >>> mlist.preferred_language = u'en'
- >>> mlist.real_name = u'A Test List'
- >>> msg = message_from_string("""\
- ... From: aperson@example.org
- ... To: alist@example.com
- ... Subject: Something important
- ...
- ... Here's something important about our mailing list.
- ... """)
-
-Holding a message means keeping a copy of it that a moderator must approve
-before the message is posted to the mailing list. To hold the message, you
-must supply the message, message metadata, and a text reason for the hold. In
-this case, we won't include any additional metadata.
-
- >>> id_1 = moderator.hold_message(mlist, msg, {}, 'Needs approval')
- >>> requests.get_request(id_1) is not None
- True
-
-We can also hold a message with some additional metadata.
-
- # Delete the Message-ID from the previous hold so we don't try to store
- # collisions in the message storage.
- >>> del msg['message-id']
- >>> msgdata = dict(sender='aperson@example.com',
- ... approved=True,
- ... received_time=123.45)
- >>> id_2 = moderator.hold_message(mlist, msg, msgdata, u'Feeling ornery')
- >>> requests.get_request(id_2) is not None
- True
-
-Once held, the moderator can select one of several dispositions. The most
-trivial is to simply defer a decision for now.
-
- >>> from mailman.interfaces import Action
- >>> moderator.handle_message(mlist, id_1, Action.defer)
- >>> requests.get_request(id_1) is not None
- True
-
-The moderator can also discard the message. This is often done with spam.
-Bye bye message!
-
- >>> moderator.handle_message(mlist, id_1, Action.discard)
- >>> print requests.get_request(id_1)
- None
- >>> virginq.files
- []
-
-The message can be rejected, meaning it is bounced back to the sender.
-
- >>> moderator.handle_message(mlist, id_2, Action.reject, 'Off topic')
- >>> print requests.get_request(id_2)
- None
- >>> qmsg, qdata = dequeue()
- >>> print qmsg.as_string()
- MIME-Version: 1.0
- Content-Type: text/plain; charset="us-ascii"
- Content-Transfer-Encoding: 7bit
- Subject: Request to mailing list "A Test List" rejected
- From: alist-bounces@example.com
- To: aperson@example.org
- Message-ID: ...
- Date: ...
- Precedence: bulk
- <BLANKLINE>
- Your request to the alist@example.com mailing list
- <BLANKLINE>
- Posting of your message titled "Something important"
- <BLANKLINE>
- has been rejected by the list moderator. The moderator gave the
- following reason for rejecting your request:
- <BLANKLINE>
- "Off topic"
- <BLANKLINE>
- Any questions or comments should be directed to the list administrator
- at:
- <BLANKLINE>
- alist-owner@example.com
- <BLANKLINE>
- >>> dump_msgdata(qdata)
- _parsemsg : False
- listname : alist@example.com
- nodecorate : True
- recips : [u'aperson@example.org']
- reduced_list_headers: True
- version : 3
-
-Or the message can be approved. This actually places the message back into
-the incoming queue for further processing, however the message metadata
-indicates that the message has been approved.
-
- >>> id_3 = moderator.hold_message(mlist, msg, msgdata, 'Needs approval')
- >>> moderator.handle_message(mlist, id_3, Action.accept)
- >>> inq = config.switchboards['in']
- >>> qmsg, qdata = dequeue(inq)
- >>> print qmsg.as_string()
- From: aperson@example.org
- To: alist@example.com
- Subject: Something important
- Message-ID: ...
- X-Message-ID-Hash: ...
- X-Mailman-Approved-At: ...
- <BLANKLINE>
- Here's something important about our mailing list.
- <BLANKLINE>
- >>> dump_msgdata(qdata)
- _parsemsg : False
- approved : True
- moderator_approved: True
- sender : aperson@example.com
- version : 3
-
-In addition to any of the above dispositions, the message can also be
-preserved for further study. Ordinarily the message is removed from the
-global message store after its disposition (though approved messages may be
-re-added to the message store). When handling a message, we can tell the
-moderator interface to also preserve a copy, essentially telling it not to
-delete the message from the storage. First, without the switch, the message
-is deleted.
-
- >>> msg = message_from_string("""\
- ... From: aperson@example.org
- ... To: alist@example.com
- ... Subject: Something important
- ... Message-ID: <12345>
- ...
- ... Here's something important about our mailing list.
- ... """)
- >>> id_4 = moderator.hold_message(mlist, msg, {}, 'Needs approval')
- >>> moderator.handle_message(mlist, id_4, Action.discard)
- >>> print config.db.message_store.get_message_by_id(u'<12345>')
- None
-
-But if we ask to preserve the message when we discard it, it will be held in
-the message store after disposition.
-
- >>> id_4 = moderator.hold_message(mlist, msg, {}, 'Needs approval')
- >>> moderator.handle_message(mlist, id_4, Action.discard, preserve=True)
- >>> stored_msg = config.db.message_store.get_message_by_id(u'<12345>')
- >>> print stored_msg.as_string()
- From: aperson@example.org
- To: alist@example.com
- Subject: Something important
- Message-ID: <12345>
- X-Message-ID-Hash: 4CF7EAU3SIXBPXBB5S6PEUMO62MWGQN6
- <BLANKLINE>
- Here's something important about our mailing list.
- <BLANKLINE>
-
-Orthogonal to preservation, the message can also be forwarded to another
-address. This is helpful for getting the message into the inbox of one of the
-moderators.
-
- # Set a new Message-ID from the previous hold so we don't try to store
- # collisions in the message storage.
- >>> del msg['message-id']
- >>> msg['Message-ID'] = u'<abcde>'
- >>> id_4 = moderator.hold_message(mlist, msg, {}, 'Needs approval')
- >>> moderator.handle_message(mlist, id_4, Action.discard,
- ... forward=[u'zperson@example.com'])
- >>> qmsg, qdata = dequeue()
- >>> print qmsg.as_string()
- Subject: Forward of moderated message
- From: alist-bounces@example.com
- To: zperson@example.com
- MIME-Version: 1.0
- Content-Type: message/rfc822
- Message-ID: ...
- Date: ...
- Precedence: bulk
- <BLANKLINE>
- From: aperson@example.org
- To: alist@example.com
- Subject: Something important
- Message-ID: <abcde>
- X-Message-ID-Hash: EN2R5UQFMOUTCL44FLNNPLSXBIZW62ER
- <BLANKLINE>
- Here's something important about our mailing list.
- <BLANKLINE>
- >>> dump_msgdata(qdata)
- _parsemsg : False
- listname : alist@example.com
- nodecorate : True
- recips : [u'zperson@example.com']
- reduced_list_headers: True
- version : 3
-
-
-Holding subscription requests
------------------------------
-
-For closed lists, subscription requests will also be held for moderator
-approval. In this case, several pieces of information related to the
-subscription must be provided, including the subscriber's address and real
-name, their password (possibly hashed), what kind of delivery option they are
-chosing and their preferred language.
-
- >>> from mailman.interfaces.member import DeliveryMode
- >>> mlist.admin_immed_notify = False
- >>> id_3 = moderator.hold_subscription(mlist,
- ... u'bperson@example.org', u'Ben Person',
- ... u'{NONE}abcxyz', DeliveryMode.regular, u'en')
- >>> requests.get_request(id_3) is not None
- True
-
-In the above case the mailing list was not configured to send the list
-moderators a notice about the hold, so no email message is in the virgin
-queue.
-
- >>> virginq.files
- []
-
-But if we set the list up to notify the list moderators immediately when a
-message is held for approval, there will be a message placed in the virgin
-queue when the message is held.
-
- >>> mlist.admin_immed_notify = True
- >>> # XXX This will almost certainly change once we've worked out the web
- >>> # space layout for mailing lists now.
- >>> id_4 = moderator.hold_subscription(mlist,
- ... u'cperson@example.org', u'Claire Person',
- ... u'{NONE}zyxcba', DeliveryMode.regular, u'en')
- >>> requests.get_request(id_4) is not None
- True
- >>> qmsg, qdata = dequeue()
- >>> print qmsg.as_string()
- MIME-Version: 1.0
- Content-Type: text/plain; charset="us-ascii"
- Content-Transfer-Encoding: 7bit
- Subject: New subscription request to list A Test List from
- cperson@example.org
- From: alist-owner@example.com
- To: alist-owner@example.com
- Message-ID: ...
- Date: ...
- Precedence: bulk
- <BLANKLINE>
- Your authorization is required for a mailing list subscription request
- approval:
- <BLANKLINE>
- For: cperson@example.org
- List: alist@example.com
- <BLANKLINE>
- At your convenience, visit:
- <BLANKLINE>
- http://lists.example.com/admindb/alist@example.com
- <BLANKLINE>
- to process the request.
- <BLANKLINE>
- >>> dump_msgdata(qdata)
- _parsemsg : False
- listname : alist@example.com
- nodecorate : True
- recips : [u'alist-owner@example.com']
- reduced_list_headers: True
- tomoderators : True
- version : 3
-
-Once held, the moderator can select one of several dispositions. The most
-trivial is to simply defer a decision for now.
-
- >>> moderator.handle_subscription(mlist, id_3, Action.defer)
- >>> requests.get_request(id_3) is not None
- True
-
-The held subscription can also be discarded.
-
- >>> moderator.handle_subscription(mlist, id_3, Action.discard)
- >>> print requests.get_request(id_3)
- None
-
-The request can be rejected, in which case a message is sent to the
-subscriber.
-
- >>> moderator.handle_subscription(mlist, id_4, Action.reject,
- ... 'This is a closed list')
- >>> print requests.get_request(id_4)
- None
- >>> qmsg, qdata = dequeue()
- >>> print qmsg.as_string()
- MIME-Version: 1.0
- Content-Type: text/plain; charset="us-ascii"
- Content-Transfer-Encoding: 7bit
- Subject: Request to mailing list "A Test List" rejected
- From: alist-bounces@example.com
- To: cperson@example.org
- Message-ID: ...
- Date: ...
- Precedence: bulk
- <BLANKLINE>
- Your request to the alist@example.com mailing list
- <BLANKLINE>
- Subscription request
- <BLANKLINE>
- has been rejected by the list moderator. The moderator gave the
- following reason for rejecting your request:
- <BLANKLINE>
- "This is a closed list"
- <BLANKLINE>
- Any questions or comments should be directed to the list administrator
- at:
- <BLANKLINE>
- alist-owner@example.com
- <BLANKLINE>
- >>> dump_msgdata(qdata)
- _parsemsg : False
- listname : alist@example.com
- nodecorate : True
- recips : [u'cperson@example.org']
- reduced_list_headers: True
- version : 3
-
-The subscription can also be accepted. This subscribes the address to the
-mailing list.
-
- >>> mlist.send_welcome_msg = True
- >>> id_4 = moderator.hold_subscription(mlist,
- ... u'fperson@example.org', u'Frank Person',
- ... u'{NONE}abcxyz', DeliveryMode.regular, u'en')
-
-A message will be sent to the moderators telling them about the held
-subscription and the fact that they may need to approve it.
-
- >>> qmsg, qdata = dequeue()
- >>> print qmsg.as_string()
- MIME-Version: 1.0
- Content-Type: text/plain; charset="us-ascii"
- Content-Transfer-Encoding: 7bit
- Subject: New subscription request to list A Test List from
- fperson@example.org
- From: alist-owner@example.com
- To: alist-owner@example.com
- Message-ID: ...
- Date: ...
- Precedence: bulk
- <BLANKLINE>
- Your authorization is required for a mailing list subscription request
- approval:
- <BLANKLINE>
- For: fperson@example.org
- List: alist@example.com
- <BLANKLINE>
- At your convenience, visit:
- <BLANKLINE>
- http://lists.example.com/admindb/alist@example.com
- <BLANKLINE>
- to process the request.
- <BLANKLINE>
- >>> dump_msgdata(qdata)
- _parsemsg : False
- listname : alist@example.com
- nodecorate : True
- recips : [u'alist-owner@example.com']
- reduced_list_headers: True
- tomoderators : True
- version : 3
-
-Accept the subscription request.
-
- >>> mlist.admin_notify_mchanges = True
- >>> moderator.handle_subscription(mlist, id_4, Action.accept)
-
-There are now two messages in the virgin queue. One is a welcome message
-being sent to the user and the other is a subscription notification that is
-sent to the moderators. The only good way to tell which is which is to look
-at the recipient list.
-
- >>> qmsg_1, qdata_1 = dequeue(expected_count=2)
- >>> qmsg_2, qdata_2 = dequeue()
- >>> if 'fperson@example.org' in qdata_1['recips']:
- ... # The first message is the welcome message
- ... welcome_qmsg = qmsg_1
- ... welcome_qdata = qdata_1
- ... admin_qmsg = qmsg_2
- ... admin_qdata = qdata_2
- ... else:
- ... welcome_qmsg = qmsg_2
- ... welcome_qdata = qdata_2
- ... admin_qmsg = qmsg_1
- ... admin_qdata = qdata_1
-
-The welcome message is sent to the person who just subscribed.
-
- >>> print welcome_qmsg.as_string()
- MIME-Version: 1.0
- Content-Type: text/plain; charset="us-ascii"
- Content-Transfer-Encoding: 7bit
- Subject: Welcome to the "A Test List" mailing list
- From: alist-request@example.com
- To: fperson@example.org
- X-No-Archive: yes
- Message-ID: ...
- Date: ...
- Precedence: bulk
- <BLANKLINE>
- Welcome to the "A Test List" mailing list!
- <BLANKLINE>
- To post to this list, send your email to:
- <BLANKLINE>
- alist@example.com
- <BLANKLINE>
- General information about the mailing list is at:
- <BLANKLINE>
- http://lists.example.com/listinfo/alist@example.com
- <BLANKLINE>
- 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:
- <BLANKLINE>
- http://example.com/fperson@example.org
- <BLANKLINE>
- You can also make such adjustments via email by sending a message to:
- <BLANKLINE>
- alist-request@example.com
- <BLANKLINE>
- 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 change your options, but for security purposes,
- this email is not included here. There is also a button on your
- options page that will send your current password to you.
- <BLANKLINE>
- >>> dump_msgdata(welcome_qdata)
- _parsemsg : False
- listname : alist@example.com
- nodecorate : True
- recips : [u'fperson@example.org']
- reduced_list_headers: True
- verp : False
- version : 3
-
-The admin message is sent to the moderators.
-
- >>> print admin_qmsg.as_string()
- MIME-Version: 1.0
- Content-Type: text/plain; charset="us-ascii"
- Content-Transfer-Encoding: 7bit
- Subject: A Test List subscription notification
- From: changeme@example.com
- To: alist-owner@example.com
- Message-ID: ...
- Date: ...
- Precedence: bulk
- <BLANKLINE>
- Frank Person <fperson@example.org> has been successfully subscribed to
- A Test List.
- <BLANKLINE>
- >>> dump_msgdata(admin_qdata)
- _parsemsg : False
- envsender : changeme@example.com
- listname : alist@example.com
- nodecorate : True
- recips : []
- reduced_list_headers: True
- version : 3
-
-Frank Person is now a member of the mailing list.
-
- >>> member = mlist.members.get_member(u'fperson@example.org')
- >>> member
- <Member: Frank Person <fperson@example.org>
- on alist@example.com as MemberRole.member>
- >>> member.preferred_language
- u'en'
- >>> print member.delivery_mode
- DeliveryMode.regular
- >>> user = config.db.user_manager.get_user(member.address.address)
- >>> user.real_name
- u'Frank Person'
- >>> user.password
- u'{NONE}abcxyz'
-
-
-Holding unsubscription requests
--------------------------------
-
-Some lists, though it is rare, require moderator approval for unsubscriptions.
-In this case, only the unsubscribing address is required. Like subscriptions,
-unsubscription holds can send the list's moderators an immediate notification.
-
- >>> mlist.admin_immed_notify = False
- >>> from mailman.interfaces.member import MemberRole
- >>> user_1 = config.db.user_manager.create_user(u'gperson@example.com')
- >>> address_1 = list(user_1.addresses)[0]
- >>> address_1.subscribe(mlist, MemberRole.member)
- <Member: gperson@example.com on alist@example.com as MemberRole.member>
- >>> user_2 = config.db.user_manager.create_user(u'hperson@example.com')
- >>> address_2 = list(user_2.addresses)[0]
- >>> address_2.subscribe(mlist, MemberRole.member)
- <Member: hperson@example.com on alist@example.com as MemberRole.member>
- >>> id_5 = moderator.hold_unsubscription(mlist, u'gperson@example.com')
- >>> requests.get_request(id_5) is not None
- True
- >>> virginq.files
- []
- >>> mlist.admin_immed_notify = True
- >>> id_6 = moderator.hold_unsubscription(mlist, u'hperson@example.com')
- >>> qmsg, qdata = dequeue()
- >>> print qmsg.as_string()
- MIME-Version: 1.0
- Content-Type: text/plain; charset="us-ascii"
- Content-Transfer-Encoding: 7bit
- Subject: New unsubscription request from A Test List by hperson@example.com
- From: alist-owner@example.com
- To: alist-owner@example.com
- Message-ID: ...
- Date: ...
- Precedence: bulk
- <BLANKLINE>
- Your authorization is required for a mailing list unsubscription
- request approval:
- <BLANKLINE>
- By: hperson@example.com
- From: alist@example.com
- <BLANKLINE>
- At your convenience, visit:
- <BLANKLINE>
- http://lists.example.com/admindb/alist@example.com
- <BLANKLINE>
- to process the request.
- <BLANKLINE>
- >>> dump_msgdata(qdata)
- _parsemsg : False
- listname : alist@example.com
- nodecorate : True
- recips : [u'alist-owner@example.com']
- reduced_list_headers: True
- tomoderators : True
- version : 3
-
-There are now two addresses with held unsubscription requests. As above, one
-of the actions we can take is to defer to the decision.
-
- >>> moderator.handle_unsubscription(mlist, id_5, Action.defer)
- >>> requests.get_request(id_5) is not None
- True
-
-The held unsubscription can also be discarded, and the member will remain
-subscribed.
-
- >>> moderator.handle_unsubscription(mlist, id_5, Action.discard)
- >>> print requests.get_request(id_5)
- None
- >>> mlist.members.get_member(u'gperson@example.com')
- <Member: gperson@example.com on alist@example.com as MemberRole.member>
-
-The request can be rejected, in which case a message is sent to the member,
-and the person remains a member of the mailing list.
-
- >>> moderator.handle_unsubscription(mlist, id_6, Action.reject,
- ... 'This list is a prison.')
- >>> print requests.get_request(id_6)
- None
- >>> qmsg, qdata = dequeue()
- >>> print qmsg.as_string()
- MIME-Version: 1.0
- Content-Type: text/plain; charset="us-ascii"
- Content-Transfer-Encoding: 7bit
- Subject: Request to mailing list "A Test List" rejected
- From: alist-bounces@example.com
- To: hperson@example.com
- Message-ID: ...
- Date: ...
- Precedence: bulk
- <BLANKLINE>
- Your request to the alist@example.com mailing list
- <BLANKLINE>
- Unsubscription request
- <BLANKLINE>
- has been rejected by the list moderator. The moderator gave the
- following reason for rejecting your request:
- <BLANKLINE>
- "This list is a prison."
- <BLANKLINE>
- Any questions or comments should be directed to the list administrator
- at:
- <BLANKLINE>
- alist-owner@example.com
- <BLANKLINE>
- >>> dump_msgdata(qdata)
- _parsemsg : False
- listname : alist@example.com
- nodecorate : True
- recips : [u'hperson@example.com']
- reduced_list_headers: True
- version : 3
-
- >>> mlist.members.get_member(u'hperson@example.com')
- <Member: hperson@example.com on alist@example.com as MemberRole.member>
-
-The unsubscription request can also be accepted. This removes the member from
-the mailing list.
-
- >>> mlist.send_goodbye_msg = True
- >>> mlist.goodbye_msg = u'So long!'
- >>> mlist.admin_immed_notify = False
- >>> id_7 = moderator.hold_unsubscription(mlist, u'gperson@example.com')
- >>> moderator.handle_unsubscription(mlist, id_7, Action.accept)
- >>> print mlist.members.get_member(u'gperson@example.com')
- None
-
-There are now two messages in the virgin queue, one to the member who was just
-unsubscribed and another to the moderators informing them of this membership
-change.
-
- >>> qmsg_1, qdata_1 = dequeue(expected_count=2)
- >>> qmsg_2, qdata_2 = dequeue()
- >>> if 'gperson@example.com' in qdata_1['recips']:
- ... # The first message is the goodbye message
- ... goodbye_qmsg = qmsg_1
- ... goodbye_qdata = qdata_1
- ... admin_qmsg = qmsg_2
- ... admin_qdata = qdata_2
- ... else:
- ... goodbye_qmsg = qmsg_2
- ... goodbye_qdata = qdata_2
- ... admin_qmsg = qmsg_1
- ... admin_qdata = qdata_1
-
-The goodbye message...
-
- >>> print goodbye_qmsg.as_string()
- MIME-Version: 1.0
- Content-Type: text/plain; charset="us-ascii"
- Content-Transfer-Encoding: 7bit
- Subject: You have been unsubscribed from the A Test List mailing list
- From: alist-bounces@example.com
- To: gperson@example.com
- Message-ID: ...
- Date: ...
- Precedence: bulk
- <BLANKLINE>
- So long!
- <BLANKLINE>
- >>> dump_msgdata(goodbye_qdata)
- _parsemsg : False
- listname : alist@example.com
- nodecorate : True
- recips : [u'gperson@example.com']
- reduced_list_headers: True
- verp : False
- version : 3
-
-...and the admin message.
-
- >>> print admin_qmsg.as_string()
- MIME-Version: 1.0
- Content-Type: text/plain; charset="us-ascii"
- Content-Transfer-Encoding: 7bit
- Subject: A Test List unsubscription notification
- From: changeme@example.com
- To: alist-owner@example.com
- Message-ID: ...
- Date: ...
- Precedence: bulk
- <BLANKLINE>
- gperson@example.com has been removed from A Test List.
- <BLANKLINE>
- >>> dump_msgdata(admin_qdata)
- _parsemsg : False
- envsender : changeme@example.com
- listname : alist@example.com
- nodecorate : True
- recips : []
- reduced_list_headers: True
- version : 3