# Configuring Mailman

Mailman is configured via an “ini”-style configuration file, usually called `mailman.cfg`. Most of the defaults produce a usable system, but you will almost certainly have to set up a few things before you run Mailman for the first time. You only need to include those settings which you want to change; everything else is inherited.

These file system paths are searched in the following order to find your site’s custom `mailman.cfg` file. The first file found is used.

- The file system path specified by the environment variable `$MAILMAN_CONFIG_FILE`

- `mailman.cfg` in the current working directory

- `var/etc/mailman.cfg` relative to the current working directory

- `$HOME/.mailman.cfg`

- `/etc/mailman.cfg`

- `/etc/mailman3/mailman.cfg`

- `../../etc/mailman.cfg` relative to the working directory of `argv[0]`

You can also use the `-C` option to specify an explicit path, and this always takes precedence. See `mailman --help` for more details.

You must restart Mailman for any changes to take effect.

## Which configuration file is in use?

Mailman itself will tell you which configuration file is being used when you run the `mailman info` command:

    $ mailman info
    GNU Mailman 3.1.0b4 (Between The Wheels)
    Python 3.5.3 (default, Jan 19 2017, 14:11:04)
    [GCC 6.3.0 20170118]
    config file: /home/mailman/var/etc/mailman.cfg
    db url: sqlite:////home/mailman/var/data/mailman.db
    devmode: DISABLED
    REST root url: http://localhost:8001/3.1/
    REST credentials: restadmin:restpass

The first time you run this command it will create the configuration file and directory using the built-in defaults, so use `-C` to specify an alternative location. Of course the `info` subcommand shows you other interesting things about your Mailman instance.

## Schemas, templates, and master sections

Mailman’s configuration system is built on top of lazr.config although in general the details aren’t important. Basically there is a `schema.cfg` file included in the source tree, which defines all the available sections and variables, along with global defaults. There is a built-in base `mailman.cfg` file also included in the source tree, which further refines the defaults.

Your custom `mailman.cfg` file, found using the search locations described above, provides the final override for these settings.

The `schema.cfg` file describes every section, variable, and permissible values, so you should consult this for more details. The `schema.cfg` file is included verbatim below.

You will notice two types of special sections in the `schema.cfg` files; those that end with the `.template` suffix, and others which end in a `.master` suffix. There are no other special sections.

Templates provide exactly that: a template for other similarly named sections. So for example, you will see a section labeled `logging.template` which provides some configuration variables and some basic defaults. You will also see a section called `logging.bounce` which refines the `logging.template` section by overriding one or more settings.

If you wanted to change the default logging level for the database component in Mailman, say from `warn` to `info`, you would add this to your `mailman.cfg` file:

    [logging.database]
    level: info

Generally you won’t add new template specialization sections; everything you need is already defined.

You will also see sections labeled with the `.master` suffix. For the most part you can treat these exactly the same as `.template` sections; the differences are only relevant for Mailman developers [1]. An example of a `.master` section is `[runner.master]` which is used to define the defaults for all the runner processes. This is specialized in the built-in `mailman.cfg` file, where you’ll see sections like `[runner.archive]` and `[runner.in]`. You won’t need to specially the master section yourself, but instead you can override some settings in the individual runner sections.

## How do I change a setting?

If you think you want to change something, it can be a little tricky to find exactly the setting you’ll need. The first step is to use the `mailman conf` command to print all the current variables and their values. With no options, this will print all the hundreds of (sorted!) available settings to standard output. You can narrow this down in two ways. You can print just the values of a particular section:

    $ mailman conf -s webservice
    [webservice] admin_pass: restpass
    [webservice] admin_user: restadmin
    [webservice] api_version: 3.1
    [webservice] hostname: localhost
    [webservice] port: 8001
    [webservice] show_tracebacks: yes
    [webservice] use_https: no

Let’s say you wanted to change the port the REST API listens on. Just add this to your `mailman.cfg` file:

    [webservice]
    port: 8080

You can also search for a specific setting:

    $ mailman conf -k prompt
    [shell] prompt: >>>

The `mailman conf` command does not provide documentation about sections or variables. In order to get more information about what a particular variable controls, read the `schema.cfg` and built-in base `mailman.cfg` file.

## Configuration Options

### `[mailman]`

#### site_owner

default: changeme@example.com

> This address is the “site owner” address. Certain messages which must be delivered to a human, but which can’t be delivered to a list owner (e.g. a bounce from a list owner), will be sent to this address. It should point to a human.

#### noreply_address

default: noreply

> This is the local-part of an email address used in the From field whenever a message comes from some entity to which there is no natural reply recipient. Mailman will append ‘@’ and the host name of the list involved. This address must not bounce and it must not point to a Mailman process.

#### default_language

default: en

> The default language for this server.

#### sender_headers

default: from from_ reply-to sender

> Membership tests for posting purposes are usually performed by looking at a set of headers, passing the test if any of their values match a member of the list. Headers are checked in the order given in this variable. The value From_ means to use the envelope sender. Field names are case insensitive. This is a space separate list of headers.

#### anonymous_list_keep_headers

default: ^x-mailman- ^x-content-filtered-by: ^x-topics: ^x-ack: ^x-beenthere: ^x-list-administrivia: ^x-spam-

> This is a space separated list of regexps which match headers to be kept in messages to anonymous lists. Many headers are removed from posts to anonymous lists before this is consulted, but of the remaining headers, any X-* headers that don’t match one of these patterns are also removed. The X-* headers kept by default are those X-* headers added by Mailman and any X-Spam- headers. The match is case-insensitive. This does not affect non X-* headers, those of which might identify senders or their domains are deleted or replaced.

#### email_commands_max_lines

default: 10

> Mail command processor will ignore mail command lines after designated max.

#### pending_request_life

default: 3d

> Default length of time a pending request is live before it is evicted from the pending database.

#### moderator_request_life

default: 180d

> Default lifetime of pending moderator requests as opposed to the above which is for user confirmations.

#### dsn_lifetime

default: 1d

> Default lifetime of saved bounce DSNs. This doesn’t need to be long. They only need to be saved so they can be attached to admin notices which are normally sent immediately, but by an asynchronous process.

#### cache_life

default: 7d

> How long should files be saved before they are evicted from the cache?

#### run_tasks_every

default: 1h

> How often should the task runner execute tasks like evicting expired pendings, workflows and cached files?

#### layout

default: here

> Which paths.* file system layout to use.

#### filtered_messages_are_preservable

default: no

> Can MIME filtered messages be preserved by list owners?

#### html_to_plain_text_command

default: /usr/bin/lynx -dump $filename

> How should text/html parts be converted to text/plain when the mailing list is set to convert HTML to plaintext? This names a command to be called, where the substitution variable $filename is filled in by Mailman, and contains the path to the temporary file that the command should read from. The command should print the converted text to stdout.

#### filter_report

default: no

> Should Mailman’s content filtering append a report of what it removed to the message?

#### listname_chars

default: [-_.0-9a-z]

> Specify what characters are allowed in list names. Characters outside of the class [-_.+=!$*{}~0-9a-z] matched case insensitively are never allowed, but this specifies a subset as the only allowable characters. This must be a valid character class regexp or the effect on list creation is unpredictable.

#### hold_digest

default: no

> Should we hold posts to lists that have a digest subject or quote the digest masthead?

#### masthead_threshold

default: 4

> If hold_digest is yes, this is the minimum number of non-blank digest masthead lines that are needed to be matched in the message for it to be considered as quoting the masthead.

#### check_max_size_on_filtered_message

default: no

> Should we check maximum message size against content filtered message?

#### pre_hook

#### post_hook

> These hooks are deprecated, but are kept here so as not to break existing configuration files. However, these hooks are not run. Define a plugin instead.

### `[shell]`

> mailman shell (also withlist) gives you an interactive prompt that you can use to interact with an initialized and configured Mailman system. Use –help for more information. This section allows you to configure certain aspects of this interactive shell.

#### prompt

default: >>>

> Customize the interpreter prompt.

#### banner

default: 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.

> Banner to show on startup.

#### use_ipython

default: no

> Use IPython as the shell, which must be found on the system. Valid values are no, yes, and debug where the latter is equivalent to yes except that any import errors will be displayed to stderr.

#### history_file

> Set this to allow for command line history if readline is available. This can be as simple as $var_dir/history.py to put the file in the var directory.

### `[database]`

#### class

default: mailman.database.sqlite.SQLiteDatabase

> The class implementing the IDatabase.

#### url

default: sqlite:///$DATA_DIR/mailman.db

#### debug

default: no

> Use this to set the Storm database engine URL. You generally have one primary database connection for all of Mailman. List data and most rosters will store their data in this database, although external rosters may access other databases in their own way. This string supports standard ‘configuration’ substitutions.

### `[webservice]`

#### hostname

default: localhost

> The hostname at which admin web service resources are exposed.

#### port

default: 8001

> The port at which the admin web service resources are exposed.

#### use_https

default: no

> Whether or not requests to the web service are secured through SSL.

#### show_tracebacks

default: yes

> Whether or not to show tracebacks in an HTTP response for a request that raised an exception.

#### api_version

default: 3.1

> The API version number for the current (highest) API.

#### admin_user

default: restadmin

> The administrative username.

#### admin_pass

default: restpass

> The administrative password.

#### workers

default: 2

> Number of workers to start. http://docs.gunicorn.org/en/stable/settings.htmlworkers

#### configuration

default: python:mailman.config.gunicorn

> Configuration for webservice.

### `[mta]`

#### incoming

default: mailman.mta.postfix.LMTP

> The class defining the interface to the incoming mail transport agent.

#### outgoing

default: mailman.mta.deliver.deliver

> The callable implementing delivery to the outgoing mail transport agent. This must accept three arguments, the mailing list, the message, and the message metadata dictionary.

#### smtp_host

default: localhost

#### smtp_port

default: 25

#### smtp_user

#### smtp_pass

> How to connect to the outgoing MTA. If smtp_user and smtp_pass is given, then Mailman will attempt to log into the MTA when making a new connection.

#### smtp_secure_mode

default: smtp

> One of smtp/smtps/starttls, specifies the protocol Mailman will use when connecting. Typically will correspond to smtp_port: 25 -> smtp, 465 -> smtps, 587 -> starttls.

#### smtp_verify_cert

default: yes

> When smtp_secure_mode is smtps or starttls, whether to require a server cert and verify it.

#### smtp_verify_hostname

default: yes

> When smtp_secure_mode is smtps or starttls, whether to check that the server certificate specifies the same hostname as smtp_host.

#### lmtp_host

default: 127.0.0.1

#### lmtp_port

default: 8024

> Where the LMTP server listens for connections. Use 127.0.0.1 instead of localhost for Postfix integration, because Postfix only consults DNS (e.g. not /etc/hosts).

#### max_recipients

default: 10

> Ceiling on the number of recipients that can be specified in a single SMTP transaction. Set to 0 to submit the entire recipient list in one transaction.

#### max_sessions_per_connection

default: 0

> Ceiling on the number of SMTP sessions to perform on a single socket connection. Some MTAs have limits. Set this to 0 to do as many as we like (i.e. your MTA has no limits). Set this to some number great than 0 and Mailman will close the SMTP connection and re-open it after this number of consecutive sessions.

#### max_delivery_threads

default: 0

> Maximum number of simultaneous subthreads that will be used for SMTP delivery. After the recipients list is chunked according to max_recipients, each chunk is handed off to the SMTP server by a separate such thread. If your Python interpreter was not built for threads, this feature is disabled. You can explicitly disable it in all cases by setting max_delivery_threads to 0.

#### delivery_retry_period

default: 5d

> How long should messages which have delivery failures continue to be retried? After this period of time, a message that has failed recipients will be dequeued and those recipients will never receive the message.

#### verp_delimiter

default: +

#### verp_format

default: ${bounces}+${local}=${domain}

> These variables control the format and frequency of VERP-like delivery for better bounce detection. VERP is Variable Envelope Return Path, defined here:

> http://cr.yp.to/proto/verp.txt

> This involves encoding the address of the recipient as Mailman knows it into the envelope sender address (i.e. RFC 5321 MAIL FROM). Thus, no matter what kind of forwarding the recipient has in place, should it eventually bounce, we will receive an unambiguous notice of the bouncing address.

> However, we’re technically only “VERP-like” because we’re doing the envelope sender encoding in Mailman, not in the MTA. We do require cooperation from the MTA, so you must be sure your MTA can be configured for extended address semantics.

> The first variable describes how to encode VERP envelopes. It must contain these three string interpolations, which get filled in by Mailman:

> $bounces – the list’s -bounces robot address will be set here $local – the recipient address’s local mailbox part will be set here $domain – the recipient address’s domain name will be set here

> This example uses the default below.

> FQDN list address is: mylist@dom.ain Recipient is: aperson@a.nother.dom

> The envelope sender will be mylist-bounces+aperson=a.nother.dom@dom.ain

> Note that your MTA /must/ be configured to deliver such an addressed message to mylist-bounces!

#### verp_confirm_format

default: $address+$cookie

> For nicer confirmation emails, use a VERP-like format which encodes the confirmation cookie in the reply address. This lets us put a more user friendly Subject: on the message, but requires cooperation from the MTA. Format is like verp_format, but with the following substitutions:

> $address – the list-confirm address $cookie – the confirmation cookie

#### verp_regexp

default: ^(?P<bounces>[^+]+?)+(?P<local>[^=]+)=(?P<domain>[^@]+)@.*$

> This regular expression unambiguously decodes VERP addresses, which will be placed in the To: (or other, depending on the MTA) header of the bounce message by the bouncing MTA. Getting this right is critical – and tricky. Learn your Python regular expressions. It must define exactly three named groups, bounces, local and domain, with the same definition as above. It will be compiled case-insensitively.

#### verp_confirm_regexp

default: ^(.*<)?(?P<addr>[^+]+?)+(?P<cookie>[^@]+)@.*$

> This is analogous to verp_regexp, but for splitting apart the verp_confirm_format. MUAs have been observed that mung

> From: local_part@host

> into

> To: “local_part” <local_part@host>

> when replying, so we skip everything up to ‘<’ if any.

#### verp_confirmations

default: yes

> Set this to ‘no’ to disable user friendly confirmations and avoid encoding the confirmation cookie in the reply address.

#### verp_personalized_deliveries

default: no

> Another good opportunity is when regular delivery is personalized. Here again, we’re already incurring the performance hit for addressing each individual recipient. Set this to ‘yes’ to enable VERPs on all personalized regular deliveries (personalized digests aren’t supported yet).

#### verp_delivery_interval

default: 0

> And finally, we can VERP normal, non-personalized deliveries. However, because it can be a significant performance hit, we allow you to decide how often to VERP regular deliveries. This is the interval, in number of messages, to do a VERP recipient address. The same variable controls both regular and digest deliveries. Set to 0 to disable occasional VERPs, set to 1 to VERP every delivery, or to some number > 1 for only occasional VERPs.

#### verp_probe_format

default: $bounces+$token@$domain

#### verp_probe_regexp

default: ^(?P<bounces>[^+]+?)+(?P<token>[^@]+)@.*$

#### verp_probes

default: no

> VERP format and regexp for probe messages. Set this ‘yes’ to activate VERP probe for disabling by bounce.

#### max_autoresponses_per_day

default: 10

> This is the maximum number of automatic responses sent to an address because of -request messages or posting hold messages. This limit prevents response loops between Mailman and misconfigured remote email robots. Mailman already inhibits automatic replies to any message labeled with a header “Precendence: bulk|list|junk”. This is a fallback safety valve so it should be set fairly high. Set to 0 for no limit (probably useful only for debugging).

#### remove_dkim_headers

default: no

> Some list posts and mail to the -owner address may contain DomainKey or DomainKeys Identified Mail (DKIM) signature headers <http://www.dkim.org/>. Various list transformations to the message such as adding a list header or footer or scrubbing attachments or even reply-to munging can break these signatures. It is generally felt that these signatures have value, even if broken and even if the outgoing message is resigned. However, some sites may wish to remove these headers by setting this to ‘yes’.

#### configuration

default: python:mailman.config.postfix

> Where can we find the mail server specific configuration file? The path can be either a file system path or a Python import path. If the value starts with python: then it is a Python import path, otherwise it is a file system path. File system paths must be absolute since no guarantees are made about the current working directory. Python paths should not include the trailing .cfg, which the file must end with.

### `[devmode]`

#### enabled

default: no

> Setting enabled to true enables certain safeguards and other behavior changes that make developing Mailman easier. For example, it forces the SMTP RCPT TO recipients to be a test address so that no messages are accidentally sent to real addresses.

#### recipient

> Set this to an address to force the SMTP RCPT TO recipents when devmode is enabled. This way messages can’t be accidentally sent to real addresses.

#### testing

default: no

> This gets set by the testing layers so that the runner subprocesses produce predictable dates and times.

#### wait

default: 60s

> Time-outs for starting up various test subprocesses, such as the LMTP and REST servers. This is only used for the test suite, so if you’re seeing test failures, try increasing the wait time.

### `[bounces]`

#### register_bounces_every

default: 15m

> How often should the bounce runner process queued detected bounces?

### `[ARC]`

> This section defines email authetication parameters, in particular, with respect to the ARC(Authenticated-Recieved-Chain) protocol. See http://arc-spec.org/ for reference.

> The DMARC protocol is the industry standard for cryptographically validating both the content and originating source of email. However it is regularly the case that mailing lists break this source of authentication via modifying the From, and possibly other headers, and altering the contents of emails by, say, adding a common footer to outgoing mail. The ARC protocol is the industry standard for rectify this. ARC cryptographically seals the outgoing emails by adding a collection of headers. These headers act quite analagously to a chain of DKIM signatures, where each intermediary validates the ARC signature(if one exists) of the incomming message, and then appends its own collection of header fields. Enabling this protocol makes it possible for email service providers to validate the content & originator of an email, even if it has taken multiple steps from the originator to the recipient.

> The general implementation of ARC within Mailman is addition of two additional handlers to the pipeline. One, at the very beginning of the pipeline cryptographically validaties the incomming ARC headers before the message has been modified, and appends its results to the Authentication-Results header.

> The second handler is at the end of the pipeline. It cryptographically signs the message, with all modifications that have been made, along with the analysis of the validation handler, and adds its output as a new set of ARC header fields.

#### enabled

default: no

> This flag globally enables ARC signing & validation. To enable, set this to yes.

#### dmarc

default: yes

#### dkim

default: yes

> DKIM & DMARC authentication checks on incoming email is critical to using ARC successfully. Mailman can do these check on its own, but if you already perform these checks earlier in your pipeline, say via a milter previous to Mailman, they can be used instead, as long as you specify your domain as a trusted domain below. If those checks are not placed in an Authentication-Results header from a trusted domain they will be ignored.

#### authserv_id

> This is the domain name as which Mailman identifies in any authentication headers it generates. Mandatory to set for ARC signing to work.

#### trusted_authserv_ids

> Trusted Domains

> This list should include all additional domains that you manage that may be handling your incoming mail Only necessary to update if there are local domains or subdomains that are performing DKIM, DMARC, or SPF checks.

> > trusted_authserv_ids: subdomain.your_domain.com, trusted_other_domain.com

#### privkey

#### selector

#### domain

> Key Management

> In order for your server to be able to cryptographical sign its messages a DKIM public/private key pair will need to be created. See http://www.gettingemaildelivered.com/dkim-explained-how-to-set-up-and-use-domainkeys-identified-mail-effectively for reference. The following parameters let the software find your private & public keys

> Note

> Some versions of OpenSSL generate private keys which some versions of dkimpy (the library used by Mailman for handling ARC) cannot read. This manifests in “Unparsable private key” exceptions while processing email. If you encounter this, try to regenerate the RSA key with the -traditional flag.

> ::

>   privkey: /some/location/yourprivatekey.pem selector: test domain: your_domain.com

#### sig_headers

default: From, Sender, Reply-To, Subject, Date, Message-ID, To, Cc, MIME-Version, Content-Type, Content-Transfer-Encoding, Content-ID, Content-Description, Resent-Date, Resent-From, Resent-Sender, Resent-To, Resent-Cc, Resent-Message-ID, In-Reply-To, References, List-Id, List-Help, List-Unsubscribe, List-Subscribe, List-Post, List-Owner, List-Archive

> This configures the headers that will be cryptographically signed This list is what is recommended by the DKIM & ARC specifications. Inclusion of the From header is mandatory.

### `[antispam]`

> This section defines basic antispam detection settings.

#### header_checks

> This value contains lines which specify RFC 822 headers in the email to check for spamminess. Each line contains a key: value pair, where the key is the header to check and the value is a Python regular expression to match against the header’s value. Multiple checks should be entered as multiline value with leading spaces:

>     header_checks:
>       X-Spam: (yes|maybe)
>       Authentication-Results: mail.example.com; dmarc=(fail|quarantine)

> The header value and regular expression are always matched case-insensitively.

#### jump_chain

default: hold

> The chain to jump to if any of the header patterns matches. This must be the name of an existing chain such as ‘discard’, ‘reject’, ‘hold’, or ‘accept’, otherwise ‘hold’ will be used.

### `[styles]`

#### default

default: legacy-default

> The default style to apply if nothing else was requested. The value is the name of an existing style. If no such style exists, no style will be applied.

### `[digests]`

#### mime_digest_keep_headers

default: Date From To Cc Subject Message-ID Keywords In-Reply-To References Content-Type MIME-Version Content-Transfer-Encoding Precedence Reply-To Message List-Post

> Headers which should be kept in both RFC 1153 (plain) and MIME digests. RFC 1153 also specifies these headers in this exact order, so order matters. These are space separated and case insensitive.

#### plain_digest_keep_headers

default: Message Date From Subject To Cc Message-ID Keywords Content-Type

### `[nntp]`

> The nntp runner is no longer started by default. If you are actually gating to/from usenet, you need to add [runner.nntp] start: yes to your mailman.cfg

#### user

#### password

> Set these variables if you need to authenticate to your NNTP server for Usenet posting or reading. Leave these blank if no authentication is necessary.

#### host

#### port

> Host and port of the NNTP server to connect to. Leave these blank to use the default localhost:119.

#### remove_headers

default: nntp-posting-host nntp-posting-date x-trace x-complaints-to xref date-received posted posting-version relay-version received

> This controls how headers must be cleansed in order to be accepted by your NNTP server. Some servers like INN reject messages containing prohibited headers, or duplicate headers. The NNTP server may reject the message for other reasons, but there’s little that can be programmatically done about that.

> These headers (case ignored) are removed from the original message. This is a whitespace separate list of headers.

#### rewrite_duplicate_headers

default: To X-Original-To CC X-Original-CC Content-Transfer-Encoding X-Original-Content-Transfer-Encoding MIME-Version X-MIME-Version

> These headers are left alone, unless there are duplicates in the original message. Any second and subsequent headers are rewritten to the second named header (case preserved). This is a list of header pairs, one pair per line.

#### gatenews_every

default: 5m

> The NNTP runner periodically runs the gatenews command to gate news from usenet for lists that do that. This controls how often gatenews is run.

### `[dmarc]`

> RFC 7489 - Domain-based Message Authentication, Reporting, and Conformance. https://en.wikipedia.org/wiki/DMARC

#### resolver_timeout

default: 3s

> Parameters for DMARC DNS lookups. If you are seeing ‘DNSException: Unable to query DMARC policy …’ entries in your error log, you may need to adjust these.

> The time to wait for a response from a name server before timeout.

#### resolver_lifetime

default: 5s

> The total time to spend trying to get an answer to the DNS question.

#### org_domain_data_url

default: https://publicsuffix.org/list/public_suffix_list.dat

> A URL from which to retrieve the data for the algorithm that computes Organizational Domains for DMARC policy lookup purposes. This can be anything handled by the Python urllib.request.urlopen function. See https://publicsuffix.org/list/ for info.

#### cache_lifetime

default: 7d

> How long should the local suffix list be used before it’s considered out of date. After this amount of time a new list will be downloaded, but if it can’t be accessed, old data will still be used.

> urlpatterns typically represent the urls that are used in email templates generated by Mailman Core. They key represents the $key that can be used in the templates.

> These are the url patterns for Postorius.

## schema.cfg

`schema.cfg` defines the ini-file schema and contains documentation for every section and configuration variable.

    # Copyright (C) 2008-2023 by the Free Software Foundation, Inc.
    #
    # This file is part of GNU Mailman.
    #
    # GNU Mailman 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 3 of the License, or (at your option)
    # any later version.
    #
    # GNU Mailman 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
    # GNU Mailman.  If not, see <https://www.gnu.org/licenses/>.

    # This is the GNU Mailman configuration schema.  It defines the default
    # configuration options for the core system and plugins.  It uses ini-style
    # formats under the lazr.config regime to define all system configuration
    # options.  See <https://launchpad.net/lazr.config> for details.

    [mailman]
    # This address is the "site owner" address.  Certain messages which must be
    # delivered to a human, but which can't be delivered to a list owner (e.g. a
    # bounce from a list owner), will be sent to this address.  It should point to
    # a human.
    site_owner: changeme@example.com

    # This is the local-part of an email address used in the From field whenever a
    # message comes from some entity to which there is no natural reply recipient.
    # Mailman will append '@' and the host name of the list involved.  This
    # address must not bounce and it must not point to a Mailman process.
    noreply_address: noreply

    # The default language for this server.
    default_language: en

    # Membership tests for posting purposes are usually performed by looking at a
    # set of headers, passing the test if any of their values match a member of
    # the list.  Headers are checked in the order given in this variable.  The
    # value From_ means to use the envelope sender.  Field names are case
    # insensitive.  This is a space separate list of headers.
    sender_headers: from from_ reply-to sender

    # This is a space separated list of regexps which match headers to be kept
    # in messages to anonymous lists.  Many headers are removed from posts to
    # anonymous lists before this is consulted, but of the remaining headers,
    # any X-* headers that don't match one of these patterns are also removed.
    # The X-* headers kept by default are those X-* headers added by Mailman
    # and any X-Spam- headers.  The match is case-insensitive.  This does not
    # affect non X-* headers, those of which might identify senders or their
    # domains are deleted or replaced.
    anonymous_list_keep_headers: ^x-mailman- ^x-content-filtered-by: ^x-topics:
     ^x-ack: ^x-beenthere: ^x-list-administrivia: ^x-spam-

    # Mail command processor will ignore mail command lines after designated max.
    email_commands_max_lines: 10

    # Default length of time a pending request is live before it is evicted from
    # the pending database.
    pending_request_life: 3d

    # Default lifetime of pending moderator requests as opposed to the above which
    # is for user confirmations.
    moderator_request_life: 180d

    # Default lifetime of saved bounce DSNs.  This doesn't need to be long.
    # They only need to be saved so they can be attached to admin notices which
    # are normally sent immediately, but by an asynchronous process.
    dsn_lifetime: 1d

    # How long should files be saved before they are evicted from the cache?
    cache_life: 7d

    # How often should the task runner execute tasks like evicting expired
    # pendings, workflows and cached files?
    run_tasks_every: 1h

    # Which paths.* file system layout to use.
    layout: here

    # Can MIME filtered messages be preserved by list owners?
    filtered_messages_are_preservable: no

    # How should text/html parts be converted to text/plain when the mailing list
    # is set to convert HTML to plaintext?  This names a command to be called,
    # where the substitution variable $filename is filled in by Mailman, and
    # contains the path to the temporary file that the command should read from.
    # The command should print the converted text to stdout.
    html_to_plain_text_command: /usr/bin/lynx -dump $filename

    # Should Mailman's content filtering append a report of what it removed to
    # the message?
    filter_report: no

    # Specify what characters are allowed in list names.  Characters outside of
    # the class [-_.+=!$*{}~0-9a-z] matched case insensitively are never allowed,
    # but this specifies a subset as the only allowable characters.  This must be
    # a valid character class regexp or the effect on list creation is
    # unpredictable.
    listname_chars: [-_.0-9a-z]

    # Should we hold posts to lists that have a digest subject or quote the
    # digest masthead?
    hold_digest: no

    # If hold_digest is yes, this is the minimum number of non-blank digest
    # masthead lines that are needed to be matched in the message for it to be
    # considered as quoting the masthead.
    masthead_threshold: 4

    # Should we check maximum message size against content filtered message?
    check_max_size_on_filtered_message: no

    # These hooks are deprecated, but are kept here so as not to break existing
    # configuration files.  However, these hooks are not run.  Define a plugin
    # instead.
    pre_hook:
    post_hook:

    [plugin.master]
    # Plugin configuration section template.
    #
    # To add a plugin, instantiate this section (changing `master` to whatever
    # your plugin's name is), and define at least a `path` and a `class`.  When
    # the plugin is loaded, its subpackages will be search for components matching
    # the following interfaces:
    #
    # - IChain for new chains
    # - ICliSubCommand - `mailman` subcommands
    # - IEmailCommand - new email commands
    # - IHandler for new handlers
    # - IPipeline for new pipelines
    # - IRule for new rules
    # - IStyle for new styles.
    #
    # See the IPlugin interface for more details.

    # The full Python import path for you IPlugin implementing class.  It is
    # required to provide this.
    class:

    # Whether to enable this plugin or not.
    enabled: no

    # Additional configuration file for this plugin.  If the value starts with
    # `python:` it is a Python import path, in which case the value should not
    # include the trailing .cfg (although the file is required to have this
    # suffix).  Without `python:`, it is a file system path, and must be an
    # absolute path, since no guarantees are made about the current working
    # directory.
    configuration:

    # Package (as a dotted Python import path) to search for components that this
    # plugin wants to add, such as ISTyles, IRules, etc.  If not given, the
    # plugin's name is used.
    component_package:

    [shell]
    # `mailman shell` (also `withlist`) gives you an interactive prompt that you
    # can use to interact with an initialized and configured Mailman system.  Use
    # --help for more information.  This section allows you to configure certain
    # aspects of this interactive shell.

    # Customize the interpreter prompt.
    prompt: >>>

    # Banner to show on startup.
    banner: 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.

    # Use IPython as the shell, which must be found on the system.  Valid values
    # are `no`, `yes`, and `debug` where the latter is equivalent to `yes` except
    # that any import errors will be displayed to stderr.
    use_ipython: no

    # Set this to allow for command line history if readline is available.  This
    # can be as simple as $var_dir/history.py to put the file in the var directory.
    history_file:

    [paths.master]
    # Important directories for Mailman operation.  These are defined here so that
    # different layouts can be supported.   For example, a developer layout would
    # be different from a FHS layout.  Most paths are based off the var_dir, and
    # often just setting that will do the right thing for all the other paths.
    # You might also have to set spool_dir though.
    #
    # Substitutions are allowed, but must be of the form $var where 'var' names a
    # configuration variable in the paths.* section.  Substitutions are expanded
    # recursively until no more $-variables are present.  Beware of infinite
    # expansion loops!
    #
    # This is the root of the directory structure that Mailman will use to store
    # its run-time data.
    var_dir: /var/tmp/mailman
    # This is where the Mailman queue files directories will be created.
    queue_dir: $var_dir/queue
    # This is the directory containing the Mailman 'runner' and 'master' commands
    # if set to the string '$argv', it will be taken as the directory containing
    # the 'mailman' command.
    bin_dir: $argv
    # All list-specific data.
    list_data_dir: $var_dir/lists
    # Directory where log files go.
    log_dir: $var_dir/logs
    # Directory for system-wide locks.
    lock_dir: $var_dir/locks
    # Directory for system-wide data.
    data_dir: $var_dir/data
    # Cache files.
    cache_dir: $var_dir/cache
    # Directory for configuration files and such.
    etc_dir: $var_dir/etc
    # Directory containing Mailman plugins.
    ext_dir: $var_dir/ext
    # Directory where the default IMessageStore puts its messages.
    messages_dir: $var_dir/messages
    # Directory for archive backends to store their messages in.  Archivers should
    # create a subdirectory in here to store their files.
    archive_dir: $var_dir/archives
    # Root directory for site-specific template override files.
    template_dir: $var_dir/templates
    # There are also a number of paths to specific file locations that can be
    # defined.  For these, the directory containing the file must already exist,
    # or be one of the directories created by Mailman as per above.
    #
    # This is where PID file for the master runner is stored.
    pid_file: $var_dir/master.pid
    # Lock file.
    lock_file: $lock_dir/master.lck

    [devmode]
    # Setting enabled to true enables certain safeguards and other behavior
    # changes that make developing Mailman easier.  For example, it forces the
    # SMTP RCPT TO recipients to be a test address so that no messages are
    # accidentally sent to real addresses.
    enabled: no

    # Set this to an address to force the SMTP RCPT TO recipents when devmode is
    # enabled.  This way messages can't be accidentally sent to real addresses.
    recipient:

    # This gets set by the testing layers so that the runner subprocesses produce
    # predictable dates and times.
    testing: no

    # Time-outs for starting up various test subprocesses, such as the LMTP and
    # REST servers.  This is only used for the test suite, so if you're seeing
    # test failures, try increasing the wait time.
    wait: 60s

    [passwords]
    # Where can we find the passlib configuration file?  The path can be either a
    # file system path or a Python import path.  If the value starts with python:
    # then it is a Python import path, otherwise it is a file system path.  File
    # system paths must be absolute since no guarantees are made about the current
    # working directory.  Python paths should not include the trailing .cfg, which
    # the file must end with.
    configuration: python:mailman.config.passlib

    # When Mailman generates them, this is the default length of passwords.
    password_length: 8

    [runner.master]
    # Define which runners, and how many of them, to start.

    # The full import path to the class for this runner.
    class: mailman.core.runner.Runner

    # The queue directory path that this runner scans.  This is ignored for
    # runners that don't manage a queue directory.
    path: $QUEUE_DIR/$name

    # The number of parallel runners.  This must be a power of 2.  This is ignored
    # for runners that don't manage a queue directory.
    instances: 1

    # Whether to start this runner or not.
    start: yes

    # The maximum number of restarts for this runner.  When the runner exits
    # because of an error or other unexpected problem, it is automatically
    # restarted, until the maximum number of restarts has been reached.
    max_restarts: 10

    # The sleep interval for the runner.  It wakes up once every interval to
    # process the files in its slice of the queue directory.  Some runners may
    # ignore this.
    sleep_time: 1s

    [database]
    # The class implementing the IDatabase.
    class: mailman.database.sqlite.SQLiteDatabase

    # Use this to set the Storm database engine URL.  You generally have one
    # primary database connection for all of Mailman.  List data and most rosters
    # will store their data in this database, although external rosters may access
    # other databases in their own way.  This string supports standard
    # 'configuration' substitutions.
    url: sqlite:///$DATA_DIR/mailman.db
    debug: no

    [logging.template]
    # This defines various log settings.  The options available are:
    #
    # - level     -- Overrides the default level; this may be any of the
    #                standard Python logging levels, case insensitive.
    # - format    -- Overrides the default format string
    # - datefmt   -- Overrides the default date format string
    # - path      -- Overrides the default logger path.  This may be a relative
    #                path name, in which case it is relative to Mailman's LOG_DIR,
    #                or it may be an absolute path name.  You cannot change the
    #                handler class that will be used.
    # - propagate -- Boolean specifying whether to propagate log message from this
    #                logger to the root "mailman" logger.  You cannot override
    #                settings for the root logger.
    #
    # In this section, you can define defaults for all loggers, which will be
    # prefixed by 'mailman.'.  Use subsections to override settings for specific
    # loggers.  The names of the available loggers are:
    #
    # - archiver        --  All archiver output
    # - bounce          --  All bounce processing logs go here
    # - config          --  Configuration issues
    # - database        --  Database logging (SQLAlchemy and Alembic)
    # - debug           --  Only used for development
    # - error           --  All exceptions go to this log
    # - fromusenet      --  Information related to the Usenet to Mailman gateway
    # - http            --  Internal wsgi-based web interface
    # - locks           --  Lock state changes
    # - mischief        --  Various types of hostile activity
    # - plugins         --  Plugin logs
    # - runner          --  Runner process start/stops
    # - smtp            --  SMTP activity
    # - subscribe       --  Information about leaves/joins
    # - task            --  Messages from the task runner
    # - vette           --  Message vetting information
    format: %(asctime)s (%(process)d) %(message)s
    datefmt: %b %d %H:%M:%S %Y
    propagate: no
    level: info
    path: mailman.log

    [logging.root]

    [logging.archiver]

    [logging.bounce]
    path: bounce.log

    [logging.config]

    [logging.database]
    level: warn

    [logging.debug]
    path: debug.log
    level: info

    [logging.error]

    [logging.fromusenet]

    [logging.http]

    [logging.gunicorn]
    format: %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"

    [logging.locks]

    [logging.mischief]

    [logging.plugins]
    path: plugins.log

    [logging.runner]

    [logging.smtp]
    path: smtp.log

    # The smtp logger defines additional options for handling the logging of each
    # attempted delivery.  These format strings specify what information is logged
    # for every message, every successful delivery, every refused delivery and
    # every recipient failure.  To disable a status message, set the value to 'no'
    # (without the quotes).
    #
    # These template strings accept the following set of substitution
    # placeholders, if available.
    #
    # msgid     -- the Message-ID of the message in question
    # listname  -- the fully-qualified list name
    # sender    -- the sender if available
    # recip     -- the recipient address if available, or the number of
    #              recipients being delivered to
    # size      -- the approximate size of the message in bytes
    # seconds   -- the number of seconds the operation took
    # refused   -- the number of refused recipients
    # smtpcode  -- the SMTP success or failure code
    # smtpmsg   -- the SMTP success or failure message

    every: $msgid smtp to $listname for $recip recips, completed in $time seconds
    success: $msgid post to $listname from $sender, $size bytes
    refused: $msgid post to $listname from $sender, $size bytes, $refused failures
    failure: $msgid delivery to $recip failed with code $smtpcode, $smtpmsg

    [logging.subscribe]

    [logging.task]

    [logging.vette]

    [webservice]
    # The hostname at which admin web service resources are exposed.
    hostname: localhost

    # The port at which the admin web service resources are exposed.
    port: 8001

    # Whether or not requests to the web service are secured through SSL.
    use_https: no

    # Whether or not to show tracebacks in an HTTP response for a request that
    # raised an exception.
    show_tracebacks: yes

    # The API version number for the current (highest) API.
    api_version: 3.1

    # The administrative username.
    admin_user: restadmin

    # The administrative password.
    admin_pass: restpass

    # Number of workers to start.
    # http://docs.gunicorn.org/en/stable/settings.html#workers
    workers: 2

    # Configuration for webservice.
    configuration: python:mailman.config.gunicorn

    [language.master]
    # Template for language definitions.  The section name must be [language.xx]
    # where xx is the 2-character ISO code for the language.

    # The English name for the language.
    description: English (USA)
    # And the default character set for the language.
    charset: us-ascii
    # Whether the language is enabled or not.
    enabled: yes

    # Language charsets as imported from Mailman 2.1 defaults
    # Ref: http://www.lingoes.net/en/translator/langcode.htm
    [language.ar]
    description: Arabic
    charset: utf-8
    enabled: yes

    [language.ast]
    description: Asturian
    charset: utf-8
    enabled: yes

    [language.bg]
    description: Bulgarian
    charset: utf-8
    enabled: yes

    [language.ca]
    description: Catalan
    charset: utf-8
    enabled: yes

    [language.cs]
    description: Czech
    charset: utf-8
    enabled: yes

    [language.da]
    description: Danish
    charset: utf-8
    enabled: yes

    [language.de]
    description: German
    charset: utf-8
    enabled: yes

    [language.el]
    description: Greek
    charset: utf-8
    enabled: yes

    [language.es]
    description: Spanish
    charset: utf-8
    enabled: yes

    [language.et]
    description: Estonian
    charset: utf-8
    enabled: yes

    [language.eu]
    # Basque
    description: Euskara
    charset: utf-8
    enabled: yes

    [language.fi]
    description: Finnish
    charset: utf-8
    enabled: yes

    [language.fr]
    description: French
    charset: utf-8
    enabled: yes

    [language.gl]
    description: Galician
    charset: utf-8
    enabled: yes

    [language.he]
    description: Hebrew
    charset: utf-8
    enabled: yes

    [language.hr]
    description: Croatian
    charset: utf-8
    enabled: yes

    [language.hu]
    description: Hungarian
    charset: utf-8
    enabled: yes

    [language.ia]
    description: Interlingua
    charset: utf-8
    enabled: yes

    [language.it]
    description: Italian
    charset: utf-8
    enabled: yes

    [language.ja]
    description: Japanese
    charset: utf-8
    enabled: yes

    [language.ko]
    description: Korean
    charset: utf-8
    enabled: yes

    [language.lt]
    description: Lithuanian
    charset: utf-8
    enabled: yes

    [language.nl]
    description: Dutch
    charset: utf-8
    enabled: yes

    [language.no]
    description: Norwegian
    charset: utf-8
    enabled: yes

    [language.pl]
    description: Polish
    charset: utf-8
    enabled: yes

    [language.pt]
    description: Portuguese
    charset: utf-8
    enabled: yes

    [language.pt_BR]
    description: Portuguese (Brazil)
    charset: utf-8
    enabled: yes

    [language.ro]
    description: Romanian
    charset: utf-8
    enabled: yes

    [language.ru]
    description: Russian
    charset: utf-8
    enabled: yes

    [language.sk]
    description: Slovak
    charset: utf-8
    enabled: yes

    [language.sl]
    description: Slovenian
    charset: utf-8
    enabled: yes

    [language.sr]
    description: Serbian
    charset: utf-8
    enabled: yes

    [language.sv]
    description: Swedish
    charset: utf-8
    enabled: yes

    [language.tr]
    description: Turkish
    charset: utf-8
    enabled: yes

    [language.uk]
    description: Ukrainian
    charset: utf-8
    enabled: yes

    [language.vi]
    description: Vietnamese
    charset: utf-8
    enabled: yes

    [language.zh_CN]
    description: Chinese
    charset: utf-8
    enabled: yes

    [language.zh_TW]
    description: Chinese (Taiwan)
    charset: utf-8
    enabled: yes

    [ARC]
    # This section defines email authetication parameters, in particular, with
    # respect to the ARC(Authenticated-Recieved-Chain) protocol. See
    # http://arc-spec.org/ for reference.
    #
    # The DMARC protocol is the industry standard for cryptographically validating
    # both the content and originating source of email. However it is regularly
    # the case that mailing lists break this source of authentication via modifying
    # the From, and possibly other headers, and altering the contents of
    # emails by, say, adding a common footer to outgoing mail.
    # The ARC protocol is the industry standard for rectify this.
    # ARC cryptographically seals the outgoing emails by adding a collection
    # of headers.  These headers act quite analagously to a chain of DKIM
    # signatures, where each intermediary validates the ARC signature(if one exists)
    # of the incomming message, and then appends its own collection of header fields.
    # Enabling this protocol makes it possible for email service providers
    # to validate the content & originator of an email, even if it has taken multiple
    # steps from the originator to the recipient.
    #
    # The general implementation of ARC within Mailman is addition of two
    # additional handlers to the pipeline.  One, at the very beginning of the
    # pipeline cryptographically validaties the incomming ARC headers before the
    # message has been modified, and appends its results to the
    # Authentication-Results header.
    #
    # The second handler is at the end of the pipeline.  It cryptographically
    # signs the message, with all modifications that have been made, along
    # with the analysis of the validation handler, and adds its output as
    # a new set of ARC header fields.

    # This flag globally enables ARC signing & validation. To enable, set this to
    # yes.
    enabled: no

    # DKIM & DMARC authentication checks on incoming email is critical to using ARC
    # successfully. Mailman can do these check on its own, but if you already perform
    # these checks earlier in your pipeline, say via a milter previous to Mailman,
    # they can be used instead, as long as you specify your domain as a trusted
    # domain below.  If those checks are not placed in an Authentication-Results
    # header from a trusted domain they will be ignored.
    dmarc: yes
    dkim: yes

    # This is the domain name as which Mailman identifies in any authentication
    # headers it generates. Mandatory to set for ARC signing to work.
    authserv_id:

    # Trusted Domains
    #
    # This list should include all additional domains
    # that you manage that may be handling your incoming mail
    # Only necessary to update if there are local domains or subdomains
    # that are performing DKIM, DMARC, or SPF checks.
    #
    #     trusted_authserv_ids: subdomain.your_domain.com, trusted_other_domain.com
    trusted_authserv_ids:

    # Key Management
    #
    # In order for your server to be able to cryptographical sign its messages
    # a DKIM public/private key pair will need to be created.
    # See http://www.gettingemaildelivered.com/dkim-explained-how-to-set-up-and-use-domainkeys-identified-mail-effectively
    # for reference.  The following parameters let the software find your
    # private & public keys
    #
    # .. note::
    #
    #    Some versions of OpenSSL generate private keys which some versions of
    #    dkimpy (the library used by Mailman for handling ARC) cannot read.
    #    This manifests in "Unparsable private key" exceptions while processing
    #    email. If you encounter this, try to regenerate the RSA key with the
    #    -traditional flag.
    #
    # ::
    #     privkey: /some/location/yourprivatekey.pem
    #     selector: test
    #     domain: your_domain.com
    privkey:
    selector:
    domain:

    # This configures the headers that will be cryptographically signed
    # This list is what is recommended by the DKIM & ARC specifications.
    # Inclusion of the From header is mandatory.
    sig_headers: From, Sender, Reply-To, Subject, Date, Message-ID, To, Cc, MIME-Version, Content-Type, Content-Transfer-Encoding, Content-ID, Content-Description, Resent-Date, Resent-From, Resent-Sender, Resent-To, Resent-Cc, Resent-Message-ID, In-Reply-To, References, List-Id, List-Help, List-Unsubscribe, List-Subscribe, List-Post, List-Owner, List-Archive

    [antispam]
    # This section defines basic antispam detection settings.

    # This value contains lines which specify RFC 822 headers in the email to
    # check for spamminess.  Each line contains a `key: value` pair, where the key
    # is the header to check and the value is a Python regular expression to match
    # against the header's value.  Multiple checks should be entered as multiline
    # value with leading spaces:
    # ::
    #     header_checks:
    #       X-Spam: (yes|maybe)
    #       Authentication-Results: mail.example.com; dmarc=(fail|quarantine)
    #
    # The header value and regular expression are always matched
    # case-insensitively.
    header_checks:

    # The chain to jump to if any of the header patterns matches.  This must be
    # the name of an existing chain such as 'discard', 'reject', 'hold', or
    # 'accept', otherwise 'hold' will be used.
    jump_chain: hold

    [mta]
    # The class defining the interface to the incoming mail transport agent.
    incoming: mailman.mta.postfix.LMTP

    # The callable implementing delivery to the outgoing mail transport agent.
    # This must accept three arguments, the mailing list, the message, and the
    # message metadata dictionary.
    outgoing: mailman.mta.deliver.deliver

    # How to connect to the outgoing MTA.  If smtp_user and smtp_pass is given,
    # then Mailman will attempt to log into the MTA when making a new connection.
    smtp_host: localhost
    smtp_port: 25
    smtp_user:
    smtp_pass:

    # One of smtp/smtps/starttls, specifies the protocol Mailman will use when
    # connecting.  Typically will correspond to smtp_port: 25 -> smtp, 465 -> smtps,
    # 587 -> starttls.
    smtp_secure_mode: smtp

    # When smtp_secure_mode is smtps or starttls, whether to require a server cert
    # and verify it.
    smtp_verify_cert: yes

    # When smtp_secure_mode is smtps or starttls, whether to check that the
    # server certificate specifies the same hostname as smtp_host.
    smtp_verify_hostname: yes

    # Where the LMTP server listens for connections.  Use 127.0.0.1 instead of
    # localhost for Postfix integration, because Postfix only consults DNS
    # (e.g. not /etc/hosts).
    lmtp_host: 127.0.0.1
    lmtp_port: 8024

    # Ceiling on the number of recipients that can be specified in a single SMTP
    # transaction.  Set to 0 to submit the entire recipient list in one
    # transaction.
    max_recipients: 10

    # Ceiling on the number of SMTP sessions to perform on a single socket
    # connection.  Some MTAs have limits.  Set this to 0 to do as many as we like
    # (i.e. your MTA has no limits).  Set this to some number great than 0 and
    # Mailman will close the SMTP connection and re-open it after this number of
    # consecutive sessions.
    max_sessions_per_connection: 0

    # Maximum number of simultaneous subthreads that will be used for SMTP
    # delivery.  After the recipients list is chunked according to max_recipients,
    # each chunk is handed off to the SMTP server by a separate such thread.  If
    # your Python interpreter was not built for threads, this feature is disabled.
    # You can explicitly disable it in all cases by setting max_delivery_threads
    # to 0.
    max_delivery_threads: 0

    # How long should messages which have delivery failures continue to be
    # retried?  After this period of time, a message that has failed recipients
    # will be dequeued and those recipients will never receive the message.
    delivery_retry_period: 5d

    # These variables control the format and frequency of VERP-like delivery for
    # better bounce detection.  VERP is Variable Envelope Return Path, defined
    # here:
    #
    # http://cr.yp.to/proto/verp.txt
    #
    # This involves encoding the address of the recipient as Mailman knows it into
    # the envelope sender address (i.e. RFC 5321 MAIL FROM).  Thus, no matter what
    # kind of forwarding the recipient has in place, should it eventually bounce,
    # we will receive an unambiguous notice of the bouncing address.
    #
    # However, we're technically only "VERP-like" because we're doing the envelope
    # sender encoding in Mailman, not in the MTA.  We do require cooperation from
    # the MTA, so you must be sure your MTA can be configured for extended address
    # semantics.
    #
    # The first variable describes how to encode VERP envelopes.  It must contain
    # these three string interpolations, which get filled in by Mailman:
    #
    # $bounces -- the list's -bounces robot address will be set here
    # $local   -- the recipient address's local mailbox part will be set here
    # $domain  -- the recipient address's domain name will be set here
    #
    # This example uses the default below.
    #
    # FQDN list address is: mylist@dom.ain
    # Recipient is:         aperson@a.nother.dom
    #
    # The envelope sender will be mylist-bounces+aperson=a.nother.dom@dom.ain
    #
    # Note that your MTA /must/ be configured to deliver such an addressed message
    # to mylist-bounces!
    verp_delimiter: +
    verp_format: ${bounces}+${local}=${domain}

    # For nicer confirmation emails, use a VERP-like format which encodes the
    # confirmation cookie in the reply address.  This lets us put a more user
    # friendly Subject: on the message, but requires cooperation from the MTA.
    # Format is like verp_format, but with the following substitutions:
    #
    # $address  -- the list-confirm address
    # $cookie   -- the confirmation cookie
    verp_confirm_format: $address+$cookie

    # This regular expression unambiguously decodes VERP addresses, which will be
    # placed in the To: (or other, depending on the MTA) header of the bounce
    # message by the bouncing MTA.  Getting this right is critical -- and tricky.
    # Learn your Python regular expressions.  It must define exactly three named
    # groups, `bounces`, `local` and `domain`, with the same definition as above.
    # It will be compiled case-insensitively.
    verp_regexp: ^(?P<bounces>[^+]+?)\+(?P<local>[^=]+)=(?P<domain>[^@]+)@.*$

    # This is analogous to verp_regexp, but for splitting apart the
    # verp_confirm_format.  MUAs have been observed that mung
    #
    # From: local_part@host
    #
    # into
    #
    # To: "local_part" <local_part@host>
    #
    # when replying, so we skip everything up to '<' if any.
    verp_confirm_regexp: ^(.*<)?(?P<addr>[^+]+?)\+(?P<cookie>[^@]+)@.*$

    # Set this to 'no' to disable user friendly confirmations and avoid encoding
    # the confirmation cookie in the reply address.
    verp_confirmations: yes

    # Another good opportunity is when regular delivery is personalized.  Here
    # again, we're already incurring the performance hit for addressing each
    # individual recipient.  Set this to 'yes' to enable VERPs on all personalized
    # regular deliveries (personalized digests aren't supported yet).
    verp_personalized_deliveries: no

    # And finally, we can VERP normal, non-personalized deliveries.  However,
    # because it can be a significant performance hit, we allow you to decide how
    # often to VERP regular deliveries.  This is the interval, in number of
    # messages, to do a VERP recipient address.  The same variable controls both
    # regular and digest deliveries.  Set to 0 to disable occasional VERPs, set to
    # 1 to VERP every delivery, or to some number > 1 for only occasional VERPs.
    verp_delivery_interval: 0

    # VERP format and regexp for probe messages.
    verp_probe_format: $bounces+$token@$domain
    verp_probe_regexp: ^(?P<bounces>[^+]+?)\+(?P<token>[^@]+)@.*$
    # Set this 'yes' to activate VERP probe for disabling by bounce.
    verp_probes: no

    # This is the maximum number of automatic responses sent to an address because
    # of -request messages or posting hold messages.  This limit prevents response
    # loops between Mailman and misconfigured remote email robots.  Mailman
    # already inhibits automatic replies to any message labeled with a header
    # "Precendence: bulk|list|junk".  This is a fallback safety valve so it should
    # be set fairly high.  Set to 0 for no limit (probably useful only for
    # debugging).
    max_autoresponses_per_day: 10

    # Some list posts and mail to the -owner address may contain DomainKey or
    # DomainKeys Identified Mail (DKIM) signature headers <http://www.dkim.org/>.
    # Various list transformations to the message such as adding a list header or
    # footer or scrubbing attachments or even reply-to munging can break these
    # signatures.  It is generally felt that these signatures have value, even if
    # broken and even if the outgoing message is resigned.  However, some sites
    # may wish to remove these headers by setting this to 'yes'.
    remove_dkim_headers: no

    # Where can we find the mail server specific configuration file?  The path can
    # be either a file system path or a Python import path.  If the value starts
    # with python: then it is a Python import path, otherwise it is a file system
    # path.  File system paths must be absolute since no guarantees are made about
    # the current working directory.  Python paths should not include the trailing
    # .cfg, which the file must end with.
    configuration: python:mailman.config.postfix

    [bounces]
    # How often should the bounce runner process queued detected bounces?
    register_bounces_every: 15m

    [archiver.master]
    # To add new archivers, define a new section based on this one, overriding the
    # following values.

    # The class implementing the IArchiver interface.
    class:

    # Set this to 'yes' to enable the archiver.
    enable: no

    # Additional configuration for the archiver.  The path can be either a file
    # system path or a Python import path.  If the value starts with python: then
    # it is a Python import path, otherwise it is a file system path.  File system
    # paths must be absolute since no guarantees are made about the current
    # working directory.  Python paths should not include the trailing .cfg, which
    # the file must end with.
    configuration: changeme

    # When sending the message to the archiver, you have the option of
    # "clobbering" the Date: header, specifically to make it more sane.  Some
    # archivers can't handle dates that are wildly off from reality.  This does
    # not change the Date: header for any other delivery vector except this
    # specific archive.
    #
    # When the original Date header is clobbered, it will always be stored in
    # X-Original-Date.  The new Date header will always be set to the date at
    # which the messages was received by the Mailman server, in UTC.
    #
    # Your options here are:
    # * never  -- Leaves the original Date header alone.
    # * always -- Always override the Date header.
    # * maybe  -- Override the Date only if it is outside the clobber_skew period.
    clobber_date: maybe
    clobber_skew: 1d

    [archiver.mhonarc]
    # This is the stock MHonArc archiver.
    class: mailman.archiving.mhonarc.MHonArc
    configuration: python:mailman.config.mhonarc

    [archiver.mail_archive]
    # This is the stock mail-archive.com archiver.
    class: mailman.archiving.mailarchive.MailArchive
    configuration: python:mailman.config.mail_archive

    [archiver.prototype]
    # This is a prototypical sample archiver.
    class: mailman.archiving.prototype.Prototype

    [styles]
    # The default style to apply if nothing else was requested.  The value is the
    # name of an existing style.  If no such style exists, no style will be
    # applied.
    default: legacy-default

    [digests]
    # Headers which should be kept in both RFC 1153 (plain) and MIME digests.  RFC
    # 1153 also specifies these headers in this exact order, so order matters.
    # These are space separated and case insensitive.
    mime_digest_keep_headers:
        Date From To Cc Subject Message-ID Keywords
        In-Reply-To References Content-Type MIME-Version
        Content-Transfer-Encoding Precedence Reply-To
        Message List-Post

    plain_digest_keep_headers:
        Message Date From
        Subject To Cc
        Message-ID Keywords
        Content-Type

    [nntp]
    # The nntp runner is no longer started by default. If you are actually gating
    # to/from usenet, you need to add
    # [runner.nntp]
    # start: yes
    # to your mailman.cfg

    # Set these variables if you need to authenticate to your NNTP server for
    # Usenet posting or reading.  Leave these blank if no authentication is
    # necessary.
    user:
    password:

    # Host and port of the NNTP server to connect to.  Leave these blank to use
    # the default localhost:119.
    host:
    port:

    # This controls how headers must be cleansed in order to be accepted by your
    # NNTP server.  Some servers like INN reject messages containing prohibited
    # headers, or duplicate headers.  The NNTP server may reject the message for
    # other reasons, but there's little that can be programmatically done about
    # that.
    #
    # These headers (case ignored) are removed from the original message.  This is
    # a whitespace separate list of headers.
    remove_headers:
        nntp-posting-host nntp-posting-date x-trace
        x-complaints-to xref date-received posted
        posting-version relay-version received

    # These headers are left alone, unless there are duplicates in the original
    # message.  Any second and subsequent headers are rewritten to the second
    # named header (case preserved).  This is a list of header pairs, one pair per
    # line.
    rewrite_duplicate_headers:
        To X-Original-To
        CC X-Original-CC
        Content-Transfer-Encoding X-Original-Content-Transfer-Encoding
        MIME-Version X-MIME-Version

    # The NNTP runner periodically runs the gatenews command to gate news from
    # usenet for lists that do that.  This controls how often gatenews is run.
    gatenews_every: 5m

    [dmarc]
    # RFC 7489 - Domain-based Message Authentication, Reporting, and Conformance.
    # https://en.wikipedia.org/wiki/DMARC

    # Parameters for DMARC DNS lookups.  If you are seeing 'DNSException: Unable
    # to query DMARC policy ...' entries in your error log, you may need to adjust
    # these.
    #
    # The time to wait for a response from a name server before timeout.
    resolver_timeout: 3s

    # The total time to spend trying to get an answer to the DNS question.
    resolver_lifetime: 5s

    # A URL from which to retrieve the data for the algorithm that computes
    # Organizational Domains for DMARC policy lookup purposes.  This can be
    # anything handled by the Python urllib.request.urlopen function.  See
    # https://publicsuffix.org/list/ for info.
    org_domain_data_url: https://publicsuffix.org/list/public_suffix_list.dat

    # How long should the local suffix list be used before it's considered out of
    # date.  After this amount of time a new list will be downloaded, but if it
    # can't be accessed, old data will still be used.
    cache_lifetime: 7d

    # urlpatterns typically represent the urls that are used in email templates
    # generated by Mailman Core. They key represents the `$key` that can be
    # used in the templates.

    # These are the url patterns for Postorius.
    [urlpatterns]
    mailinglist: $base_url/lists/$list_id
    held_message: $base_url/lists/$list_id/held_messages
    pending_subscriptions: $base_url/lists/$list_id/subscription_requests
    pending_unsubscriptions: $base_url/lists/$list_id/unsubscription_requests
    domain: $base_url/domains/$domain

## mailman.cfg

Configuration settings provided in the built-in base `mailman.cfg` file overrides those provided in `schema.cfg`.

    # Copyright (C) 2008-2023 by the Free Software Foundation, Inc.
    #
    # This file is part of GNU Mailman.
    #
    # GNU Mailman 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 3 of the License, or (at your option)
    # any later version.
    #
    # GNU Mailman 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
    # GNU Mailman.  If not, see <https://www.gnu.org/licenses/>.

    # This is the absolute bare minimum base configuration file.  User supplied
    # configurations are pushed onto this.

    [paths.local]
    # Directories as specified in schema.cfg, putting most stuff in
    # /var/tmp/mailman

    [paths.dev]
    # Convenient development layout where everything is put in a directory above
    # where the mailman.cfg file lives.
    var_dir: $cfg_file/../..

    [paths.here]
    # Layout where the var directory is put in the current working directory.
    var_dir: $cwd/var

    [paths.fhs]
    # Filesystem Hiearchy Standard 2.3
    # http://www.pathname.com/fhs/pub/fhs-2.3.html
    bin_dir: /sbin
    var_dir: /var/lib/mailman
    queue_dir: /var/spool/mailman
    log_dir: /var/log/mailman
    lock_dir: /var/lock/mailman
    etc_dir: /etc
    ext_dir: /etc/mailman.d
    pid_file: /var/run/mailman/master.pid

    [language.en]

    [runner.archive]
    class: mailman.runners.archive.ArchiveRunner

    [runner.bad]
    class: mailman.runners.fake.BadRunner
    # The bad runner is just a placeholder for its switchboard.
    start: no

    [runner.bounces]
    class: mailman.runners.bounce.BounceRunner
    sleep_time: 2m

    [runner.command]
    class: mailman.runners.command.CommandRunner

    [runner.in]
    class: mailman.runners.incoming.IncomingRunner

    [runner.lmtp]
    class: mailman.runners.lmtp.LMTPRunner
    path:

    [runner.nntp]
    class: mailman.runners.nntp.NNTPRunner
    # Most sites don't need this
    start: no

    [runner.out]
    class: mailman.runners.outgoing.OutgoingRunner

    [runner.pipeline]
    class: mailman.runners.pipeline.PipelineRunner

    [runner.rest]
    class: mailman.runners.rest.RESTRunner
    path:

    [runner.retry]
    class: mailman.runners.retry.RetryRunner
    sleep_time: 15m

    [runner.shunt]
    class: mailman.runners.fake.ShuntRunner
    # The shunt runner is just a placeholder for its switchboard.
    start: no

    [runner.task]
    class: mailman.runners.task.TaskRunner
    sleep_time: 1m
    path:

    [runner.virgin]
    class: mailman.runners.virgin.VirginRunner

    [runner.digest]
    class: mailman.runners.digest.DigestRunner

[1]

The technical differences are described in the lazr.config package, upon which Mailman’s configuration system is based.