Add per list member roster visibility option
[mailman.git] / src / mailman / rest / docs / listconf.rst
blobe0aff10a9ad03e037cad7cd2cbb37d6d82738da6
1 ==========================
2 Mailing list configuration
3 ==========================
5 Mailing lists can be configured via the REST API.
7     >>> mlist = create_list('ant@example.com')
8     >>> transaction.commit()
11 Reading a configuration
12 =======================
14 All readable attributes for a list are available on a sub-resource.
16     >>> dump_json('http://localhost:9001/3.0/lists/ant@example.com/config')
17     acceptable_aliases: []
18     admin_immed_notify: True
19     admin_notify_mchanges: False
20     administrivia: True
21     advertised: True
22     allow_list_posts: True
23     anonymous_list: False
24     archive_policy: public
25     autorespond_owner: none
26     autorespond_postings: none
27     autorespond_requests: none
28     autoresponse_grace_period: 90d
29     autoresponse_owner_text:
30     autoresponse_postings_text:
31     autoresponse_request_text:
32     bounces_address: ant-bounces@example.com
33     collapse_alternatives: True
34     convert_html_to_plaintext: False
35     created_at: 20...T...
36     default_member_action: defer
37     default_nonmember_action: hold
38     description:
39     digest_footer_uri:
40     digest_header_uri:
41     digest_last_sent_at: None
42     digest_send_periodic: True
43     digest_size_threshold: 30.0
44     digest_volume_frequency: monthly
45     digests_enabled: True
46     display_name: Ant
47     dmarc_mitigate_action: no_mitigation
48     dmarc_mitigate_unconditionally: False
49     dmarc_moderation_notice:
50     dmarc_wrapped_message_text:
51     filter_content: False
52     first_strip_reply_to: False
53     footer_uri:
54     fqdn_listname: ant@example.com
55     goodbye_message_uri:
56     header_uri:
57     http_etag: "..."
58     include_rfc2369_headers: True
59     info:
60     join_address: ant-join@example.com
61     last_post_at: None
62     leave_address: ant-leave@example.com
63     list_name: ant
64     mail_host: example.com
65     max_message_size: 40
66     max_num_recipients: 10
67     member_roster_visibility: moderators
68     moderator_password: None
69     next_digest_number: 1
70     no_reply_address: noreply@example.com
71     owner_address: ant-owner@example.com
72     post_id: 1
73     posting_address: ant@example.com
74     posting_pipeline: default-posting-pipeline
75     reply_goes_to_list: no_munging
76     reply_to_address:
77     request_address: ant-request@example.com
78     require_explicit_destination: True
79     respond_to_post_requests: True
80     send_welcome_message: True
81     subject_prefix: [Ant]
82     subscription_policy: confirm
83     volume: 1
84     welcome_message_uri:
87 Changing the full configuration
88 ===============================
90 Not all of the readable attributes can be set through the web interface.  The
91 ones that can, can either be set via ``PUT`` or ``PATCH``.  ``PUT`` changes
92 all the writable attributes in one request.
94 When using ``PUT``, all writable attributes must be included.
96     >>> dump_json('http://localhost:9001/3.0/lists/'
97     ...           'ant@example.com/config',
98     ...           dict(
99     ...             acceptable_aliases=['one@example.com', 'two@example.com'],
100     ...             admin_immed_notify=False,
101     ...             admin_notify_mchanges=True,
102     ...             administrivia=False,
103     ...             advertised=False,
104     ...             anonymous_list=True,
105     ...             archive_policy='never',
106     ...             autorespond_owner='respond_and_discard',
107     ...             autorespond_postings='respond_and_continue',
108     ...             autorespond_requests='respond_and_discard',
109     ...             autoresponse_grace_period='45d',
110     ...             autoresponse_owner_text='the owner',
111     ...             autoresponse_postings_text='the mailing list',
112     ...             autoresponse_request_text='the robot',
113     ...             display_name='Fnords',
114     ...             description='This is my mailing list',
115     ...             include_rfc2369_headers=False,
116     ...             info='This is the mailing list information',
117     ...             allow_list_posts=False,
118     ...             digest_send_periodic=False,
119     ...             digest_size_threshold=10.5,
120     ...             digest_volume_frequency='yearly',
121     ...             digests_enabled=False,
122     ...             dmarc_mitigate_action='munge_from',
123     ...             dmarc_mitigate_unconditionally=False,
124     ...             dmarc_moderation_notice='Some moderation notice',
125     ...             dmarc_wrapped_message_text='some message text',
126     ...             posting_pipeline='virgin',
127     ...             filter_content=True,
128     ...             first_strip_reply_to=True,
129     ...             convert_html_to_plaintext=True,
130     ...             collapse_alternatives=False,
131     ...             reply_goes_to_list='point_to_list',
132     ...             reply_to_address='bee@example.com',
133     ...             require_explicit_destination=False,
134     ...             member_roster_visibility='members',
135     ...             send_welcome_message=False,
136     ...             subject_prefix='[ant]',
137     ...             subscription_policy='moderate',
138     ...             default_member_action='hold',
139     ...             default_nonmember_action='discard',
140     ...             moderator_password='password',
141     ...             max_message_size='500',
142     ...             respond_to_post_requests=True,
143     ...             max_num_recipients='20',
144     ...             ),
145     ...           'PUT')
146     content-length: 0
147     date: ...
148     server: WSGIServer/...
149     status: 204
151 These values are changed permanently.
153     >>> dump_json('http://localhost:9001/3.0/lists/'
154     ...           'ant@example.com/config')
155     acceptable_aliases: ['one@example.com', 'two@example.com']
156     admin_immed_notify: False
157     admin_notify_mchanges: True
158     administrivia: False
159     advertised: False
160     allow_list_posts: False
161     anonymous_list: True
162     archive_policy: never
163     autorespond_owner: respond_and_discard
164     autorespond_postings: respond_and_continue
165     autorespond_requests: respond_and_discard
166     autoresponse_grace_period: 45d
167     autoresponse_owner_text: the owner
168     autoresponse_postings_text: the mailing list
169     autoresponse_request_text: the robot
170     ...
171     collapse_alternatives: False
172     convert_html_to_plaintext: True
173     ...
174     default_member_action: hold
175     default_nonmember_action: discard
176     description: This is my mailing list
177     ...
178     digest_send_periodic: False
179     digest_size_threshold: 10.5
180     digest_volume_frequency: yearly
181     digests_enabled: False
182     display_name: Fnords
183     dmarc_mitigate_action: munge_from
184     dmarc_mitigate_unconditionally: False
185     dmarc_moderation_notice: Some moderation notice
186     dmarc_wrapped_message_text: some message text
187     filter_content: True
188     first_strip_reply_to: True
189     footer_uri:
190     fqdn_listname: ant@example.com
191     ...
192     include_rfc2369_headers: False
193     ...
194     member_roster_visibility: members
195     moderator_password: {plaintext}password
196     ...
197     posting_pipeline: virgin
198     reply_goes_to_list: point_to_list
199     reply_to_address: bee@example.com
200     ...
201     require_explicit_destination: False
202     respond_to_post_requests: True
203     send_welcome_message: False
204     subject_prefix: [ant]
205     subscription_policy: moderate
206     ...
209 Changing a partial configuration
210 ================================
212 Using ``PATCH``, you can change just one attribute.
214     >>> dump_json('http://localhost:9001/3.0/lists/'
215     ...           'ant@example.com/config',
216     ...           dict(display_name='My List'),
217     ...           'PATCH')
218     content-length: 0
219     date: ...
220     server: ...
221     status: 204
223 These values are changed permanently.
225     >>> print(mlist.display_name)
226     My List
229 Sub-resources
230 =============
232 Mailing list configuration variables are actually available as sub-resources
233 on the mailing list.  Their values can be retrieved and set through the
234 sub-resource.
237 Simple resources
238 ----------------
240 You can view the current value of the sub-resource.
242     >>> dump_json('http://localhost:9001/3.0/lists/ant.example.com'
243     ...           '/config/display_name')
244     display_name: My List
245     http_etag: ...
247 The resource can be changed by PUTting to it.  Note that the value still
248 requires a dictionary, and that dictionary must have a single key matching the
249 name of the resource.
252     >>> dump_json('http://localhost:9001/3.0/lists/ant.example.com'
253     ...           '/config/display_name',
254     ...           dict(display_name='Your List'),
255     ...           'PUT')
256     content-length: 0
257     date: ...
258     server: ...
259     status: 204
261     >>> dump_json('http://localhost:9001/3.0/lists/ant.example.com'
262     ...           '/config/display_name')
263     display_name: Your List
264     http_etag: ...
266 PATCH works the same way, with the same effect, so you can choose to use
267 either method.
269     >>> dump_json('http://localhost:9001/3.0/lists/ant.example.com'
270     ...           '/config/display_name',
271     ...           dict(display_name='Their List'),
272     ...           'PATCH')
273     content-length: 0
274     date: ...
275     server: ...
276     status: 204
278     >>> dump_json('http://localhost:9001/3.0/lists/ant.example.com'
279     ...           '/config/display_name')
280     display_name: Their List
281     http_etag: ...
284 Acceptable aliases
285 ------------------
287 These are recipient aliases that can be used in the ``To:`` and ``CC:``
288 headers instead of the posting address.  They are often used in forwarded
289 emails.  By default, a mailing list has no acceptable aliases.
291     >>> from mailman.interfaces.mailinglist import IAcceptableAliasSet
292     >>> IAcceptableAliasSet(mlist).clear()
293     >>> transaction.commit()
294     >>> dump_json('http://localhost:9001/3.0/lists/'
295     ...           'ant@example.com/config/acceptable_aliases')
296     acceptable_aliases: []
297     http_etag: "..."
299 We can add a few by ``PUT``-ing them on the sub-resource.  The keys in the
300 dictionary are ignored.
302     >>> dump_json('http://localhost:9001/3.0/lists/'
303     ...           'ant@example.com/config/acceptable_aliases',
304     ...           dict(acceptable_aliases=['foo@example.com',
305     ...                                    'bar@example.net']),
306     ...           'PUT')
307     content-length: 0
308     date: ...
309     server: WSGIServer/...
310     status: 204
312 You can get all the mailing list's acceptable aliases through the REST API.
314     >>> response = call_http(
315     ...     'http://localhost:9001/3.0/lists/'
316     ...     'ant@example.com/config/acceptable_aliases')
317     >>> for alias in response['acceptable_aliases']:
318     ...     print(alias)
319     bar@example.net
320     foo@example.com
322 The mailing list has its aliases set.
324     >>> from mailman.interfaces.mailinglist import IAcceptableAliasSet
325     >>> aliases = IAcceptableAliasSet(mlist)
326     >>> for alias in sorted(aliases.aliases):
327     ...     print(alias)
328     bar@example.net
329     foo@example.com
331 The aliases can be removed by using ``DELETE``.
333     >>> response = call_http(
334     ...     'http://localhost:9001/3.0/lists/'
335     ...     'ant@example.com/config/acceptable_aliases',
336     ...     method='DELETE')
337     content-length: 0
338     date: ...
339     server: WSGIServer/...
340     status: 204
342 Now the mailing list has no aliases.
344     >>> aliases = IAcceptableAliasSet(mlist)
345     >>> print(len(list(aliases.aliases)))
346     0
349 Header matches
350 --------------
352 Mailman can do pattern based header matching during its normal rule
353 processing.  Each mailing list can also be configured with a set of header
354 matching regular expression rules.  These can be used to impose list-specific
355 header filtering with the same semantics as the global ``[antispam]`` section,
356 or to have a different action.
358 The list of header matches for a mailing list are returned on the
359 ``header-matches`` child of this list.
361     >>> dump_json('http://localhost:9001/3.0/lists/ant.example.com'
362     ...           '/header-matches')
363     http_etag: "..."
364     start: 0
365     total_size: 0
367 New header matches can be created by POSTing to the resource.
370     >>> dump_json('http://localhost:9001/3.0/lists/ant.example.com'
371     ...           '/header-matches', {
372     ...           'header': 'X-Spam-Flag',
373     ...           'pattern': '^Yes',
374     ...           })
375     content-length: 0
376     ...
377     location: .../3.0/lists/ant.example.com/header-matches/0
378     ...
379     status: 201
381     >>> dump_json('http://localhost:9001/3.0/lists/ant.example.com'
382     ...           '/header-matches/0')
383     header: x-spam-flag
384     http_etag: "..."
385     pattern: ^Yes
386     position: 0
387     self_link: http://localhost:9001/3.0/lists/ant.example.com/header-matches/0
389 To follow the global antispam action, the header match rule must not specify
390 an ``action`` key, which names the chain to jump to if the rule matches.  If
391 the default antispam action is changed in the configuration file and Mailman
392 is restarted, those rules will get the new jump action.  If a specific action
393 is desired, the ``action`` key must name a valid chain to jump to.
396     >>> dump_json('http://localhost:9001/3.0/lists/ant.example.com'
397     ...           '/header-matches', {
398     ...           'header': 'X-Spam-Status',
399     ...           'pattern': '^Yes',
400     ...           'action': 'discard',
401     ...           })
402     content-length: 0
403     ...
404     location: .../3.0/lists/ant.example.com/header-matches/1
405     ...
406     status: 201
408     >>> dump_json('http://localhost:9001/3.0/lists/ant.example.com'
409     ...           '/header-matches/1')
410     action: discard
411     header: x-spam-status
412     http_etag: "..."
413     pattern: ^Yes
414     position: 1
415     self_link: http://localhost:9001/3.0/lists/ant.example.com/header-matches/1
417 The resource can be changed by PATCHing it.  The ``position`` key can be used
418 to change the priority of the header match in the list.  If it is not supplied,
419 the priority is not changed.
422     >>> dump_json('http://localhost:9001/3.0/lists/ant.example.com'
423     ...           '/header-matches/1',
424     ...           dict(pattern='^No', action='accept'),
425     ...           'PATCH')
426     content-length: 0
427     date: ...
428     server: ...
429     status: 204
430     >>> dump_json('http://localhost:9001/3.0/lists/ant.example.com'
431     ...           '/header-matches/1')
432     action: accept
433     header: x-spam-status
434     http_etag: "..."
435     pattern: ^No
436     position: 1
437     self_link: http://localhost:9001/3.0/lists/ant.example.com/header-matches/1
439     >>> dump_json('http://localhost:9001/3.0/lists/ant.example.com'
440     ...           '/header-matches/1',
441     ...           dict(position=0),
442     ...           'PATCH')
443     content-length: 0
444     date: ...
445     server: ...
446     status: 204
447     >>> dump_json('http://localhost:9001/3.0/lists/ant.example.com'
448     ...           '/header-matches')
449     entry 0:
450         action: accept
451         header: x-spam-status
452         http_etag: "..."
453         pattern: ^No
454         position: 0
455         self_link: .../lists/ant.example.com/header-matches/0
456     entry 1:
457         header: x-spam-flag
458         http_etag: "..."
459         pattern: ^Yes
460         position: 1
461         self_link: .../lists/ant.example.com/header-matches/1
462     http_etag: "..."
463     start: 0
464     total_size: 2
466 The PUT method can replace an entire header match.  The ``position`` key is
467 optional; if it is omitted, the order will not be changed.
470     >>> dump_json('http://localhost:9001/3.0/lists/ant.example.com'
471     ...           '/header-matches/1',
472     ...           dict(header='X-Spam-Status',
473     ...                pattern='^Yes',
474     ...                action='hold',
475     ...           ), 'PUT')
476     content-length: 0
477     date: ...
478     server: ...
479     status: 204
481     >>> dump_json('http://localhost:9001/3.0/lists/ant.example.com'
482     ...           '/header-matches/1')
483     action: hold
484     header: x-spam-status
485     http_etag: "..."
486     pattern: ^Yes
487     position: 1
488     self_link: http://localhost:9001/3.0/lists/ant.example.com/header-matches/1
490 A header match can be removed using the DELETE method.
493     >>> dump_json('http://localhost:9001/3.0/lists/ant.example.com'
494     ...           '/header-matches/1',
495     ...           method='DELETE')
496     content-length: 0
497     ...
498     status: 204
500     >>> dump_json('http://localhost:9001/3.0/lists/ant.example.com'
501     ...           '/header-matches')
502     entry 0:
503         action: accept
504         header: x-spam-status
505         http_etag: "..."
506         pattern: ^No
507         position: 0
508         self_link: .../lists/ant.example.com/header-matches/0
509     http_etag: "..."
510     start: 0
511     total_size: 1
513 The mailing list's header matches can be cleared by issuing a DELETE request on
514 the top resource.
517     >>> dump_json('http://localhost:9001/3.0/lists/ant.example.com'
518     ...           '/header-matches',
519     ...           method='DELETE')
520     content-length: 0
521     ...
522     status: 204
524     >>> dump_json('http://localhost:9001/3.0/lists/ant.example.com'
525     ...           '/header-matches')
526     http_etag: "..."
527     start: 0
528     total_size: 0