diff options
Diffstat (limited to 'Mailman/docs')
| -rw-r--r-- | Mailman/docs/Makefile.in | 82 | ||||
| -rw-r--r-- | Mailman/docs/__init__.py | 0 | ||||
| -rw-r--r-- | Mailman/docs/addresses.txt | 144 | ||||
| -rw-r--r-- | Mailman/docs/mlist-addresses.txt | 85 | ||||
| -rw-r--r-- | Mailman/docs/mlist-rosters.txt | 118 | ||||
| -rw-r--r-- | Mailman/docs/use-listmanager.txt | 124 | ||||
| -rw-r--r-- | Mailman/docs/use-usermanager.txt | 100 | ||||
| -rw-r--r-- | Mailman/docs/users.txt | 180 |
8 files changed, 833 insertions, 0 deletions
diff --git a/Mailman/docs/Makefile.in b/Mailman/docs/Makefile.in new file mode 100644 index 000000000..0662d8a3e --- /dev/null +++ b/Mailman/docs/Makefile.in @@ -0,0 +1,82 @@ +# Copyright (C) 1998-2007 by the Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +# USA. + +# NOTE: Makefile.in is converted into Makefile by the configure script +# in the parent directory. Once configure has run, you can recreate +# the Makefile by running just config.status. + +# Variables set by configure + +VPATH= @srcdir@ +srcdir= @srcdir@ +bindir= @bindir@ +prefix= @prefix@ +exec_prefix= @exec_prefix@ +DESTDIR= + +CC= @CC@ +CHMOD= @CHMOD@ +INSTALL= @INSTALL@ + +DEFS= @DEFS@ + +# Customizable but not set by configure + +OPT= @OPT@ +CFLAGS= $(OPT) $(DEFS) +PACKAGEDIR= $(prefix)/Mailman/docs +SHELL= /bin/sh + +OTHERFILES= *.txt +MODULES= *.py + +# Modes for directories and executables created by the install +# process. Default to group-writable directories but +# user-only-writable for executables. +DIRMODE= 775 +EXEMODE= 755 +FILEMODE= 644 +INSTALL_PROGRAM=$(INSTALL) -m $(EXEMODE) + +# Directories make should decend into +SUBDIRS= + +# Rules + +all: + +install: + for f in $(MODULES) $(OTHERFILES); \ + do \ + $(INSTALL) -m $(FILEMODE) $(srcdir)/$$f $(DESTDIR)$(PACKAGEDIR); \ + done + for d in $(SUBDIRS); \ + do \ + (cd $$d; $(MAKE) DESTDIR=$(DESTDIR) install); \ + done + +finish: + +clean: + +distclean: + -rm *.pyc + -rm Makefile + @for d in $(SUBDIRS); \ + do \ + (cd $$d; $(MAKE) distclean); \ + done diff --git a/Mailman/docs/__init__.py b/Mailman/docs/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/Mailman/docs/__init__.py diff --git a/Mailman/docs/addresses.txt b/Mailman/docs/addresses.txt new file mode 100644 index 000000000..a8cf9f655 --- /dev/null +++ b/Mailman/docs/addresses.txt @@ -0,0 +1,144 @@ +Email addresses and rosters +=========================== + +Addresses represent email address, and nothing more. Some addresses are tied +to users that Mailman knows about. For example, a list member is a user that +the system knows about, but a non-member posting from a brand new email +address is a counter-example. + + +Creating a roster +----------------- + +Email address objects are tied to rosters, and rosters are tied to the user +manager. To get things started, access the global user manager and create a +new roster. + + >>> from Mailman.database import flush + >>> from Mailman.configuration import config + >>> mgr = config.user_manager + >>> roster_1 = mgr.create_roster('roster-1') + >>> sorted(roster_1.addresses) + [] + + +Creating addresses +------------------ + +Creating a simple email address object is straight forward. + + >>> addr_1 = roster_1.create('aperson@example.com') + >>> flush() + >>> addr_1.address + 'aperson@example.com' + >>> addr_1.real_name is None + True + +You can also create an email address object with a real name. + + >>> addr_2 = roster_1.create('bperson@example.com', 'Barney Person') + >>> addr_2.address + 'bperson@example.com' + >>> addr_2.real_name + 'Barney Person' + +You can also iterate through all the addresses on a roster. + + >>> sorted(addr.address for addr in roster_1.addresses) + ['aperson@example.com', 'bperson@example.com'] + +You can create another roster and add a bunch of existing addresses to the +second roster. + + >>> roster_2 = mgr.create_roster('roster-2') + >>> flush() + >>> sorted(roster_2.addresses) + [] + >>> for address in roster_1.addresses: + ... roster_2.addresses.append(address) + >>> roster_2.create('cperson@example.com', 'Charlie Person') + <Address: Charlie Person <cperson@example.com> [not verified]> + >>> sorted(addr.address for addr in roster_2.addresses) + ['aperson@example.com', 'bperson@example.com', 'cperson@example.com'] + +The first roster hasn't been affected. + + >>> sorted(addr.address for addr in roster_1.addresses) + ['aperson@example.com', 'bperson@example.com'] + + +Removing addresses +------------------ + +You can remove an address from a roster just by deleting it. + + >>> for addr in roster_1.addresses: + ... if addr.address == 'aperson@example.com': + ... break + >>> addr.address + 'aperson@example.com' + >>> roster_1.addresses.remove(addr) + >>> sorted(addr.address for addr in roster_1.addresses) + ['bperson@example.com'] + +Again, this doesn't affect the other rosters. + + >>> sorted(addr.address for addr in roster_2.addresses) + ['aperson@example.com', 'bperson@example.com', 'cperson@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 isset by default. + + >>> addr = roster_1.create('dperson@example.com', 'David Person') + >>> addr.registered_on is None + True + >>> addr.validated_on is None + True + +The registered date takes a Python datetime object. + + >>> from datetime import datetime + >>> addr.registered_on = datetime(2007, 5, 8, 22, 54, 1) + >>> print addr.registered_on + 2007-05-08 22:54:01 + >>> addr.validated_on is None + True + +And of course, you can also set the validation date. + + >>> addr.validated_on = datetime(2007, 5, 13, 22, 54, 1) + >>> print addr.registered_on + 2007-05-08 22:54:01 + >>> print addr.validated_on + 2007-05-13 22:54:01 + + +The null roster +--------------- + +All address objects that have been created are members of the null roster. + + >>> all = mgr.get_roster('') + >>> sorted(addr.address for addr in all.addresses) + ['aperson@example.com', 'bperson@example.com', + 'cperson@example.com', 'dperson@example.com'] + +And conversely, all addresses should have the null roster on their list of +rosters. + + >>> for addr in all.addresses: + ... assert all in addr.rosters, 'Address is missing null roster' + + +Clean up +-------- + + >>> for roster in mgr.rosters: + ... mgr.delete_roster(roster) + >>> flush() + >>> sorted(roster.name for roster in mgr.rosters) + [] diff --git a/Mailman/docs/mlist-addresses.txt b/Mailman/docs/mlist-addresses.txt new file mode 100644 index 000000000..257cf95c7 --- /dev/null +++ b/Mailman/docs/mlist-addresses.txt @@ -0,0 +1,85 @@ +Mailing list addresses +====================== + +Every mailing list has a number of addresses which are publicly available. +These are defined in the IMailingListAddresses interface. + + >>> from Mailman.configuration import config + >>> from Mailman.interfaces import IMailingListAddresses + >>> mlist = config.list_manager.create('_xtest@example.com') + >>> IMailingListAddresses.providedBy(mlist) + True + +The posting address is where people send messages to be posted to the mailing +list. This is exactly the same as the fully qualified list name. + + >>> mlist.fqdn_listname + '_xtest@example.com' + >>> mlist.posting_address + '_xtest@example.com' + +Messages to the mailing list's 'no reply' address always get discarded without +prejudice. + + >>> mlist.noreply_address + 'noreply@example.com' + +The mailing list's owner address reaches the human moderators. + + >>> mlist.owner_address + '_xtest-owner@example.com' + +The request address goes to the list's email command robot. + + >>> mlist.request_address + '_xtest-request@example.com' + +The bounces address accepts and processes all potential bounces. + + >>> mlist.bounces_address + '_xtest-bounces@example.com' + +The join (a.k.a. subscribe) address is where someone can email to get added to +the mailing list. The subscribe alias is a synonym for join, but it's +deprecated. + + >>> mlist.join_address + '_xtest-join@example.com' + >>> mlist.subscribe_address + '_xtest-subscribe@example.com' + +The leave (a.k.a. unsubscribe) address is where someone can email to get added +to the mailing list. The unsubscribe alias is a synonym for leave, but it's +deprecated. + + >>> mlist.leave_address + '_xtest-leave@example.com' + >>> mlist.unsubscribe_address + '_xtest-unsubscribe@example.com' + + +Email confirmations +------------------- + +Email confirmation messages are sent when actions such as subscriptions need +to be confirmed. It requires that a cookie be provided, which will be +included in the local part of the email address. The exact format of this is +dependent on the VERP_CONFIRM_FORMAT configuration variable. + + >>> mlist.confirm_address('cookie') + '_xtest-confirm+cookie@example.com' + >>> mlist.confirm_address('wookie') + '_xtest-confirm+wookie@example.com' + + >>> old_format = config.VERP_CONFIRM_FORMAT + >>> config.VERP_CONFIRM_FORMAT = '$address---$cookie' + >>> mlist.confirm_address('cookie') + '_xtest-confirm---cookie@example.com' + >>> config.VERP_CONFIRM_FORMAT = old_format + + +Clean up +-------- + + >>> for mlist in config.list_manager.mailing_lists: + ... config.list_manager.delete(mlist) diff --git a/Mailman/docs/mlist-rosters.txt b/Mailman/docs/mlist-rosters.txt new file mode 100644 index 000000000..490a07e0c --- /dev/null +++ b/Mailman/docs/mlist-rosters.txt @@ -0,0 +1,118 @@ +Mailing list rosters +==================== + +Mailing lists use rosters to manage and organize users for various purposes. +In order to allow for separate storage of mailing list data and user data, the +connection between mailing list objects and rosters is indirect. Mailing +lists manage roster names, and these roster names are used to find the rosters +that contain the actual users. + + +Privileged rosters +------------------ + +Mailing lists have two types of privileged users, owners and moderators. +Owners get to change the configuration of mailing lists and moderators get to +approve or deny held messages and subscription requests. + +When a mailing list is created, it automatically contains a roster for the +list owners and a roster for the list moderators. + + >>> from Mailman.database import flush + >>> from Mailman.configuration import config + >>> mlist = config.list_manager.create('_xtest@example.com') + >>> flush() + >>> sorted(roster.name for roster in mlist.owner_rosters) + ['_xtest@example.com owners'] + >>> sorted(roster.name for roster in mlist.moderator_rosters) + ['_xtest@example.com moderators'] + +These rosters are initially empty. + + >>> owner_roster = list(mlist.owner_rosters)[0] + >>> sorted(address for address in owner_roster.addresses) + [] + >>> moderator_roster = list(mlist.moderator_rosters)[0] + >>> sorted(address for address in moderator_roster.addresses) + [] + +You can create new rosters and add them to the list of owner or moderator +rosters. + + >>> roster_1 = config.user_manager.create_roster('roster-1') + >>> roster_2 = config.user_manager.create_roster('roster-2') + >>> roster_3 = config.user_manager.create_roster('roster-3') + >>> flush() + +Make roster-1 an owner roster, roster-2 a moderator roster, and roster-3 both +an owner and a moderator roster. + + >>> mlist.add_owner_roster(roster_1) + >>> mlist.add_moderator_roster(roster_2) + >>> mlist.add_owner_roster(roster_3) + >>> mlist.add_moderator_roster(roster_3) + >>> flush() + + >>> sorted(roster.name for roster in mlist.owner_rosters) + ['_xtest@example.com owners', 'roster-1', 'roster-3'] + >>> sorted(roster.name for roster in mlist.moderator_rosters) + ['_xtest@example.com moderators', 'roster-2', 'roster-3'] + + +Privileged users +---------------- + +Rosters are the lower level way of managing owners and moderators, but usually +you just want to know which users have owner and moderator privileges. You +can get the list of such users by using different attributes. + +Because the rosters are all empty to start with, we can create a bunch of +users that will end up being our owners and moderators. + + >>> aperson = config.user_manager.create_user() + >>> bperson = config.user_manager.create_user() + >>> cperson = config.user_manager.create_user() + +These users need addresses, because rosters manage addresses. + + >>> address_1 = roster_1.create('aperson@example.com', 'Anne Person') + >>> aperson.link(address_1) + >>> address_2 = roster_2.create('bperson@example.com', 'Ben Person') + >>> bperson.link(address_2) + >>> address_3 = roster_1.create('cperson@example.com', 'Claire Person') + >>> cperson.link(address_3) + >>> roster_3.addresses.append(address_3) + >>> flush() + +Now that everything is set up, we can iterate through the various collections +of privileged users. Here are the owners of the list. + + >>> from Mailman.interfaces import IUser + >>> addresses = [] + >>> for user in mlist.owners: + ... assert IUser.providedBy(user), 'Non-IUser owner found' + ... for address in user.addresses: + ... addresses.append(address.address) + >>> sorted(addresses) + ['aperson@example.com', 'cperson@example.com'] + +Here are the moderators of the list. + + >>> addresses = [] + >>> for user in mlist.moderators: + ... assert IUser.providedBy(user), 'Non-IUser moderator found' + ... for address in user.addresses: + ... addresses.append(address.address) + >>> sorted(addresses) + ['bperson@example.com', 'cperson@example.com'] + +The administrators of a mailing list are the union of the owners and +moderators. + + >>> addresses = [] + >>> for user in mlist.administrators: + ... assert IUser.providedBy(user), 'Non-IUser administrator found' + ... for address in user.addresses: + ... addresses.append(address.address) + >>> sorted(addresses) + ['aperson@example.com', 'bperson@example.com', 'cperson@example.com'] diff --git a/Mailman/docs/use-listmanager.txt b/Mailman/docs/use-listmanager.txt new file mode 100644 index 000000000..9e237f02f --- /dev/null +++ b/Mailman/docs/use-listmanager.txt @@ -0,0 +1,124 @@ +Using the IListManager interface +================================ + +The IListManager is how you create, delete, and retrieve mailing list +objects. The Mailman system instantiates an IListManager for you based on the +configuration variable MANAGERS_INIT_FUNCTION. The instance is accessible +on the global config object. + + >>> from Mailman.database import flush + >>> from Mailman.configuration import config + >>> from Mailman.interfaces import IListManager + >>> IListManager.providedBy(config.list_manager) + True + >>> mgr = config.list_manager + + +Creating a mailing list +----------------------- + +Creating the list returns the newly created IMailList object. + + >>> from Mailman.interfaces import IMailingList + >>> mlist = mgr.create('_xtest@example.com') + >>> flush() + >>> IMailingList.providedBy(mlist) + True + +This object has an identity. + + >>> from Mailman.interfaces import IMailingListIdentity + >>> IMailingListIdentity.providedBy(mlist) + True + +All lists with identities have a short name, a host name, and a fully +qualified listname. This latter is what uniquely distinguishes the mailing +list to the system. + + >>> mlist.list_name + '_xtest' + >>> mlist.host_name + 'example.com' + >>> mlist.fqdn_listname + '_xtest@example.com' + +If you try to create a mailing list with the same name as an existing list, +you will get an exception. + + >>> mlist_dup = mgr.create('_xtest@example.com') + Traceback (most recent call last): + ... + MMListAlreadyExistsError: _xtest@example.com + + +Deleting a mailing list +----------------------- + +Deleting an existing mailing list also deletes its rosters and roster sets. + + >>> sorted(r.name for r in config.user_manager.rosters) + ['', '_xtest@example.com moderators', '_xtest@example.com owners'] + + >>> mgr.delete(mlist) + >>> flush() + >>> sorted(mgr.names) + [] + >>> sorted(r.name for r in config.user_manager.rosters) + [''] + +Attempting to access attributes of the deleted mailing list raises an +exception: + + >>> mlist.fqdn_listname + Traceback (most recent call last): + ... + AttributeError: fqdn_listname + +After deleting the list, you can create it again. + + >>> mlist = mgr.create('_xtest@example.com') + >>> flush() + >>> mlist.fqdn_listname + '_xtest@example.com' + + +Retrieving a mailing list +------------------------- + +When a mailing list exists, you can ask the list manager for it and you will +always get the same object back. + + >>> mlist_2 = mgr.get('_xtest@example.com') + >>> mlist_2 is mlist + True + +Don't try to get a list that doesn't exist yet though, or you will get an +exception. + + >>> mgr.get('_xtest_2@example.com') + Traceback (most recent call last): + ... + MMUnknownListError: _xtest_2@example.com + + +Iterating over all mailing lists +-------------------------------- + +Once you've created a bunch of mailing lists, you can use the list manager to +iterate over either the list objects, or the list names. + + >>> mlist_3 = mgr.create('_xtest_3@example.com') + >>> mlist_4 = mgr.create('_xtest_4@example.com') + >>> flush() + >>> sorted(mgr.names) + ['_xtest@example.com', '_xtest_3@example.com', '_xtest_4@example.com'] + >>> sorted(m.fqdn_listname for m in mgr.mailing_lists) + ['_xtest@example.com', '_xtest_3@example.com', '_xtest_4@example.com'] + + +Cleaning up +----------- + + >>> for mlist in mgr.mailing_lists: + ... mgr.delete(mlist) + >>> flush() diff --git a/Mailman/docs/use-usermanager.txt b/Mailman/docs/use-usermanager.txt new file mode 100644 index 000000000..f79bff8c6 --- /dev/null +++ b/Mailman/docs/use-usermanager.txt @@ -0,0 +1,100 @@ +The user manager and rosters +============================ + +The IUserManager is how you create, delete, and roster objects. Rosters +manage collections of users. The Mailman system instantiates an IUserManager +for you based on the configuration variable MANAGERS_INIT_FUNCTION. The +instance is accessible on the global config object. + + >>> from Mailman.configuration import config + >>> from Mailman.interfaces import IUserManager + >>> mgr = config.user_manager + >>> IUserManager.providedBy(mgr) + True + + +The default roster +------------------ + +The user manager always contains at least one roster, the 'null' roster or +'all inclusive roster'. + + >>> sorted(roster.name for roster in mgr.rosters) + [''] + + +Adding rosters +-------------- + +You create a roster to hold users. The only thing a roster needs is a name, +basically just an identifying string. + + >>> from Mailman.database import flush + >>> from Mailman.interfaces import IRoster + >>> roster = mgr.create_roster('roster-1') + >>> IRoster.providedBy(roster) + True + >>> roster.name + 'roster-1' + >>> flush() + +If you try to create a roster with the same name as an existing roster, you +will get an exception. + + >>> roster_dup = mgr.create_roster('roster-1') + Traceback (most recent call last): + ... + RosterExistsError: roster-1 + + +Deleting a roster +----------------- + +Delete the roster, and you can then create it again. + + >>> mgr.delete_roster(roster) + >>> flush() + >>> roster = mgr.create_roster('roster-1') + >>> flush() + >>> roster.name + 'roster-1' + + +Retrieving a roster +------------------- + +When a roster exists, you can ask the user manager for it and you will always +get the same object back. + + >>> roster_2 = mgr.get_roster('roster-1') + >>> roster_2.name + 'roster-1' + >>> roster is roster_2 + True + +Trying to get a roster that does not yet exist returns None. + + >>> print mgr.get_roster('no roster') + None + + +Iterating over all the rosters +------------------------------ + +Once you've created a bunch of rosters, you can use the user manager to +iterate over all the rosters. + + >>> roster_2 = mgr.create_roster('roster-2') + >>> roster_3 = mgr.create_roster('roster-3') + >>> roster_4 = mgr.create_roster('roster-4') + >>> flush() + >>> sorted(roster.name for roster in mgr.rosters) + ['', 'roster-1', 'roster-2', 'roster-3', 'roster-4'] + + +Cleaning up +----------- + + >>> for roster in mgr.rosters: + ... mgr.delete_roster(roster) + >>> flush() diff --git a/Mailman/docs/users.txt b/Mailman/docs/users.txt new file mode 100644 index 000000000..caad6b216 --- /dev/null +++ b/Mailman/docs/users.txt @@ -0,0 +1,180 @@ +Users +===== + +Users are entities that combine addresses, preferences, and a password +scheme. Password schemes can be anything from a traditional +challenge/response type password string to an OpenID url. + + +Create, deleting, and managing users +------------------------------------ + +Users are managed by the IUserManager. Users don't have any unique +identifying information, and no such id is needed to create them. + + >>> from Mailman.database import flush + >>> from Mailman.configuration import config + >>> mgr = config.user_manager + >>> user = mgr.create_user() + +Users have a real name, a password scheme, a default profile, and a set of +addresses that they control. All of these data are None or empty for a newly +created user. + + >>> user.real_name is None + True + >>> user.password is None + True + >>> user.addresses + [] + +You can iterate over all the users in a user manager. + + >>> another_user = mgr.create_user() + >>> flush() + >>> all_users = list(mgr.users) + >>> len(list(all_users)) + 2 + >>> user is not another_user + True + >>> user in all_users + True + >>> another_user in all_users + True + +You can also delete users from the user manager. + + >>> mgr.delete_user(user) + >>> mgr.delete_user(another_user) + >>> flush() + >>> len(list(mgr.users)) + 0 + + +Simple user information +----------------------- + +Users may have a real name and a password scheme. + + >>> user = mgr.create_user() + >>> user.password = 'my password' + >>> user.real_name = 'Zoe Person' + >>> flush() + >>> only_person = list(mgr.users)[0] + >>> only_person.password + 'my password' + >>> only_person.real_name + 'Zoe Person' + +The password and real name can be changed at any time. + + >>> user.real_name = 'Zoe X. Person' + >>> user.password = 'another password' + >>> only_person.real_name + 'Zoe X. Person' + >>> only_person.password + 'another password' + + +Users and addresses +------------------- + +One of the pieces of information that a user links to is a set of email +addresses, in the form of IAddress objects. A user can control many +addresses, but addresses may be control by only one user. + +Given a user and an address, you can link the two together. + + >>> roster = mgr.get_roster('') + >>> address = roster.create('aperson@example.com', 'Anne Person') + >>> user.link(address) + >>> flush() + >>> sorted(address.address for address in user.addresses) + ['aperson@example.com'] + +But don't try to link an address to more than one user. + + >>> another_user = mgr.create_user() + >>> another_user.link(address) + Traceback (most recent call last): + ... + AddressAlreadyLinkedError: Anne Person <aperson@example.com> + +You can also ask whether a given user controls a given address. + + >>> user.controls(address) + True + >>> not_my_address = roster.create('bperson@example.com', 'Ben Person') + >>> user.controls(not_my_address) + False + +Given a text email address, the user manager can find the user that controls +that address. + + >>> mgr.get_user('aperson@example.com') is user + True + >>> mgr.get_user('bperson@example.com') is None + True + +Addresses can also be unlinked from a user. + + >>> user.unlink(address) + >>> user.controls(address) + False + >>> mgr.get_user('aperson@example.com') is None + True + +But don't try to unlink the address from a user it's not linked to. + + >>> user.unlink(address) + Traceback (most recent call last): + ... + AddressNotLinkedError: Anne Person <aperson@example.com> + >>> another_user.unlink(address) + Traceback (most recent call last): + ... + AddressNotLinkedError: Anne Person <aperson@example.com> + >>> mgr.delete_user(another_user) + + +Users and profiles +------------------ + +Users always have a default profile. + + >>> from Mailman.interfaces import IProfile + >>> IProfile.providedBy(user.profile) + True + +A profile is a set of preferences such as whether the user wants to receive an +acknowledgment of all of their posts to a mailing list... + + >>> user.profile.acknowledge_posts + False + +...whether the user wants to hide their email addresses on web pages and in +postings to the list... + + >>> user.profile.hide_address + True + +...the language code for the user's preferred language... + + >>> user.profile.preferred_language + 'en' + +...whether the user wants to receive the list's copy of a message if they are +explicitly named in one of the recipient headers... + + >>> user.profile.receive_list_copy + True + +...whether the user wants to receive a copy of their own postings... + + >>> user.profile.receive_own_postings + True + +...and the preferred delivery method. + + >>> print user.profile.delivery_mode + DeliveryMode.regular |
