Email addresses
===============

Addresses represent a text email address, along with some meta data about
those addresses, such as their registration date, and whether and when they've
been validated.  Addresses may be linked to the users that Mailman knows
about.  Addresses are subscribed to mailing lists though members.

    >>> from mailman.configuration import config
    >>> usermgr = config.db.user_manager


Creating addresses
------------------

Addresses are created directly through the user manager, which starts out with
no addresses.

    >>> sorted(address.address for address in usermgr.addresses)
    []

Creating an unlinked email address is straightforward.

    >>> address_1 = usermgr.create_address(u'aperson@example.com')
    >>> sorted(address.address for address in usermgr.addresses)
    [u'aperson@example.com']

However, such addresses have no real name.

    >>> address_1.real_name
    u''

You can also create an email address object with a real name.

    >>> address_2 = usermgr.create_address(
    ...     u'bperson@example.com', u'Ben Person')
    >>> sorted(address.address for address in usermgr.addresses)
    [u'aperson@example.com', u'bperson@example.com']
    >>> sorted(address.real_name for address in usermgr.addresses)
    [u'', u'Ben Person']

The str() of the address is the RFC 2822 preferred originator format, while
the repr() carries more information.

    >>> str(address_2)
    'Ben Person <bperson@example.com>'
    >>> repr(address_2)
    '<Address: Ben Person <bperson@example.com> [not verified] at 0x...>'

You can assign real names to existing addresses.

    >>> address_1.real_name = u'Anne Person'
    >>> sorted(address.real_name for address in usermgr.addresses)
    [u'Anne Person', u'Ben Person']

These addresses are not linked to users, and can be seen by searching the user
manager for an associated user.

    >>> print usermgr.get_user(u'aperson@example.com')
    None
    >>> print usermgr.get_user(u'bperson@example.com')
    None

You can create email addresses that are linked to users by using a different
interface.

    >>> user_1 = usermgr.create_user(u'cperson@example.com', u'Claire Person')
    >>> sorted(address.address for address in user_1.addresses)
    [u'cperson@example.com']
    >>> sorted(address.address for address in usermgr.addresses)
    [u'aperson@example.com', u'bperson@example.com', u'cperson@example.com']
    >>> sorted(address.real_name for address in usermgr.addresses)
    [u'Anne Person', u'Ben Person', u'Claire Person']

And now you can find the associated user.

    >>> print usermgr.get_user(u'aperson@example.com')
    None
    >>> print usermgr.get_user(u'bperson@example.com')
    None
    >>> usermgr.get_user(u'cperson@example.com')
    <User "Claire Person" at ...>


Deleting addresses
------------------

You can remove an unlinked address from the user manager.

    >>> usermgr.delete_address(address_1)
    >>> sorted(address.address for address in usermgr.addresses)
    [u'bperson@example.com', u'cperson@example.com']
    >>> sorted(address.real_name for address in usermgr.addresses)
    [u'Ben Person', u'Claire Person']

Deleting a linked address does not delete the user, but it does unlink the
address from the user.

    >>> sorted(address.address for address in user_1.addresses)
    [u'cperson@example.com']
    >>> user_1.controls(u'cperson@example.com')
    True
    >>> address_3 = list(user_1.addresses)[0]
    >>> usermgr.delete_address(address_3)
    >>> sorted(address.address for address in user_1.addresses)
    []
    >>> user_1.controls(u'cperson@example.com')
    False
    >>> sorted(address.address for address in usermgr.addresses)
    [u'bperson@example.com']


Registration and validation
---------------------------

Addresses have two dates, the date the address was registered on and the date
the address was validated on.  Neither date is set by default.

    >>> address_4 = usermgr.create_address(
    ...     u'dperson@example.com', u'Dan Person')
    >>> print address_4.registered_on
    None
    >>> print address_4.verified_on
    None

The registered date takes a Python datetime object.

    >>> from datetime import datetime
    >>> address_4.registered_on = datetime(2007, 5, 8, 22, 54, 1)
    >>> print address_4.registered_on
    2007-05-08 22:54:01
    >>> print address_4.verified_on
    None

And of course, you can also set the validation date.

    >>> address_4.verified_on = datetime(2007, 5, 13, 22, 54, 1)
    >>> print address_4.registered_on
    2007-05-08 22:54:01
    >>> print address_4.verified_on
    2007-05-13 22:54:01


Subscriptions
-------------

Addresses get subscribed to mailing lists, not users.  When the address is
subscribed, a role is specified.

    >>> address_5 = usermgr.create_address(
    ...     u'eperson@example.com', u'Elly Person')
    >>> mlist = config.db.list_manager.create(u'_xtext@example.com')
    >>> from mailman.interfaces import MemberRole
    >>> address_5.subscribe(mlist, MemberRole.owner)
    <Member: Elly Person <eperson@example.com> on
             _xtext@example.com as MemberRole.owner>
    >>> address_5.subscribe(mlist, MemberRole.member)
    <Member: Elly Person <eperson@example.com> on
             _xtext@example.com as MemberRole.member>

Now Elly is both an owner and a member of the mailing list.

    >>> sorted(mlist.owners.members)
    [<Member: Elly Person <eperson@example.com> on
              _xtext@example.com as MemberRole.owner>]
    >>> sorted(mlist.moderators.members)
    []
    >>> sorted(mlist.administrators.members)
    [<Member: Elly Person <eperson@example.com> on
              _xtext@example.com as MemberRole.owner>]
    >>> sorted(mlist.members.members)
    [<Member: Elly Person <eperson@example.com> on
              _xtext@example.com as MemberRole.member>]
    >>> sorted(mlist.regular_members.members)
    [<Member: Elly Person <eperson@example.com> on
              _xtext@example.com as MemberRole.member>]
    >>> sorted(mlist.digest_members.members)
    []


Case-preserved addresses
------------------------

Technically speaking, email addresses are case sensitive in the local part.
Mailman preserves the case of addresses and uses the case preserved version
when sending the user a message, but it treats addresses that are different in
case equivalently in all other situations.

    >>> address_6 = usermgr.create_address(
    ...     u'FPERSON@example.com', u'Frank Person')

The str() of such an address prints the RFC 2822 preferred originator format
with the original case-preserved address.  The repr() contains all the gory
details.

    >>> str(address_6)
    'Frank Person <FPERSON@example.com>'
    >>> repr(address_6)
    '<Address: Frank Person <FPERSON@example.com> [not verified]
               key: fperson@example.com at 0x...>'

Both the case-insensitive version of the address and the original
case-preserved version are available on attributes of the IAddress object.

    >>> address_6.address
    u'fperson@example.com'
    >>> address_6.original_address
    u'FPERSON@example.com'

Because addresses are case-insensitive for all other purposes, you cannot
create an address that differs only in case.

    >>> usermgr.create_address(u'fperson@example.com')
    Traceback (most recent call last):
    ...
    ExistingAddressError: FPERSON@example.com
    >>> usermgr.create_address(u'fperson@EXAMPLE.COM')
    Traceback (most recent call last):
    ...
    ExistingAddressError: FPERSON@example.com
    >>> usermgr.create_address(u'FPERSON@example.com')
    Traceback (most recent call last):
    ...
    ExistingAddressError: FPERSON@example.com

You can get the address using either the lower cased version or case-preserved
version.  In fact, searching for an address is case insensitive.

    >>> usermgr.get_address(u'fperson@example.com').address
    u'fperson@example.com'
    >>> usermgr.get_address(u'FPERSON@example.com').address
    u'fperson@example.com'
