Can't add emails to accept_these_nonmembers
I need to set some nonmembers to a list as these members send message to the list, but don't need to receive any message from the list.
I've used list_name.settings['accept_these_nonmembers'].append to add members to the list, but it gets discarded once I run list_name.settings.save().
On 2/25/26 2:43 PM, Ibiam Chihurumnaya via Mailman-users wrote:
I need to set some nonmembers to a list as these members send message to the list, but don't need to receive any message from the list.
I've used list_name.settings['accept_these_nonmembers'].append to add members to the list, but it gets discarded once I run list_name.settings.save().
I don't understand what you are doing. The above makes no sense to me. Please provide more detail on exactly what it is you are doing.
However, accept_these_nonmembersis an artifact from Mailman 2.1 and
only exists in Mailman 3 to support patterns as opposed to individual
email addresses.
In Mailman 3, there are two ways to accomplish this. One way is to subscribe the user as a member and set the member's delivery to disabled. The other way is to add the user as a nonmember and set the nonmember's moderation_action to default processing.
-- Mark Sapiro <mark@msapiro.net> The highway is for gamblers, San Francisco Bay Area, California better use your sense - B. Dylan
Mark Sapiro wrote:
On 2/25/26 2:43 PM, Ibiam Chihurumnaya via Mailman-users wrote:
I need to set some nonmembers to a list as these members send message to the list, but don't need to receive any message from the list. I've used list_name.settings['accept_these_nonmembers'].append to add members to the list, but it gets discarded once I run list_name.settings.save().
accept_these_nonmembers is a list hence the append, I didn't add the argument to append, maybe that's what caused the confusion.
I don't understand what you are doing. The above makes no sense to me. Please provide more detail on exactly what it is you are doing. However, accept_these_nonmembersis an artifact from Mailman 2.1 and only exists in Mailman 3 to support patterns as opposed to individual email addresses. In Mailman 3, there are two ways to accomplish this. One way is to subscribe the user as a member and set the member's delivery to disabled. The other way is to add the user as a nonmember and set the nonmember's moderation_action to default processing.
I had done the members part in the past, but the issue with it was I wanted certain members to not receive messages from the list, but only send to the list.
-- Mark Sapiro <mark@msapiro.net> The highway is for gamblers, San Francisco Bay Area, California better use your sense - B. Dylan
Ibiam Chihurumnaya via Mailman-users writes:
I had done the members part in the past, but the issue with it was I wanted certain members to not receive messages from the list, but only send to the list.
As Mark explained, you can set those members to 'Default Processing' in the moderation option, and to 'No Mail' in the mail options. In that case they or list owners could reset them to receive mail.
The alternative is to add the addresses one by one as non-members and set their moderation. In that case they cannot receive mail, although they may be able to subscribe themselves depending on list settings, or an administrator could subscribe them. In both cases the nonmember would remain unless removed by an administrator.
In both cases, although you can add members with mass subscription, there are no "mass" operations to update the subscription option or to create non-members in Postorius, you need to do it one by one. You can automate that by using a loop over a list of addresses in Mailman shell, or if you expect to do it more than once, you could create a withlist script to use with the -r option.
-- GNU Mailman consultant (installation, migration, customization) Sirius Open Source https://www.siriusopensource.com/ Software systems consulting in Europe, North America, and Japan
Stephen J. Turnbull wrote:
I had done the members part in the past, but the issue with it was I wanted certain members to not receive messages from the list, but only send to the list. As Mark explained, you can set those members to 'Default Processing' in the moderation option, and to 'No Mail' in the mail options. In
Ibiam Chihurumnaya via Mailman-users writes: that case they or list owners could reset them to receive mail.
Yes, I'll try this.
The alternative is to add the addresses one by one as non-members and set their moderation. In that case they cannot receive mail, although they may be able to subscribe themselves depending on list settings, or an administrator could subscribe them. In both cases the nonmember would remain unless removed by an administrator. In both cases, although you can add members with mass subscription, there are no "mass" operations to update the subscription option or to create non-members in Postorius, you need to do it one by one. You can automate that by using a loop over a list of addresses in Mailman shell, or if you expect to do it more than once, you could create a withlist script to use with the -r option.
It's just a few emails so I'm doing it manually.
-- GNU Mailman consultant (installation, migration, customization) Sirius Open Source https://www.siriusopensource.com/ Software systems consulting in Europe, North America, and Japan
I've set the moderation action for each nonmember, I had added each email as nonmbers before and that was my mistake as that's what triggered them receiving emails which isn't what I intended.
Thank you!
On 2/26/26 07:27, Ibiam Chihurumnaya via Mailman-users wrote:
Mark Sapiro wrote:
On 2/25/26 2:43 PM, Ibiam Chihurumnaya via Mailman-users wrote:
I've used list_name.settings['accept_these_nonmembers'].append to add members to the list, but it gets discarded once I run list_name.settings.save().
accept_these_nonmembers is a list hence the append, I didn't add the argument to append, maybe that's what caused the confusion.
Again, the above makes no sense. In what context are you doing this?
mailman shell or something else? What is list_name is it a mailing
list object or something else? mailing list objects have no settings
attribute? There is no settings mapping with keys so
settings['accept_these_nonmembers'] is meaningless. What is
list_name.settings?
-- Mark Sapiro <mark@msapiro.net> The highway is for gamblers, San Francisco Bay Area, California better use your sense - B. Dylan
Mark Sapiro wrote:
Mark Sapiro wrote: On 2/25/26 2:43 PM, Ibiam Chihurumnaya via Mailman-users wrote: I've used list_name.settings['accept_these_nonmembers'].append to add members to the list, but it gets discarded once I run list_name.settings.save(). accept_these_nonmembers is a list hence the append, I didn't add the argument to append, maybe that's what caused the confusion. Again, the above makes no sense. In what context are you doing this? mailman shell or something else? What is list_name is it a mailing
On 2/26/26 07:27, Ibiam Chihurumnaya via Mailman-users wrote: list object or something else? mailing list objects have no settings attribute? There is no settings mapping with keys so settings['accept_these_nonmembers'] is meaningless. What is list_name.settings?
I'm doing it in mailman shell, list_name is a List object, and it seems to have a settings
attribute as list_name.settings returns
{'acceptable_aliases': [], 'accept_these_nonmembers': [], 'admin_immed_notify': True, 'admin_notify_mchanges': False, 'administrivia': True, 'advertised': False, 'allow_list_posts': True, 'anonymous_list': False, 'archive_policy': 'public', 'archive_rendering_mode': 'text', 'autorespond_owner': 'none', 'autorespond_postings': 'none', 'autorespond_requests': 'none', 'autoresponse_grace_period': '90d', 'autoresponse_owner_text': '', 'autoresponse_postings_text': '', 'autoresponse_request_text': '', 'bounces_address': 'systems-logs-bounces@lists.sugarlabs.org', 'bounce_info_stale_after': '7d', 'bounce_notify_owner_on_bounce_increment': False, 'bounce_notify_owner_on_disable': True, 'bounce_notify_owner_on_removal': True, 'bounce_score_threshold': 5, 'bounce_you_are_disabled_warnings': 3, 'bounce_you_are_disabled_warnings_interval': '7d', 'collapse_alternatives': True, 'convert_html_to_plaintext': False, 'created_at': '2026-02-04T21:53:10.928951', 'default_member_action': 'defer', 'default_nonmember_action': 'accept', 'description': '', 'digest_last_sent_at': '2026-02-26T10:54:11.703949', 'digest_send_periodic': True, 'digest_size_threshold': 30.0, 'digest_volume_frequency': 'monthly', 'digests_enabled': True, 'display_name': 'Systems-logs', 'discard_these_nonmembers': [], 'dmarc_mitigate_action': 'no_mitigation', 'dmarc_mitigate_unconditionally': False, 'dmarc_addresses': [], 'dmarc_moderation_notice': '', 'dmarc_wrapped_message_text': '', 'emergency': False, 'filter_action': 'discard', 'filter_content': False, 'filter_extensions': [], 'filter_types': [], 'first_strip_reply_to': False, 'forward_unrecognized_bounces_to': 'administrators', 'fqdn_listname': 'systems-logs@lists.sugarlabs.org', 'gateway_to_mail': False, 'gateway_to_news': False, 'hold_these_nonmembers': [], 'include_rfc2369_headers': True, 'info': '', 'join_address': 'systems-logs-join@lists.sugarlabs.org', 'last_post_at': '2026-02-26T11:28:37.171138', 'leave_address': 'systems-logs-leave@lists.sugarlabs.org', 'linked_newsgroup': '', 'list_name': 'systems-logs', 'mail_host': 'lists.sugarlabs.org', 'max_message_size': 40, 'max_num_recipients': 10, 'max_days_to_hold': 0, 'member_roster_visibility': 'moderators', 'moderator_password': None, 'newsgroup_moderation': 'none', 'next_digest_number': 53, 'nntp_prefix_subject_too': True, 'no_reply_address': 'noreply@lists.sugarlabs.org', 'owner_address': 'systems-logs-owner@lists.sugarlabs.org', 'pass_types': [], 'pass_extensions': [], 'personalize': 'none', 'post_id': 298, 'posting_address': 'systems-logs@lists.sugarlabs.org', 'posting_pipeline': 'default-posting-pipeline', 'preferred_language': 'en', 'process_bounces': True, 'reject_these_nonmembers': [], 'reply_goes_to_list': 'no_munging', 'reply_to_address': '', 'request_address': 'systems-logs-request@lists.sugarlabs.org', 'require_explicit_destination': True, 'respond_to_post_requests': True, 'send_goodbye_message': True, 'send_welcome_message': True, 'subject_prefix': '[Systems-logs] ', 'subscription_policy': 'confirm', 'unsubscription_policy': 'confirm', 'usenet_watermark': None, 'volume': 1}
-- Mark Sapiro <mark@msapiro.net> The highway is for gamblers, San Francisco Bay Area, California better use your sense - B. Dylan
On 2/26/26 13:20, Ibiam Chihurumnaya via Mailman-users wrote:
I'm doing it in
mailman shell, list_name is a List object, and it seems to have asettingsattribute aslist_name.settingsreturns{'acceptable_aliases': [], ...}
I would really like to know what Mailman version this is, and how it was installed? In my case with Mailman core from the head of the GitLab branch:
$ mailman shell -l list.example.com
Welcome to the GNU Mailman shell
Use commit() to commit changes.
Use abort() to discard changes since the last commit.
Exit with ctrl+D does an implicit commit() but exit() does not.
The variable 'm' is the list.example.com mailing list
>>> m.settings
Traceback (most recent call last):
File "<console>", line 1, in <module>
AttributeError: 'MailingList' object has no attribute 'settings'
>>> m.settings['accept_these_nonmembers']
Traceback (most recent call last):
File "<console>", line 1, in <module>
AttributeError: 'MailingList' object has no attribute 'settings'
>>>
Presumably in your case, you could do
list_name.settings['accept_these_nonmembers'].append('user@example.com')
or
list_name.settings['accept_these_nonmembers'].extend(['user1@example.com',
'user2@example.com', 'user3@example.com'])
but as I've said previously, accept_these_nonmembers is not the
preferred way to do this. Something like
$ mailman addmembers --delivery disabled FILE LIST
where FILE contains the addresses to add, one per line and LIST is the list name would add the addresses as members with delivery disabled. To add them as nonmembers with moderation_action Defer:
$ mailman shell -l list.example.com
Welcome to the GNU Mailman shell
Use commit() to commit changes.
Use abort() to discard changes since the last commit.
Exit with ctrl+D does an implicit commit() but exit() does not.
The variable 'm' is the list.example.com mailing list
>>> from mailman.app.membership import add_member
>>> addresses = ('user1@example.com', 'user2@example.com',
... 'user3@example.com')
>>> for addr in addresses:
... rr = RequestRecord(addr)
... nm = add_member(m, rr, role=MemberRole.nonmember)
... nm.moderation_action = Action.defer
...
>>>commit()
Of course, all of this can be done, perhaps more easily, using the Postorius web UI.
-- Mark Sapiro <mark@msapiro.net> The highway is for gamblers, San Francisco Bay Area, California better use your sense - B. Dylan
Mark Sapiro wrote:
On 2/26/26 13:20, Ibiam Chihurumnaya via Mailman-users wrote:
I'm doing it in mailman shell, list_name is a List object, and it seems to have a settings attribute as list_name.settings returns {'acceptable_aliases': [], ...} I would really like to know what Mailman version this is, and how it was installed? In my case with Mailman core from the head of the GitLab branch: $ mailman shell -l list.example.com Welcome to the GNU Mailman shell Use commit() to commit changes. Use abort() to discard changes since the last commit. Exit with ctrl+D does an implicit commit() but exit() does not. The variable 'm' is the list.example.com mailing list
m.settings Traceback (most recent call last): File "<console>", line 1, in <module> AttributeError: 'MailingList' object has no attribute 'settings' m.settings['accept_these_nonmembers'] Traceback (most recent call last): File "<console>", line 1, in <module> AttributeError: 'MailingList' object has no attribute 'settings'
Currently running Mailman 3.3.10 and I followed the instructions from https://docs.mailman3.org/en/latest/install/virtualenv.html# to install.
This is the output from mine, I get the same output as you do when I try exactly what you do;
mailman shell -l systems-logs@lists.sugarlabs.org Welcome to the GNU Mailman shell Use commit() to commit changes. Use abort() to discard changes since the last commit. Exit with ctrl+D does an implicit commit() but exit() does not. The variable 'm' is the systems-logs@lists.sugarlabs.org mailing list
m.settings Traceback (most recent call last): File "<console>", line 1, in <module> AttributeError: 'MailingList' object has no attribute 'settings'
I get something else when I do it differently - how I've been doing it so far -.
mailman shell Welcome to the GNU Mailman shell Use commit() to commit changes. Use abort() to discard changes since the last commit. Exit with ctrl+D does an implicit commit() but exit() does not.
from mailmanclient import Client from mailmanclient import Client client = Client('http://localhost:8001/3.1', '**', '**') sg = client.domains[0] sy = sg.get_lists()[-1] sy <List 'systems-logs@lists.sugarlabs.org'> sy.settings {'acceptable_aliases': [], 'accept_these_nonmembers': [], 'admin_immed_notify': True, 'admin_notify_mchanges': False, 'administrivia': True, 'advertised': False, 'allow_list_posts': True, 'anonymous_list': False, 'archive_policy': 'public', 'archive_rendering_mode': 'text', 'autorespond_owner': 'none', 'autorespond_postings': 'none', 'autorespond_requests': 'none', 'autoresponse_grace_period': '90d', 'autoresponse_owner_text': '', 'autoresponse_postings_text': '', 'autoresponse_request_text': '', 'bounces_address': 'systems-logs-bounces@lists.sugarlabs.org', 'bounce_info_stale_after': '7d', 'bounce_notify_owner_on_bounce_increment': False, 'bounce_notify_owner_on_disable': True, 'bounce_notify_owner_on_removal': True, 'bounce_score_threshold': 5, 'bounce_you_are_disabled_warnings': 3, 'bounce_you_are_disabled_warnings_interval': '7d', 'collapse_alternatives': True, 'convert_html_to_plaintext': False, 'created_at': '2026-02-04T21:53:10.928951', 'default_member_action': 'defer', 'default_nonmember_action': 'accept', 'description': '', 'digest_last_sent_at': '2026-02-27T11:24:11.916379', 'digest_send_periodic': True, 'digest_size_threshold': 30.0, 'digest_volume_frequency': 'monthly', 'digests_enabled': True, 'display_name': 'Systems-logs', 'discard_these_nonmembers': [], 'dmarc_mitigate_action': 'no_mitigation', 'dmarc_mitigate_unconditionally': False, 'dmarc_addresses': [], 'dmarc_moderation_notice': '', 'dmarc_wrapped_message_text': '', 'emergency': False, 'filter_action': 'discard', 'filter_content': False, 'filter_extensions': [], 'filter_types': [], 'first_strip_reply_to': False, 'forward_unrecognized_bounces_to': 'administrators', 'fqdn_listname': 'systems-logs@lists.sugarlabs.org', 'gateway_to_mail': False, 'gateway_to_news': False, 'hold_these_nonmembers': [], 'include_rfc2369_headers': True, 'info': '', 'join_address': 'systems-logs-join@lists.sugarlabs.org', 'last_post_at': '2026-02-27T11:32:51.317220', 'leave_address': 'systems-logs-leave@lists.sugarlabs.org', 'linked_newsgroup': '', 'list_name': 'systems-logs', 'mail_host': 'lists.sugarlabs.org', 'max_message_size': 40, 'max_num_recipients': 10, 'max_days_to_hold': 0, 'member_roster_visibility': 'moderators', 'moderator_password': None, 'newsgroup_moderation': 'none', 'next_digest_number': 60, 'nntp_prefix_subject_too': True, 'no_reply_address': 'noreply@lists.sugarlabs.org', 'owner_address': 'systems-logs-owner@lists.sugarlabs.org', 'pass_types': [], 'pass_extensions': [], 'personalize': 'none', 'post_id': 316, 'posting_address': 'systems-logs@lists.sugarlabs.org', 'posting_pipeline': 'default-posting-pipeline', 'preferred_language': 'en', 'process_bounces': True, 'reject_these_nonmembers': [], 'reply_goes_to_list': 'no_munging', 'reply_to_address': '', 'request_address': 'systems-logs-request@lists.sugarlabs.org', 'require_explicit_destination': True, 'respond_to_post_requests': True, 'send_goodbye_message': True, 'send_welcome_message': True, 'subject_prefix': '[Systems-logs] ', 'subscription_policy': 'confirm', 'unsubscription_policy': 'confirm', 'usenet_watermark': None, 'volume': 1}
Presumably in your case, you could do list_name.settings['accept_these_nonmembers'].append('user@example.com')
or
list_name.settings['accept_these_nonmembers'].extend(['user1@example.com', 'user2@example.com', 'user3@example.com'])
but as I've said previously, accept_these_nonmembers is not the preferred way to do this. Something like $ mailman addmembers --delivery disabled FILE LIST
Yes, I see now that it's not the preferred way to do it.
It's difficult to know that when looking at the documentation.
where FILE contains the addresses to add, one per line and LIST is the list name would add the addresses as members with delivery disabled. To add them as nonmembers with moderation_action Defer: $ mailman shell -l list.example.com Welcome to the GNU Mailman shell Use commit() to commit changes. Use abort() to discard changes since the last commit. Exit with ctrl+D does an implicit commit() but exit() does not. The variable 'm' is the list.example.com mailing list
from mailman.app.membership import add_member addresses = ('user1@example.com', 'user2@example.com', ... 'user3@example.com') for addr in addresses: ... rr = RequestRecord(addr) ... nm = add_member(m, rr, role=MemberRole.nonmember) ... nm.moderation_action = Action.defer ... commit()
Thank you!
Of course, all of this can be done, perhaps more easily, using the Postorius web UI.
Yes, but like I've mentioned in another thread, I don't have access to the web UI because I can't get a confirmation link.
-- Mark Sapiro <mark@msapiro.net> The highway is for gamblers, San Francisco Bay Area, California better use your sense - B. Dylan
On 2/27/26 07:17, Ibiam Chihurumnaya via Mailman-users wrote:
Currently running Mailman 3.3.10 and I followed the instructions from https://docs.mailman3.org/en/latest/install/virtualenv.html# to install.
OK.
I get something else when I do it differently - how I've been doing it so far -.
mailman shell Welcome to the GNU Mailman shell Use commit() to commit changes. Use abort() to discard changes since the last commit. Exit with ctrl+D does an implicit commit() but exit() does not.
from mailmanclient import Client from mailmanclient import Client client = Client('http://localhost:8001/3.1', '**', '**') sg = client.domains[0] sy = sg.get_lists()[-1] sy <List 'systems-logs@lists.sugarlabs.org'> sy.settings {'acceptable_aliases': [], ...
OK. You are using Mailman Client which is a bunch of Python bindings for Mailman core's REST API and which is intended for use by HyperKitty, Postorius and Django-Mailman3 to communicate with Mailman core via its REST API.
If you are using mailman shell you already have direct access to all
of Mailman core. Using Mailman Client is just adding overhead to things
you could do directly.
If you really want to use Mailman Client, rather than invoking mailman shell and all it brings that you don't use, you could just invoke your
venv's python, e.g.,
$ /opt/mailman/venv/bin/python
or if your venv is active, just
(venv) $ python
and then import Client and continue as above.
Yes, but like I've mentioned in another thread, I don't have access to the web UI because I can't get a confirmation link.
You can always confirm your address manually
UPDATE account_emailaddress SET verified = 't' where email = 'your_address';
-- Mark Sapiro <mark@msapiro.net> The highway is for gamblers, San Francisco Bay Area, California better use your sense - B. Dylan
Mark Sapiro wrote:
On 2/27/26 07:17, Ibiam Chihurumnaya via Mailman-users wrote:
Currently running Mailman 3.3.10 and I followed the instructions from https://docs.mailman3.org/en/latest/install/virtualenv.html# to install. OK. I get something else when I do it differently - how I've been doing it so far -. mailman shell Welcome to the GNU Mailman shell Use commit() to commit changes. Use abort() to discard changes since the last commit. Exit with ctrl+D does an implicit commit() but exit() does not. from mailmanclient import Client from mailmanclient import Client client = Client('http://localhost:8001/3.1', '**', '**') sg = client.domains[0] sy = sg.get_lists()[-1] sy <List 'systems-logs@lists.sugarlabs.org'> sy.settings {'acceptable_aliases': [], ... OK. You are using Mailman Client which is a bunch of Python bindings for Mailman core's REST API and which is intended for use by HyperKitty, Postorius and Django-Mailman3 to communicate with Mailman core via its REST API.
Yes, the major reason I did this was because I wrote some helper scripts to do some things like create and delete a list, which the only domain in the mailing list selected.
I'm assuming any other way to communicate with the rest API would automatically select the only domain that exists.
It also seems to give more granular control over lists and members.
Can mailman directly provide most of this functionality?
If you are using mailman shell you already have direct access to all of Mailman core. Using Mailman Client is just adding overhead to things you could do directly. If you really want to use Mailman Client, rather than invoking mailman shell and all it brings that you don't use, you could just invoke your venv's python, e.g., $ /opt/mailman/venv/bin/python or if your venv is active, just (venv) $ python and then import Client and continue as above.
Makes sense, thank you!
Yes, but like I've mentioned in another thread, I don't have access to the web UI because I can't get a confirmation link. You can always confirm your address manually UPDATE account_emailaddress SET verified = 't' where email = 'your_address';
That worked, thank you!
-- Mark Sapiro <mark@msapiro.net> The highway is for gamblers, San Francisco Bay Area, California better use your sense - B. Dylan
I'm going go into a lot of detail. You probably don't need all of it, but I plan to integrate it into the documentation "soon-ish", so you get it too. ;-)
Ibiam Chihurumnaya via Mailman-users writes:
Yes, the major reason I did this [through the REST API] was because I wrote some helper scripts to do some things like create and delete a list, which the only domain in the mailing list selected.
I'm assuming any other way to communicate with the rest API would automatically select the only domain that exists.
Not quite true, but for all of the operations where a list is not an argument (eg, editing an Address), the domain is irrelevant, while if a list is an argument, its domain is part of its identification.
In Mailman 2, the identity of a mailing list was its localpart, and the domain was auxiliary data. In Mailman 3, the public identity of a mailing list is its List-Id, which is usually its List-Post address with the '@' replaced by '.'. The List-Post address always contains the domain of the mailing list by definition. The List-Id and List-Post address are equivalent ways to identify the list in all the Mailman API and UI contexts I can think of. (It's possible there are some where only one of them works, but scripting applications should always accept either.)
So in Mailman 3 it's not possible to operate on a list without *explicitly* specifying the domain in the List-Post address, or implicitly by using the list_id and accessing list_host.
You could write functions to check for a unique domain and then append it to the localpart to match against the List-Post address, but we don't provide any. You could also do that for the localpart and query list_id or List-Post for .startswith(localpart), and check that for uniqueness, but again we don't provide functions like that.
It also seems to give more granular control over lists and members.
In some sense, yes, on the other hand, it provides no access controls at all.
Can mailman directly provide most of this functionality?
mailman shell cannot access the Django databases, so it can't help
you with "can't confirm a user" issues directly (eg, it can't do the
SQL UPDATE command Mark recommended). (You don't need confirmation
for the superuser created by mailman-web createsuperuser, though, so
I don't understand why you had trouble logging in.)[1]
The mailman shell command can only be used on the host where the
mailman instance runs.[2] It starts a Python process which has direct
access to *all* of the data and functions that any Mailman process
does, configures it according to the mailman.cfg it finds[3], and
returns to the Python prompt. This means that you can bypass some
validation if you're skillful (or careless) enough, but if you stick
to the APIs defined in the classes defined in interfaces/*.py you
should be quite safe.
With the -l LIST_ID option, it opens a database transaction. Then
it finds that list's MailingList object and binds the identifier 'm'
to it, and finally returns to the prompt. This requires a running
database process (PostgreSQL, etc), so you *will* be able to change
the instance. Be careful when playing around! I *think* that if you
don't use -l there is no database transaction opened, unless you do
it explicitly.
From there, there are three ways to operate on the Mailman 3 instance.
Directly from Python, using the Python objects such as MailingLists, subscriptions, Users, and Addresses. You can do anything that Python can do (although there are validation methods so Really Stupid operations, like setting an Address's display name to float NaN will raise an exception ... at least I think it will <shudder/>). This does *not* require a running instance of the Mailman system, but *will* make changes to a *stopped* instance if you used the
-l LIST_IDoption or otherwise commit a transaction (eg, using "config.db.commit()"). It can also make changes to a *running* instance.If there is no REST API URL in the arguments of examples on docs.mailman3.org, then this is what is being shown. (There are a few cases where a Python callable is created that implicitly uses a REST API, so be careful. It's always easy to see where this is so.)
Using the documentation helpers such as dump_json to access a *running* instance directly via the REST API.
Using a mailmanclient Client object to access a *running* instance via *proxy objects*. These appear to be standard Python objects defined by Mailman such as addresses, users, subscriptions, and lists, but in fact use the REST API to access the objects in the running Mailman instance (a separate process).
In fact, the data of the Mailman instance is stored in the backing database (and some on disk, such as queues and digests), and these are being accessed both by the running daemons and your mailman shell process with equal privilege and equal priority. Sanity is preserved by database transactions and file locking.
Bottom line: if you have access to the instance host, the "direct from
Python" approach is most powerful and fastest, especially for common
cases of list modification operations with mailman shell -l LIST_ID.
And you can make scripts very concisely by using -r SCRIPT and placing
SCRIPT in the virtual environment "bin" directory.
Footnotes:
[1] There is also a mailman-web command is very powerful and
flexible. It has shell and dbshell subcommands, but I don't think
these are as useful to Mailman admins as mailman shell can be.
(mailman-web dbshell just runs the database's command-line client,
but you can do that more easily, as dbshell needs a --settings SETTINGS.PY option or environment variable to find the right database
manager and database!)
[2] It needs a full Mailman core installation and a mailman.cfg[2]). In theory, the REST API can operate across the Internet. In practice, that is an Extremey Bad Idea, Do NOT Do This. Also in practice, cross- node operation is used in many Docker-based instances, but that's on a private network, usually a non-routable LAN in a single host or VM.
[3] There is a complicated search process which in some cases may
create a new mailman.cfg. Always check if the mailman info command
finds the mailman.cfg you expect, usually /etc/mailman3/mailman.cfg.
If not, use the -C /path/to/mailman.cfg option. In my environments,
$ su - mailman # obviously
$ . .v/bin/activate # .v = the virtual environment
$ mailman info
always gives the expected output.
Regards, Steve
-- GNU Mailman consultant (installation, migration, customization) Sirius Open Source https://www.siriusopensource.com/ Software systems consulting in Europe, North America, and Japan
Thank you! This was helpful, would definitely be helpful in the documentation.
It was odd to me that I needed to confirm the superuser I created, the only way I could login was after I edited the db. The user does have superuser access as expected.
Ibiam Chihurumnaya via Mailman-users writes:
Thank you! This was helpful, would definitely be helpful in the documentation.
It was odd to me that I needed to confirm the superuser I created, the only way I could login was after I edited the db.
I don't understand why you would need to confirm the superuser. Since the superuser is created by the owner of the Mailman installation and the database, they can always do what you did. So createsuperuser may as well automatically confirm the address. I guess it's sort of useful in that you might typo the address.
What version of Django are you using?
-- GNU Mailman consultant (installation, migration, customization) Sirius Open Source https://www.siriusopensource.com/ Software systems consulting in Europe, North America, and Japan
Stephen J. Turnbull wrote:
Thank you! This was helpful, would definitely be helpful in the documentation. It was odd to me that I needed to confirm the superuser I created, the only way I could login was after I edited the db. I don't understand why you would need to confirm the superuser. Since
Ibiam Chihurumnaya via Mailman-users writes: the superuser is created by the owner of the Mailman installation and the database, they can always do what you did. So createsuperuser may as well automatically confirm the address. I guess it's sort of useful in that you might typo the address. What version of Django are you using?
Currently on 5.2.10, I didn't typo the address because before I edited the table in the DB, the login page for said user asked me to check for the confirmation email and the address shown on that page was the right one.
Ibiam Chihurumnaya via Mailman-users writes:
Currently on 5.2.10,
I don't think we officially support that yet. I will check if they have changed the semantics of createsuperuser in this way.
I didn't typo the address
I'm sorry, I was not clear enough. I didn't mean that *you* typoed, I meant that *if* *somebody* typoed and they didn't get the expected confirmation mail, they would know to fix it. That's the only reason I can think of to require confirmation with createsuperuser.
Regards, Steve
-- GNU Mailman consultant (installation, migration, customization) Sirius Open Source https://www.siriusopensource.com/ Software systems consulting in Europe, North America, and Japan
Stephen J. Turnbull wrote:
Ibiam Chihurumnaya via Mailman-users writes:
Currently on 5.2.10, I don't think we officially support that yet. I will check if they have changed the semantics of createsuperuser in this way.
mailman depends on django so it probably handled the installation and determined the version, so this seems odd.
I didn't typo the address I'm sorry, I was not clear enough. I didn't mean that *you* typoed, I meant that *if* *somebody* typoed and they didn't get the expected confirmation mail, they would know to fix it. That's the only reason I can think of to require confirmation with createsuperuser.
That makes sense.
participants (3)
-
Ibiam Chihurumnaya -
Mark Sapiro -
Stephen J. Turnbull