diff options
Diffstat (limited to 'mailman/docs/registration.txt')
| -rw-r--r-- | mailman/docs/registration.txt | 362 |
1 files changed, 0 insertions, 362 deletions
diff --git a/mailman/docs/registration.txt b/mailman/docs/registration.txt deleted file mode 100644 index d243188bc..000000000 --- a/mailman/docs/registration.txt +++ /dev/null @@ -1,362 +0,0 @@ -Address registration -==================== - -When a user wants to join a mailing list -- any mailing list -- in the running -instance, he or she must first register with Mailman. The only thing they -must supply is an email address, although there is additional information they -may supply. All registered email addresses must be verified before Mailman -will send them any list traffic. - - >>> from mailman.app.registrar import Registrar - >>> from mailman.interfaces.registrar import IRegistrar - -The IUserManager manages users, but it does so at a fairly low level. -Specifically, it does not handle verifications, email address syntax validity -checks, etc. The IRegistrar is the interface to the object handling all this -stuff. - -Add a domain, which will provide the context for the verification email -message. - - >>> config.push('mail', """ - ... [domain.mail_example_dot_com] - ... email_host: mail.example.com - ... base_url: http://mail.example.com - ... contact_address: postmaster@mail.example.com - ... """) - - >>> domain = config.domains['mail.example.com'] - -Get a registrar by adapting a context to the interface. - - >>> from zope.interface.verify import verifyObject - >>> registrar = IRegistrar(domain) - >>> verifyObject(IRegistrar, registrar) - True - -Here is a helper function to check the token strings. - - >>> def check_token(token): - ... assert isinstance(token, basestring), 'Not a string' - ... assert len(token) == 40, 'Unexpected length: %d' % len(token) - ... assert token.isalnum(), 'Not alphanumeric' - ... print 'ok' - -Here is a helper function to extract tokens from confirmation messages. - - >>> import re - >>> cre = re.compile('http://mail.example.com/confirm/(.*)') - >>> def extract_token(msg): - ... mo = cre.search(qmsg.get_payload()) - ... return mo.group(1) - - -Invalid email addresses ------------------------ - -The only piece of information you need to register is the email address. -Some amount of sanity checks are performed on the email address, although -honestly, not as much as probably should be done. Still, some patently bad -addresses are rejected outright. - - >>> registrar.register('') - Traceback (most recent call last): - ... - InvalidEmailAddress: '' - >>> registrar.register('some name@example.com') - Traceback (most recent call last): - ... - InvalidEmailAddress: 'some name@example.com' - >>> registrar.register('<script>@example.com') - Traceback (most recent call last): - ... - InvalidEmailAddress: '<script>@example.com' - >>> registrar.register('\xa0@example.com') - Traceback (most recent call last): - ... - InvalidEmailAddress: '\xa0@example.com' - >>> registrar.register('noatsign') - Traceback (most recent call last): - ... - InvalidEmailAddress: 'noatsign' - >>> registrar.register('nodom@ain') - Traceback (most recent call last): - ... - InvalidEmailAddress: 'nodom@ain' - - -Register an email address -------------------------- - -Registration of an unknown address creates nothing until the confirmation step -is complete. No IUser or IAddress is created at registration time, but a -record is added to the pending database, and the token for that record is -returned. - - >>> token = registrar.register(u'aperson@example.com', u'Anne Person') - >>> check_token(token) - ok - -There should be no records in the user manager for this address yet. - - >>> usermgr = config.db.user_manager - >>> print usermgr.get_user(u'aperson@example.com') - None - >>> print usermgr.get_address(u'aperson@example.com') - None - -But this address is waiting for confirmation. - - >>> pendingdb = config.db.pendings - >>> sorted(pendingdb.confirm(token, expunge=False).items()) - [(u'address', u'aperson@example.com'), - (u'real_name', u'Anne Person'), - (u'type', u'registration')] - - -Verification by email ---------------------- - -There is also a verification email sitting in the virgin queue now. This -message is sent to the user in order to verify the registered address. - - >>> switchboard = config.switchboards['virgin'] - >>> len(switchboard.files) - 1 - >>> filebase = switchboard.files[0] - >>> qmsg, qdata = switchboard.dequeue(filebase) - >>> switchboard.finish(filebase) - >>> print qmsg.as_string() - MIME-Version: 1.0 - Content-Type: text/plain; charset="us-ascii" - Content-Transfer-Encoding: 7bit - Subject: confirm ... - From: confirm-...@mail.example.com - To: aperson@example.com - Message-ID: <...> - Date: ... - Precedence: bulk - <BLANKLINE> - Email Address Registration Confirmation - <BLANKLINE> - Hello, this is the GNU Mailman server at mail.example.com. - <BLANKLINE> - We have received a registration request for the email address - <BLANKLINE> - aperson@example.com - <BLANKLINE> - Before you can start using GNU Mailman at this site, you must first - confirm that this is your email address. You can do this by replying to - this message, keeping the Subject header intact. Or you can visit this - web page - <BLANKLINE> - http://mail.example.com/confirm/... - <BLANKLINE> - If you do not wish to register this email address simply disregard this - message. If you think you are being maliciously subscribed to the list, - or have any other questions, you may contact - <BLANKLINE> - postmaster@mail.example.com - <BLANKLINE> - >>> dump_msgdata(qdata) - _parsemsg : False - nodecorate : True - recips : [u'aperson@example.com'] - reduced_list_headers: True - version : 3 - -The confirmation token shows up in several places, each of which provides an -easy way for the user to complete the confirmation. The token will always -appear in a URL in the body of the message. - - >>> sent_token = extract_token(qmsg) - >>> sent_token == token - True - -The same token will appear in the From header. - - >>> qmsg['from'] == 'confirm-' + token + '@mail.example.com' - True - -It will also appear in the Subject header. - - >>> qmsg['subject'] == 'confirm ' + token - True - -The user would then validate their just registered address by clicking on a -url or responding to the message. Either way, the confirmation process -extracts the token and uses that to confirm the pending registration. - - >>> registrar.confirm(token) - True - -Now, there is an IAddress in the database matching the address, as well as an -IUser linked to this address. The IAddress is verified. - - >>> found_address = usermgr.get_address(u'aperson@example.com') - >>> found_address - <Address: Anne Person <aperson@example.com> [verified] at ...> - >>> found_user = usermgr.get_user(u'aperson@example.com') - >>> found_user - <User "Anne Person" at ...> - >>> found_user.controls(found_address.address) - True - >>> from datetime import datetime - >>> isinstance(found_address.verified_on, datetime) - True - - -Non-standard registrations --------------------------- - -If you try to confirm a registration token twice, of course only the first one -will work. The second one is ignored. - - >>> token = registrar.register(u'bperson@example.com') - >>> check_token(token) - ok - >>> filebase = switchboard.files[0] - >>> qmsg, qdata = switchboard.dequeue(filebase) - >>> switchboard.finish(filebase) - >>> sent_token = extract_token(qmsg) - >>> token == sent_token - True - >>> registrar.confirm(token) - True - >>> registrar.confirm(token) - False - -If an address is in the system, but that address is not linked to a user yet -and the address is not yet validated, then no user is created until the -confirmation step is completed. - - >>> usermgr.create_address(u'cperson@example.com') - <Address: cperson@example.com [not verified] at ...> - >>> token = registrar.register(u'cperson@example.com', u'Claire Person') - >>> print usermgr.get_user(u'cperson@example.com') - None - >>> filebase = switchboard.files[0] - >>> qmsg, qdata = switchboard.dequeue(filebase) - >>> switchboard.finish(filebase) - >>> registrar.confirm(token) - True - >>> usermgr.get_user(u'cperson@example.com') - <User "Claire Person" at ...> - >>> usermgr.get_address(u'cperson@example.com') - <Address: cperson@example.com [verified] at ...> - -Even if the address being registered has already been verified, the -registration sends a confirmation. - - >>> token = registrar.register(u'cperson@example.com') - >>> token is not None - True - - -Discarding ----------- - -A confirmation token can also be discarded, say if the user changes his or her -mind about registering. When discarded, no IAddress or IUser is created. - - >>> token = registrar.register(u'eperson@example.com', u'Elly Person') - >>> check_token(token) - ok - >>> registrar.discard(token) - >>> print pendingdb.confirm(token) - None - >>> print usermgr.get_address(u'eperson@example.com') - None - >>> print usermgr.get_user(u'eperson@example.com') - None - - -Registering a new address for an existing user ----------------------------------------------- - -When a new address for an existing user is registered, there isn't too much -different except that the new address will still need to be verified before it -can be used. - - >>> dperson = usermgr.create_user(u'dperson@example.com', u'Dave Person') - >>> dperson - <User "Dave Person" at ...> - >>> address = usermgr.get_address(u'dperson@example.com') - >>> address.verified_on = datetime.now() - - >>> from operator import attrgetter - >>> sorted((addr for addr in dperson.addresses), key=attrgetter('address')) - [<Address: Dave Person <dperson@example.com> [verified] at ...>] - >>> dperson.register(u'david.person@example.com', u'David Person') - <Address: David Person <david.person@example.com> [not verified] at ...> - >>> token = registrar.register(u'david.person@example.com') - >>> filebase = switchboard.files[0] - >>> qmsg, qdata = switchboard.dequeue(filebase) - >>> switchboard.finish(filebase) - >>> registrar.confirm(token) - True - >>> user = usermgr.get_user(u'david.person@example.com') - >>> user is dperson - True - >>> user - <User "Dave Person" at ...> - >>> sorted((addr for addr in user.addresses), key=attrgetter('address')) - [<Address: David Person <david.person@example.com> [verified] at ...>, - <Address: Dave Person <dperson@example.com> [verified] at ...>] - - -Corner cases ------------- - -If you try to confirm a token that doesn't exist in the pending database, the -confirm method will just return None. - - >>> registrar.confirm('no token') - False - -Likewise, if you try to confirm, through the IUserRegistrar interface, a token -that doesn't match a registration even, you will get None. However, the -pending even matched with that token will still be removed. - - >>> from mailman.interfaces.pending import IPendable - >>> from zope.interface import implements - - >>> class SimplePendable(dict): - ... implements(IPendable) - >>> pendable = SimplePendable(type='foo', bar='baz') - >>> token = pendingdb.add(pendable) - >>> registrar.confirm(token) - False - >>> print pendingdb.confirm(token) - None - - -Registration and subscription ------------------------------ - -Fred registers with Mailman at the same time that he subscribes to a mailing -list. - - >>> from mailman.app.lifecycle import create_list - >>> mlist = create_list(u'alpha@example.com') - >>> token = registrar.register( - ... u'fred.person@example.com', 'Fred Person', mlist) - -Before confirmation, Fred is not a member of the mailing list. - - >>> print mlist.members.get_member(u'fred.person@example.com') - None - -But after confirmation, he is. - - >>> registrar.confirm(token) - True - >>> print mlist.members.get_member(u'fred.person@example.com') - <Member: Fred Person <fred.person@example.com> - on alpha@example.com as MemberRole.member> - - -Clean up --------- - - >>> config.pop('mail') |
