
When my company migrated from MM2 to MM3, they discovered there were things that didn't work as expected (don't get me started). So they developed a set of Python functions which allowed then to fill in the missing functionality. However, they've discovered that some of those functions either never worked properly, or no longer work. For example,
def list_nonmembers(mlist):
for accepted in mlist.accept_these_nonmembers:
print("Accepted: ",accepted)
for held in mlist.hold_these_nonmembers:
print("Held: ",held)
They're run by shelling into the machine which hosts mailman and executed like so (where scripts is scripts.py
)
sudo -iu mailman mailman shell -l MAILING_LIST_ID --run scripts.list_nonmembers
I'm recommending that we install Postorius, as I suspect many of the functions they've written are already present in that UI, but it's not as simple as that. Instead they're wanting a handful of these functions (including the one listed above) replaced sooner than we could get Postorius up and running.
I've gotten this far:
from mailman.interfaces.listmanager import IListManager
from zope.component import getUtility
mylist_id = 'bravo-open1@tena-sda.org'
list_manager = getUtility(IListManager)
mylist = list_manager.get(mylist_id)
The mylist variable is of type mailman.model.mailinglist.MailingList
, and includes an Attributes for nonmembers:
mylist.nonmembers
<mailman.model.roster.NonmemberRoster object at 0x7ffffa3e65b0>
But this nonmembers property doesn't output any users/addresses when printed, and throws a TypeError when I try to iterate over it:
Traceback (most recent call last):
File "<console>", line 1, in <module>
TypeError: 'NonmemberRoster' object is not iterable
So, given a mailing list instance, retrieved via list_manager.get(mylist_id)
, how would I go about printing all nonmembers and their current roles in a list (held, accepted, etc.)? Alternately, is there a different question I should be asking in order to retrieve that information?

On 5/13/25 12:40, Andy Matthews wrote:
When my company migrated from MM2 to MM3, they discovered there were things that didn't work as expected (don't get me started). So they developed a set of Python functions which allowed then to fill in the missing functionality. However, they've discovered that some of those functions either never worked properly, or no longer work. For example,
def list_nonmembers(mlist): for accepted in mlist.accept_these_nonmembers: print("Accepted: ",accepted) for held in mlist.hold_these_nonmembers: print("Held: ",held)
They're run by shelling into the machine which hosts mailman and executed like so (where scripts is
scripts.py
)sudo -iu mailman mailman shell -l MAILING_LIST_ID --run scripts.list_nonmembers
That should work. What happens when you run it? Possibly it prints nothing because the list's accept_these_nonmembers and hold_these_nonmembers attributes are empty.
I'm recommending that we install Postorius, as I suspect many of the functions they've written are already present in that UI, but it's not as simple as that. Instead they're wanting a handful of these functions (including the one listed above) replaced sooner than we could get Postorius up and running.
I've gotten this far:
from mailman.interfaces.listmanager import IListManager from zope.component import getUtility mylist_id = 'bravo-open1@tena-sda.org' list_manager = getUtility(IListManager) mylist = list_manager.get(mylist_id)
The mylist variable is of type
mailman.model.mailinglist.MailingList
, and includes an Attributes for nonmembers:mylist.nonmembers <mailman.model.roster.NonmemberRoster object at 0x7ffffa3e65b0>
But this nonmembers property doesn't output any users/addresses when printed, and throws a TypeError when I try to iterate over it:
First of all I think there may be some confusion between the list's
nonmembers and the *_these_nonmembers attributes. *_these_nonmembers are
legacy attributes which exist to support ^...
regexps and @list_id
entries, but the preferred way to accept, hold, reject or discard
individual nonmembers is to set the nonmember's moderation action.
Traceback (most recent call last): File "<console>", line 1, in <module> TypeError: 'NonmemberRoster' object is not iterable
You need to iterate over mylist.nonmembers.members, i.e. the roster's members, not the roster.
So, given a mailing list instance, retrieved via
list_manager.get(mylist_id)
, how would I go about printing all nonmembers and their current roles in a list (held, accepted, etc.)? Alternately, is there a different question I should be asking in order to retrieve that information?
It's not roles as you've already limited the role to nonmember. It's moderation_action.
for nonmember in mylist.nonmembers.members:
print(f'Nonmember: {nonmember.address.email},'
f' moderation_action: {nonmember.moderation_action}')
Note that moderation_action: None means list default.
-- Mark Sapiro <mark@msapiro.net> The highway is for gamblers, San Francisco Bay Area, California better use your sense - B. Dylan

Ahhh, thank you for the clarification Mark. You might be right that the list had no members. I tried running these commands after a slew of automated tests, so that i hopefully had members, but I might have selected one which didn't. I'll try again with these updates you've offered. Thanks!
Side note, how was your vacation earlier in the year?

okay, iterating over the members property of the roster is what I was missing. Also, I think I was looking at a roster that was empty anyway.
from pprint import pprint
from mailman.interfaces.listmanager import IListManager
from zope.component import getUtility
list_id = 'foo@bar.org'
list_manager = getUtility(IListManager)
mylist = list_manager.get(list_id)
[pprint(member) for member in mylist.nonmembers.members]
[pprint(member) for member in mylist.owners.members]
[pprint(member) for member in mylist.moderators.members]
[pprint(member) for member in mylist.administrators.members]
[pprint(member) for member in mylist.members.members]

On 5/14/25 14:13, Andy Matthews wrote:
[pprint(member) for member in mylist.nonmembers.members] [pprint(member) for member in mylist.owners.members] [pprint(member) for member in mylist.moderators.members] [pprint(member) for member in mylist.administrators.members]
This is redundant. The administrators roster is just the union of the owners and moderators rosters.
[pprint(member) for member in mylist.members.members]
Also,
[pprint(member) for member in ...]
and
[print(member) for member in ...]
are equivalent as both pprint(member) and print(member) just print the repr() of the member object.
-- Mark Sapiro <mark@msapiro.net> The highway is for gamblers, San Francisco Bay Area, California better use your sense - B. Dylan

Great, thanks for the clarification. This was just my first pass, I'll update it locally as I expand out from this foundation.
participants (2)
-
Andy Matthews
-
Mark Sapiro