Migrating to Mailman 3
Mailman 2.1 has served its purpose at work for several years. Python 2 is at its end of life in FreeBSD. It’s time to move on to Mailman 3 and Python 3, or to Sympa if I’m unsuccessful in getting Mailman 3 up & running. I’ll try and document each step along the way.
Note, this is a long and dull blog entry. I’ll summarize this gig in another blog post when everything works as planned.
Parallel to my own efforts, Dan Langille (dvl@) is attempting to get Mailman 3 working for the FreeBSD project. I’ll be leaning on most of his work, e.g. r556421, r556422, and this.
I started by creating a new, dedicated VM almost 7 weeks ago. It has been given 4 vCPUs and 8 GiB of memory. It uses a 17 GiB virtual disk for boot and swap partitions; 512K legacy boot partition, 128M UEFI system partition, and 16G swap partition. The root pool is configured as raidz1 stretching over 3 virtual disks, each of 12 GiB, yielding roughly 35G. A dedicated data pool is configured as raidz1 stretching over 3 drives, each of 2 GiB, yielding roughly 5G. All disks are GPT partitioned and uses GPT labels for every partition.
xbd0
aka ada0
:
GPT 128 1 freebsd-boot 40 1024 gptboot0 2 efi 1064 262144 esp0 3 freebsd-swap 263208 33554432 swap0
xbd1
aka ada1
:
GPT 128 1 freebsd-zfs 40 25165744 lists_zroot0
xbd2
aka ada2
:
GPT 128 1 freebsd-zfs 40 25165744 lists_zroot1
xbd4
:
GPT 128 1 freebsd-zfs 40 25165744 lists_zroot2
xbd5
:
GPT 128 1 freebsd-zfs 40 4194224 lists_zdata0
xbd6
:
GPT 128 1 freebsd-zfs 40 4194224 lists_zdata1
xbd7
:
GPT 128 1 freebsd-zfs 40 4194224 lists_zdata2
(The virtual DVD drive is mapped to xbd3
in case you were wondering.)
I might redo the root pool as it has been given way too much storage.
To keep the user data separated from the system, the dedicated zpool named lists_zdata
will store these filesystems (and possibly more):
/home
/usr/local/mailman
/usr/local/www
/var/db/postfix
/var/db/postgres/data11
/var/db/postgres/data11/base
/var/db/postgres/data11/pg_wal
/var/spool/clientmqueue
/var/spool/mqueue
/var/spool/postfix
/var/spool/sympa
The VM has these ports installed:
Webserver and certificate management:
www/apache24
security/py-certbot@py37
Postfix as the MTA instead of sendmail from base:
mail/postfix
Mailman 3 & friends:
mail/mailman3@py37
www/py-postorius@py37
www/py-gunicorn@py37
devel/py-importlib-resources@py37
mail/py-authres@py37
mail/py-authheaders@py37
Sympa & friends:
mail/sympa
databases/postgresql11-client
databases/postgresql11-contrib
databases/postgresql11-server
(I’ll take the leap to PostgreSQL 13 in early spring 2021.)
For sysadmin tasks:
misc/amanda-client
shells/bash
devel/cvs+ipv6
editors/emacs@nox
devel/gdb
sysutils/htop
net-mgmt/iftop
sysutils/lsof
sysutils/lsop
misc/mc-nox11
sysutils/ncdu
net-mgmt/net-snmp
security/rkhunter
sysutils/parallel
sysutils/psmisc
sysutils/screen
For communicating back to the mothership^Whypervisor:
sysutils/xe-guest-utilities
sysutils/xen-guest-tools
All packages are built from the ports tree by our resident builder.
The Mailman 3 Pre-Installation Guide and subsequent chapters will undoubtly be handy along the way.
2020-12-01
I got sidetracked too many times today to do anything useful beyond writing the initial part of these notes. Maybe I’ll fare better tomorrow.
2020-12-02
I ran these two commands and got myself a surprise:
# cd /usr/local/mailman # mailman info Traceback (most recent call last): File "/usr/local/lib/python3.7/site-packages/pkg_resources/__init__.py", line 583, in _build_master ws.require(__requires__) File "/usr/local/lib/python3.7/site-packages/pkg_resources/__init__.py", line 900, in require needed = self.resolve(parse_requirements(requirements)) File "/usr/local/lib/python3.7/site-packages/pkg_resources/__init__.py", line 791, in resolve raise VersionConflict(dist, req).with_context(dependent_req) pkg_resources.ContextualVersionConflict: (zope.interface 4.6.0 (/usr/local/lib/python3.7/site-packages), Requirement.parse('zope.interface>=5.0'), {'mailman'}) During handling of the above exception, another exception occurred: Traceback (most recent call last): File "/usr/local/bin/mailman", line 6, infrom pkg_resources import load_entry_point File "/usr/local/lib/python3.7/site-packages/pkg_resources/__init__.py", line 3251, in @_call_aside File "/usr/local/lib/python3.7/site-packages/pkg_resources/__init__.py", line 3235, in _call_aside f(*args, **kwargs) File "/usr/local/lib/python3.7/site-packages/pkg_resources/__init__.py", line 3264, in _initialize_master_working_set working_set = WorkingSet._build_master() File "/usr/local/lib/python3.7/site-packages/pkg_resources/__init__.py", line 585, in _build_master return cls._build_from_requirements(__requires__) File "/usr/local/lib/python3.7/site-packages/pkg_resources/__init__.py", line 598, in _build_from_requirements dists = ws.resolve(reqs, Environment()) File "/usr/local/lib/python3.7/site-packages/pkg_resources/__init__.py", line 786, in resolve raise DistributionNotFound(req, requirers) pkg_resources.DistributionNotFound: The 'zope.interface>=5.0' distribution was not found and is required by mailman
I have an old version of zope which is strange since the installed zope packages got pulled in by mail/mailman3@py37
and security/py-certbot@py37
:
# pkg info -r py37-zope\* py37-zope.component-4.2.2: py37-mailman-3.3.1 py37-certbot-1.9.0,1 py37-zope.configuration-4.1.0: py37-mailman-3.3.1 py37-zope.event-4.1.0: py37-mailman-3.3.1 py37-zope.component-4.2.2 py37-zope.schema-4.2.2_1 py37-zope.i18nmessageid-3.6.1_1: py37-zope.configuration-4.1.0 py37-zope.interface-4.6.0: py37-mailman-3.3.1 py37-certbot-1.9.0,1 py37-lazr.config-2.2.2 py37-zope.configuration-4.1.0 py37-flufl.bounce-3.0_1 py37-zope.component-4.2.2 py37-lazr.delegates-2.0.4 py37-zope.schema-4.2.2_1 py37-zope.schema-4.2.2_1: py37-zope.configuration-4.1.0
This doesn’t look too well until the ports tree is updated to support zope>=5.0.
As suggested by Dan Langille, I changed /usr/local/lib/python3.7/site-packages/mailman-3.3.1-py3.7.egg-info/requires.txt
to accept zope.interface>=4.0
:
--- lib/python3.7/site-packages/mailman-3.3.1-py3.7.egg-info/requires.txt.orig 2020-10-15 16:40:14.000000000 +0200 +++ lib/python3.7/site-packages/mailman-3.3.1-py3.7.egg-info/requires.txt 2020-12-02 20:58:48.791696000 +0100 @@ -19,4 +19,4 @@ zope.component zope.configuration zope.event -zope.interface>=5.0 +zope.interface>=4.0
Well, I got a bit further:
# cd /usr/local/mailman # mailman info Traceback (most recent call last): File "/usr/local/bin/mailman", line 6, infrom pkg_resources import load_entry_point File "/usr/local/lib/python3.7/site-packages/pkg_resources/__init__.py", line 3251, in @_call_aside File "/usr/local/lib/python3.7/site-packages/pkg_resources/__init__.py", line 3235, in _call_aside f(*args, **kwargs) File "/usr/local/lib/python3.7/site-packages/pkg_resources/__init__.py", line 3264, in _initialize_master_working_set working_set = WorkingSet._build_master() File "/usr/local/lib/python3.7/site-packages/pkg_resources/__init__.py", line 583, in _build_master ws.require(__requires__) File "/usr/local/lib/python3.7/site-packages/pkg_resources/__init__.py", line 900, in require needed = self.resolve(parse_requirements(requirements)) File "/usr/local/lib/python3.7/site-packages/pkg_resources/__init__.py", line 786, in resolve raise DistributionNotFound(req, requirers) pkg_resources.DistributionNotFound: The 'gunicorn' distribution was not found and is required by mailman
It looks like I need to add www/py-gunicorn@py37
to the local metaport.
# pkg update -f && pkg upgrade Updating builder01 repository catalogue... Fetching meta.conf: 100% 163 B 0.2kB/s 00:01 Fetching packagesite.txz: 100% 228 KiB 233.2kB/s 00:01 Processing entries: 100% builder01 repository update completed. 845 packages processed. All repositories are up to date. Updating builder01 repository catalogue... builder01 repository is up to date. All repositories are up to date. Checking for upgrades (3 candidates): 100% Processing candidates (3 candidates): 100% The following 4 package(s) will be affected (of 0 checked): New packages to be INSTALLED: py37-gunicorn: 19.9.0_1 py37-setproctitle: 1.1.10_1 Installed packages to be UPGRADED: libxml2: 2.9.10_1 -> 2.9.10_2 lists-localbase: 2020113000 -> 2020120200 Number of packages to be installed: 2 Number of packages to be upgraded: 2 The process will require 1 MiB more space. 1 MiB to be downloaded. Proceed with this action? [y/N]: y [1/4] Fetching lists-localbase-2020120200.txz: 100% 928 B 0.9kB/s 00:01 [2/4] Fetching libxml2-2.9.10_2.txz: 100% 825 KiB 845.2kB/s 00:01 [3/4] Fetching py37-gunicorn-19.9.0_1.txz: 100% 180 KiB 184.5kB/s 00:01 [4/4] Fetching py37-setproctitle-1.1.10_1.txz: 100% 10 KiB 10.4kB/s 00:01 Checking integrity... done (0 conflicting) [1/4] Upgrading libxml2 from 2.9.10_1 to 2.9.10_2... [1/4] Extracting libxml2-2.9.10_2: 100% [2/4] Installing py37-setproctitle-1.1.10_1... [2/4] Extracting py37-setproctitle-1.1.10_1: 100% [3/4] Installing py37-gunicorn-19.9.0_1... [3/4] Extracting py37-gunicorn-19.9.0_1: 100% [4/4] Upgrading lists-localbase from 2020113000 to 2020120200...
Let’s try again:
# cd /usr/local/mailman # mailman info Traceback (most recent call last): File "/usr/local/bin/mailman", line 6, infrom pkg_resources import load_entry_point File "/usr/local/lib/python3.7/site-packages/pkg_resources/__init__.py", line 3251, in @_call_aside File "/usr/local/lib/python3.7/site-packages/pkg_resources/__init__.py", line 3235, in _call_aside f(*args, **kwargs) File "/usr/local/lib/python3.7/site-packages/pkg_resources/__init__.py", line 3264, in _initialize_master_working_set working_set = WorkingSet._build_master() File "/usr/local/lib/python3.7/site-packages/pkg_resources/__init__.py", line 583, in _build_master ws.require(__requires__) File "/usr/local/lib/python3.7/site-packages/pkg_resources/__init__.py", line 900, in require needed = self.resolve(parse_requirements(requirements)) File "/usr/local/lib/python3.7/site-packages/pkg_resources/__init__.py", line 786, in resolve raise DistributionNotFound(req, requirers) pkg_resources.DistributionNotFound: The 'importlib_resources>=1.1.0' distribution was not found and is required by mailman
Righto, more ports to add to the local metaport. This time it’s devel/py-importlib-resources@py37
.
# pkg update -f && pkg upgrade Updating builder01 repository catalogue... Fetching meta.conf: 100% 163 B 0.2kB/s 00:01 Fetching packagesite.txz: 100% 228 KiB 233.6kB/s 00:01 Processing entries: 100% builder01 repository update completed. 847 packages processed. All repositories are up to date. Updating builder01 repository catalogue... builder01 repository is up to date. All repositories are up to date. Checking for upgrades (2 candidates): 100% Processing candidates (2 candidates): 100% The following 2 package(s) will be affected (of 0 checked): New packages to be INSTALLED: py37-importlib-resources: 3.3.0 Installed packages to be UPGRADED: lists-localbase: 2020120200 -> 2020120201 Number of packages to be installed: 1 Number of packages to be upgraded: 1 34 KiB to be downloaded. Proceed with this action? [y/N]: y [1/2] Fetching lists-localbase-2020120201.txz: 100% 952 B 1.0kB/s 00:01 [2/2] Fetching py37-importlib-resources-3.3.0.txz: 100% 33 KiB 33.6kB/s 00:01 Checking integrity... done (0 conflicting) [1/2] Installing py37-importlib-resources-3.3.0... [1/2] Extracting py37-importlib-resources-3.3.0: 100% [2/2] Upgrading lists-localbase from 2020120200 to 2020120201...
Will it work this time?
# cd /usr/local/mailman # mailman info Traceback (most recent call last): File "/usr/local/bin/mailman", line 6, infrom pkg_resources import load_entry_point File "/usr/local/lib/python3.7/site-packages/pkg_resources/__init__.py", line 3251, in @_call_aside File "/usr/local/lib/python3.7/site-packages/pkg_resources/__init__.py", line 3235, in _call_aside f(*args, **kwargs) File "/usr/local/lib/python3.7/site-packages/pkg_resources/__init__.py", line 3264, in _initialize_master_working_set working_set = WorkingSet._build_master() File "/usr/local/lib/python3.7/site-packages/pkg_resources/__init__.py", line 583, in _build_master ws.require(__requires__) File "/usr/local/lib/python3.7/site-packages/pkg_resources/__init__.py", line 900, in require needed = self.resolve(parse_requirements(requirements)) File "/usr/local/lib/python3.7/site-packages/pkg_resources/__init__.py", line 786, in resolve raise DistributionNotFound(req, requirers) pkg_resources.DistributionNotFound: The 'authres>=1.0.1' distribution was not found and is required by mailman
More ports to add. mail/py-authres@py37
it is.
# pkg update -f && pkg upgrade Updating builder01 repository catalogue... Fetching meta.conf: 100% 163 B 0.2kB/s 00:01 Fetching packagesite.txz: 100% 228 KiB 233.9kB/s 00:01 Processing entries: 100% builder01 repository update completed. 848 packages processed. All repositories are up to date. Updating builder01 repository catalogue... builder01 repository is up to date. All repositories are up to date. Checking for upgrades (2 candidates): 100% Processing candidates (2 candidates): 100% The following 2 package(s) will be affected (of 0 checked): New packages to be INSTALLED: py37-authres: 1.2.0 Installed packages to be UPGRADED: lists-localbase: 2020120201 -> 2020120202 Number of packages to be installed: 1 Number of packages to be upgraded: 1 31 KiB to be downloaded. Proceed with this action? [y/N]: y [1/2] Fetching lists-localbase-2020120202.txz: 100% 968 B 1.0kB/s 00:01 [2/2] Fetching py37-authres-1.2.0.txz: 100% 30 KiB 30.7kB/s 00:01 Checking integrity... done (0 conflicting) [1/2] Installing py37-authres-1.2.0... [1/2] Extracting py37-authres-1.2.0: 100% [2/2] Upgrading lists-localbase from 2020120201 to 2020120202...
Do I dare try again?
# cd /usr/local/mailman # mailman info Traceback (most recent call last): File "/usr/local/bin/mailman", line 6, infrom pkg_resources import load_entry_point File "/usr/local/lib/python3.7/site-packages/pkg_resources/__init__.py", line 3251, in @_call_aside File "/usr/local/lib/python3.7/site-packages/pkg_resources/__init__.py", line 3235, in _call_aside f(*args, **kwargs) File "/usr/local/lib/python3.7/site-packages/pkg_resources/__init__.py", line 3264, in _initialize_master_working_set working_set = WorkingSet._build_master() File "/usr/local/lib/python3.7/site-packages/pkg_resources/__init__.py", line 583, in _build_master ws.require(__requires__) File "/usr/local/lib/python3.7/site-packages/pkg_resources/__init__.py", line 900, in require needed = self.resolve(parse_requirements(requirements)) File "/usr/local/lib/python3.7/site-packages/pkg_resources/__init__.py", line 786, in resolve raise DistributionNotFound(req, requirers) pkg_resources.DistributionNotFound: The 'authheaders>=0.9.2' distribution was not found and is required by mailman
Will this ever succeed? Oh well, let’s add mail/py-authheaders@py37
.
# pkg update -f && pkg upgrade Updating builder01 repository catalogue... Fetching meta.conf: 100% 163 B 0.2kB/s 00:01 Fetching packagesite.txz: 100% 229 KiB 234.7kB/s 00:01 Processing entries: 100% builder01 repository update completed. 852 packages processed. All repositories are up to date. Updating builder01 repository catalogue... builder01 repository is up to date. All repositories are up to date. Checking for upgrades (2 candidates): 100% Processing candidates (2 candidates): 100% The following 6 package(s) will be affected (of 0 checked): New packages to be INSTALLED: libsodium: 1.0.18 py37-authheaders: 0.13.0 py37-dkimpy: 1.0.5 py37-publicsuffix2: 2.20191221_8 py37-pynacl: 1.4.0 Installed packages to be UPGRADED: lists-localbase: 2020120202 -> 2020120203 Number of packages to be installed: 5 Number of packages to be upgraded: 1 The process will require 3 MiB more space. 563 KiB to be downloaded. Proceed with this action? [y/N]: y [1/6] Fetching lists-localbase-2020120203.txz: 100% 984 B 1.0kB/s 00:01 [2/6] Fetching py37-authheaders-0.13.0.txz: 100% 75 KiB 77.1kB/s 00:01 [3/6] Fetching py37-dkimpy-1.0.5.txz: 100% 57 KiB 58.8kB/s 00:01 [4/6] Fetching py37-pynacl-1.4.0.txz: 100% 86 KiB 87.6kB/s 00:01 [5/6] Fetching libsodium-1.0.18.txz: 100% 264 KiB 270.6kB/s 00:01 [6/6] Fetching py37-publicsuffix2-2.20191221_8.txz: 100% 79 KiB 80.9kB/s 00:01 Checking integrity... done (0 conflicting) [1/6] Installing libsodium-1.0.18... [1/6] Extracting libsodium-1.0.18: 100% [2/6] Installing py37-pynacl-1.4.0... [2/6] Extracting py37-pynacl-1.4.0: 100% [3/6] Installing py37-dkimpy-1.0.5... [3/6] Extracting py37-dkimpy-1.0.5: 100% [4/6] Installing py37-publicsuffix2-2.20191221_8... [4/6] Extracting py37-publicsuffix2-2.20191221_8: 100% [5/6] Installing py37-authheaders-0.13.0... [5/6] Extracting py37-authheaders-0.13.0: 100% [6/6] Upgrading lists-localbase from 2020120202 to 2020120203...
How about now?
# cd /usr/local/mailman # mailman info GNU Mailman 3.3.1 (Tom Sawyer) Python 3.7.9 (default, Oct 15 2020, 08:08:23) [Clang 10.0.1 (git@github.com:llvm/llvm-project.git llvmorg-10.0.1-0-gef32c611a config file: None db url: sqlite:////usr/local/mailman/data/mailman.db devmode: DISABLED REST root url: http://localhost:8001/3.1/ REST credentials: restadmin:restpass
Finally, we are getting somewhere.
I’m beginning to feel that www/py-gunicorn@py37
, devel/py-importlib-resources@py37
, mail/py-authres@py37
, and mail/py-authheaders@py37
should really have been pulled in by mail/mailman3@py37
.
It’s getting late, so I’ll continue tomorrow.
2020-12-03
Running mailman info
last night populated /usr/local/mailman
with directories and files, including /usr/local/mailman/etc/mailman.cfg
. The latter has only a few comments:
# AUTOMATICALLY GENERATED BY MAILMAN ON 2020-12-02 22:02:09 UTC # # This is your GNU Mailman 3 configuration file. You can edit this file to # configure Mailman to your needs, and Mailman will never overwrite it. # Additional configuration information is available here: # # https://mailman.readthedocs.io/en/latest/src/mailman/config/docs/config.html # # For example, uncomment the following lines to run Mailman in developer mode. # # [devmode] # enabled: yes # recipient: your.address@your.domain
Poking around led me to the MAILMAN_CONFIG_FILE
environment variable.
# cd /usr/local/mailman # setenv MAILMAN_CONFIG_FILE /usr/local/mailman/etc/mailman.cfg # mailman info GNU Mailman 3.3.1 (Tom Sawyer) Python 3.7.9 (default, Oct 15 2020, 08:08:23) [Clang 10.0.1 (git@github.com:llvm/llvm-project.git llvmorg-10.0.1-0-gef32c611a config file: /usr/local/mailman/etc/mailman.cfg db url: sqlite:////usr/local/mailman/data/mailman.db devmode: DISABLED REST root url: http://localhost:8001/3.1/ REST credentials: restadmin:restpass
Now there’s a slight improvement. Maybe we can now try to start the Mailman service.
# service mailman onestart Traceback (most recent call last): File "/usr/local/bin/mailman", line 11, inload_entry_point('mailman==3.3.1', 'console_scripts', 'mailman')() File "/usr/local/lib/python3.7/site-packages/click/core.py", line 829, in __call__ return self.main(*args, **kwargs) File "/usr/local/lib/python3.7/site-packages/click/core.py", line 781, in main with self.make_context(prog_name, args, **extra) as ctx: File "/usr/local/lib/python3.7/site-packages/click/core.py", line 700, in make_context self.parse_args(ctx, args) File "/usr/local/lib/python3.7/site-packages/click/core.py", line 1212, in parse_args rest = Command.parse_args(self, ctx, args) File "/usr/local/lib/python3.7/site-packages/click/core.py", line 1048, in parse_args value, args = param.handle_parse_result(ctx, opts, args) File "/usr/local/lib/python3.7/site-packages/click/core.py", line 1630, in handle_parse_result value = invoke_param_callback(self.callback, ctx, self, value) File "/usr/local/lib/python3.7/site-packages/click/core.py", line 123, in invoke_param_callback return callback(ctx, param, value) File "/usr/local/lib/python3.7/site-packages/mailman/bin/mailman.py", line 94, in initialize_config initialize(value) File "/usr/local/lib/python3.7/site-packages/mailman/core/initialize.py", line 217, in initialize initialize_1(config_path) File "/usr/local/lib/python3.7/site-packages/mailman/core/initialize.py", line 122, in initialize_1 mailman.config.config.load(config_path) File "/usr/local/lib/python3.7/site-packages/mailman/config/config.py", line 142, in load self.push(filename, user_config.read()) File "/usr/local/lib/python3.7/site-packages/mailman/config/config.py", line 148, in push self._post_process() File "/usr/local/lib/python3.7/site-packages/mailman/config/config.py", line 160, in _post_process self.ensure_directories_exist() File "/usr/local/lib/python3.7/site-packages/mailman/config/config.py", line 262, in ensure_directories_exist with Lock(lock_file): File "/usr/local/lib/python3.7/site-packages/flufl/lock/_lockfile.py", line 334, in __enter__ self.lock() File "/usr/local/lib/python3.7/site-packages/flufl/lock/_lockfile.py", line 203, in lock self._write() File "/usr/local/lib/python3.7/site-packages/flufl/lock/_lockfile.py", line 417, in _write with open(self._claimfile, 'w') as fp: PermissionError: [Errno 13] Permission denied: '/usr/local/mailman/locks/mailman-cfg.lck|[REDACTED]|1810|4264959031836525201'
Hum. It looks like ownership of files and directories is an issue.
# cd /usr/local/mailman # ls -Rl total 58 drwxr-xr-x 2 root mailman 2 Dec 2 23:02 archives drwxr-xr-x 2 root mailman 2 Dec 2 23:02 cache drwxr-xr-x 2 root mailman 3 Dec 2 23:02 data drwxr-xr-x 2 root mailman 3 Dec 2 23:02 etc drwxr-xr-x 2 root mailman 2 Dec 2 23:02 lists drwxr-xr-x 2 root mailman 2 Dec 3 09:22 locks drwxr-xr-x 2 root mailman 7 Dec 2 23:02 logs drwxr-xr-x 2 root mailman 2 Dec 2 23:02 messages drwxr-xr-x 14 root mailman 14 Dec 2 23:02 queue drwxr-xr-x 2 root mailman 2 Dec 2 23:02 templates ./archives: total 0 ./cache: total 0 ./data: total 395 -rw-rw---- 1 root mailman 270336 Dec 2 23:02 mailman.db ./etc: total 6 -rw-rw---- 1 root mailman 501 Dec 3 09:13 mailman.cfg ./lists: total 0 ./locks: total 0 ./logs: total 8 -rw-rw---- 1 root mailman 0 Dec 2 23:02 bounce.log -rw-rw---- 1 root mailman 0 Dec 2 23:02 debug.log -rw-rw---- 1 root mailman 2738 Dec 3 09:24 mailman.log -rw-rw---- 1 root mailman 0 Dec 2 23:02 plugins.log -rw-rw---- 1 root mailman 0 Dec 2 23:02 smtp.log ./messages: total 0 ./queue: total 6 drwxrwx--- 2 root mailman 2 Dec 2 23:02 archive drwxrwx--- 2 root mailman 2 Dec 2 23:02 bad drwxrwx--- 2 root mailman 2 Dec 2 23:02 bounces drwxrwx--- 2 root mailman 2 Dec 2 23:02 command drwxrwx--- 2 root mailman 2 Dec 2 23:02 digest drwxrwx--- 2 root mailman 2 Dec 2 23:02 in drwxrwx--- 2 root mailman 2 Dec 2 23:02 nntp drwxrwx--- 2 root mailman 2 Dec 2 23:02 out drwxrwx--- 2 root mailman 2 Dec 2 23:02 pipeline drwxrwx--- 2 root mailman 2 Dec 2 23:02 retry drwxrwx--- 2 root mailman 2 Dec 2 23:02 shunt drwxrwx--- 2 root mailman 2 Dec 2 23:02 virgin ./queue/archive: total 0 ./queue/bad: total 0 ./queue/bounces: total 0 ./queue/command: total 0 ./queue/digest: total 0 ./queue/in: total 0 ./queue/nntp: total 0 ./queue/out: total 0 ./queue/pipeline: total 0 ./queue/retry: total 0 ./queue/shunt: total 0 ./queue/virgin: total 0 ./templates: total 0
Only /usr/local/mailman
is truly owned by mailman:mailman
due to the scripts I use when creating my ZFS pools.
# chown -R mailman:mailman /usr/local/mailman # cd /usr/local/mailman # ls -Rl total 58 drwxr-xr-x 2 mailman mailman 2 Dec 2 23:02 archives drwxr-xr-x 2 mailman mailman 2 Dec 2 23:02 cache drwxr-xr-x 2 mailman mailman 3 Dec 2 23:02 data drwxr-xr-x 2 mailman mailman 3 Dec 2 23:02 etc drwxr-xr-x 2 mailman mailman 2 Dec 2 23:02 lists drwxr-xr-x 2 mailman mailman 2 Dec 3 09:22 locks drwxr-xr-x 2 mailman mailman 7 Dec 2 23:02 logs drwxr-xr-x 2 mailman mailman 2 Dec 2 23:02 messages drwxr-xr-x 14 mailman mailman 14 Dec 2 23:02 queue drwxr-xr-x 2 mailman mailman 2 Dec 2 23:02 templates ./archives: total 0 ./cache: total 0 ./data: total 395 -rw-rw---- 1 mailman mailman 270336 Dec 2 23:02 mailman.db ./etc: total 6 -rw-rw---- 1 mailman mailman 501 Dec 3 09:13 mailman.cfg ./lists: total 0 ./locks: total 0 ./logs: total 8 -rw-rw---- 1 mailman mailman 0 Dec 2 23:02 bounce.log -rw-rw---- 1 mailman mailman 0 Dec 2 23:02 debug.log -rw-rw---- 1 mailman mailman 2738 Dec 3 09:24 mailman.log -rw-rw---- 1 mailman mailman 0 Dec 2 23:02 plugins.log -rw-rw---- 1 mailman mailman 0 Dec 2 23:02 smtp.log ./messages: total 0 ./queue: total 6 drwxrwx--- 2 mailman mailman 2 Dec 2 23:02 archive drwxrwx--- 2 mailman mailman 2 Dec 2 23:02 bad drwxrwx--- 2 mailman mailman 2 Dec 2 23:02 bounces drwxrwx--- 2 mailman mailman 2 Dec 2 23:02 command drwxrwx--- 2 mailman mailman 2 Dec 2 23:02 digest drwxrwx--- 2 mailman mailman 2 Dec 2 23:02 in drwxrwx--- 2 mailman mailman 2 Dec 2 23:02 nntp drwxrwx--- 2 mailman mailman 2 Dec 2 23:02 out drwxrwx--- 2 mailman mailman 2 Dec 2 23:02 pipeline drwxrwx--- 2 mailman mailman 2 Dec 2 23:02 retry drwxrwx--- 2 mailman mailman 2 Dec 2 23:02 shunt drwxrwx--- 2 mailman mailman 2 Dec 2 23:02 virgin ./queue/archive: total 0 ./queue/bad: total 0 ./queue/bounces: total 0 ./queue/command: total 0 ./queue/digest: total 0 ./queue/in: total 0 ./queue/nntp: total 0 ./queue/out: total 0 ./queue/pipeline: total 0 ./queue/retry: total 0 ./queue/shunt: total 0 ./queue/virgin: total 0 ./templates: total 0
One more try.
# service mailman onestart Starting Mailman's master runner Generating MTA alias maps sh: /usr/local/sbin/postmap: not found sh: /usr/local/sbin/postmap: not found Traceback (most recent call last): File "/usr/local/bin/mailman", line 11, inload_entry_point('mailman==3.3.1', 'console_scripts', 'mailman')() File "/usr/local/lib/python3.7/site-packages/click/core.py", line 829, in __call__ return self.main(*args, **kwargs) File "/usr/local/lib/python3.7/site-packages/click/core.py", line 782, in main rv = self.invoke(ctx) File "/usr/local/lib/python3.7/site-packages/mailman/bin/mailman.py", line 68, in invoke return super().invoke(ctx) File "/usr/local/lib/python3.7/site-packages/click/core.py", line 1259, in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) File "/usr/local/lib/python3.7/site-packages/click/core.py", line 1066, in invoke return ctx.invoke(self.callback, **ctx.params) File "/usr/local/lib/python3.7/site-packages/click/core.py", line 610, in invoke return callback(*args, **kwargs) File "/usr/local/lib/python3.7/site-packages/click/decorators.py", line 21, in new_func return f(get_current_context(), *args, **kwargs) File "/usr/local/lib/python3.7/site-packages/mailman/commands/cli_control.py", line 109, in start call_name(config.mta.incoming).regenerate() File "/usr/local/lib/python3.7/site-packages/mailman/mta/postfix.py", line 133, in regenerate raise RuntimeError(NL.join(errors)) RuntimeError: command failure: /usr/local/sbin/postmap /usr/local/mailman/data/postfix_lmtp, 127, Unknown error: 127 command failure: /usr/local/sbin/postmap /usr/local/mailman/data/postfix_domains, 127, Unknown error: 127 # service mailman onestatus GNU Mailman is running (master pid: 1882) # service mailman onestop Shutting down Mailman's master runner # service mailman onestatus GNU Mailman is not running
Without any further configuration, Mailman 3 wants to use Postfix as the MTA. Should I add Postfix to the mix or try to convince Mailman to use sendmail from base? Judging by Hooking up your mail server, ditching sendmail in favour of Postfix seems reasonable.
Upon reading D14126, I noticed service mailman info
. I decided to empty /usr/local/mailman
, add mailman_enable="YES"
to /etc/rc.conf
and run the command.
# service mailman info Usage: mailman [OPTIONS] COMMAND [ARGS]... Try 'mailman -h' for help. Error: Invalid value for '-C' / '--config': File '/usr/local/mailman/etc/mailman.cfg' does not exist.
Huh? What a tangled web we weave. Onwards!
# mkdir -p /usr/local/mailman/etc # touch /usr/local/mailman/etc/mailman.cfg # chown -R mailman:mailman /usr/local/mailman # service mailman info GNU Mailman 3.3.1 (Tom Sawyer) Python 3.7.9 (default, Oct 15 2020, 08:08:23) [Clang 10.0.1 (git@github.com:llvm/llvm-project.git llvmorg-10.0.1-0-gef32c611a config file: /usr/local/mailman/etc/mailman.cfg db url: sqlite:////usr/local/mailman/data/mailman.db devmode: DISABLED REST root url: http://localhost:8001/3.1/ REST credentials: restadmin:restpass
Apart from the empty configuration file, everything in /usr/local/mailman
are exactly as they were last night. Let’s try to start the service. Note, Postfix isn’t installed yet.
# service mailman start Starting Mailman's master runner Generating MTA alias maps sh: /usr/local/sbin/postmap: not found sh: /usr/local/sbin/postmap: not found Traceback (most recent call last): File "/usr/local/bin/mailman", line 11, inload_entry_point('mailman==3.3.1', 'console_scripts', 'mailman')() File "/usr/local/lib/python3.7/site-packages/click/core.py", line 829, in __call__ return self.main(*args, **kwargs) File "/usr/local/lib/python3.7/site-packages/click/core.py", line 782, in main rv = self.invoke(ctx) File "/usr/local/lib/python3.7/site-packages/mailman/bin/mailman.py", line 68, in invoke return super().invoke(ctx) File "/usr/local/lib/python3.7/site-packages/click/core.py", line 1259, in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) File "/usr/local/lib/python3.7/site-packages/click/core.py", line 1066, in invoke return ctx.invoke(self.callback, **ctx.params) File "/usr/local/lib/python3.7/site-packages/click/core.py", line 610, in invoke return callback(*args, **kwargs) File "/usr/local/lib/python3.7/site-packages/click/decorators.py", line 21, in new_func return f(get_current_context(), *args, **kwargs) File "/usr/local/lib/python3.7/site-packages/mailman/commands/cli_control.py", line 109, in start call_name(config.mta.incoming).regenerate() File "/usr/local/lib/python3.7/site-packages/mailman/mta/postfix.py", line 133, in regenerate raise RuntimeError(NL.join(errors)) RuntimeError: command failure: /usr/local/sbin/postmap /usr/local/mailman/data/postfix_lmtp, 127, Unknown error: 127 command failure: /usr/local/sbin/postmap /usr/local/mailman/data/postfix_domains, 127, Unknown error: 127
Let’s add Postfix to the mix.
# pkg install postfix Updating builder01 repository catalogue... builder01 repository is up to date. All repositories are up to date. Checking integrity... done (0 conflicting) The following 1 package(s) will be affected (of 0 checked): New packages to be INSTALLED: postfix: 3.5.8,1 Number of packages to be installed: 1 The process will require 7 MiB more space. Proceed with this action? [y/N]: y [1/1] Installing postfix-3.5.8,1... ===> Creating groups. Using existing group 'mail'. Creating group 'maildrop' with gid '126'. Creating group 'postfix' with gid '125'. ===> Creating users Creating user 'postfix' with uid '125'. ===> Creating homedir(s) [1/1] Extracting postfix-3.5.8,1: 100% =============================================================== Postfix was *not* activated in /usr/local/etc/mail/mailer.conf! To finish installation run the following commands: mkdir -p /usr/local/etc/mail install -m 0644 /usr/local/share/postfix/mailer.conf.postfix /usr/local/etc/mail/mailer.conf =============================================================== ===== Message from postfix-3.5.8,1: -- To use postfix instead of sendmail: - clear sendmail queue and stop the sendmail daemons Run the following commands to enable postfix during startup: - sysrc postfix_enable="YES" - sysrc sendmail_enable="NONE" If postfix is *not* already activated in /usr/local/etc/mail/mailer.conf - mv /usr/local/etc/mail/mailer.conf /usr/local/etc/mail/mailer.conf.old - install -m 0644 /usr/local/share/postfix/mailer.conf.postfix /usr/local/etc/mail/mailer.conf Disable sendmail(8) specific tasks, add the following lines to /etc/periodic.conf(.local): daily_clean_hoststat_enable="NO" daily_status_mail_rejects_enable="NO" daily_status_include_submit_mailq="NO" daily_submit_queuerun="NO" If you are using SASL, you need to make sure that postfix has access to read the sasldb file. This is accomplished by adding postfix to group mail and making the /usr/local/etc/sasldb* file(s) readable by group mail (this should be the default for new installs).
We need to do some housekeeping. I edited /etc/rc.conf
and /etc/periodic.conf
as instructed.
# less -S /usr/local/etc/mail/mailer.conf /usr/local/etc/mail/mailer.conf: No such file or directory # install -m 0644 /usr/local/share/postfix/mailer.conf.postfix /usr/local/etc/mail/mailer.conf install: /usr/local/etc/mail/mailer.conf: No such file or directory # mkdir -p /usr/local/etc/mail # install -m 0644 /usr/local/share/postfix/mailer.conf.postfix /usr/local/etc/mail/mailer.conf
While the correct instructions was displayed initially, we were also presented with some half-baked instructions further down the line.
Anyway, what does Mailman think of this new addition?
# service postfix start postfix/postfix-script: starting the Postfix mail system # service mailman restart Restarting the Mailman runners
This looks very promising, no error messages. Here’s the process tree:
# ps -aduwwx | grep mailman mailman 5861 0.0 0.9 86196 74100 - Is 10:22 0:01.31 |-- /usr/local/bin/python3.7 /usr/local/bin/master -C /usr/local/mailman/etc/mailman.cfg mailman 5873 0.0 1.0 93180 80632 - S 10:22 0:02.20 | |-- python3.7: gunicorn: master [gunicorn] (python3.7) mailman 5889 0.0 1.0 93180 80652 - S 10:22 0:00.10 | | |-- python3.7: gunicorn: worker [gunicorn] (python3.7) mailman 5890 0.0 1.0 93180 80664 - S 10:22 0:00.09 | | `-- python3.7: gunicorn: worker [gunicorn] (python3.7) mailman 10689 0.0 0.9 86476 74212 - I 11:08 0:01.26 | |-- /usr/local/bin/python3.7 /usr/local/bin/runner -C /usr/local/mailman/etc/mailman.cfg --runner=retry:0:1 mailman 10690 0.0 0.9 86476 74212 - S 11:08 0:01.76 | |-- /usr/local/bin/python3.7 /usr/local/bin/runner -C /usr/local/mailman/etc/mailman.cfg --runner=archive:0:1 mailman 10691 0.0 0.9 88216 76016 - I 11:08 0:01.46 | |-- /usr/local/bin/python3.7 /usr/local/bin/runner -C /usr/local/mailman/etc/mailman.cfg --runner=bounces:0:1 mailman 10692 0.0 0.9 86476 74212 - S 11:08 0:01.86 | |-- /usr/local/bin/python3.7 /usr/local/bin/runner -C /usr/local/mailman/etc/mailman.cfg --runner=in:0:1 mailman 10694 0.0 0.9 86476 74212 - S 11:08 0:01.76 | |-- /usr/local/bin/python3.7 /usr/local/bin/runner -C /usr/local/mailman/etc/mailman.cfg --runner=digest:0:1 mailman 10695 0.0 0.9 86476 74300 - S 11:08 0:01.76 | |-- /usr/local/bin/python3.7 /usr/local/bin/runner -C /usr/local/mailman/etc/mailman.cfg --runner=out:0:1 mailman 10696 0.0 0.9 86476 74216 - S 11:08 0:01.76 | |-- /usr/local/bin/python3.7 /usr/local/bin/runner -C /usr/local/mailman/etc/mailman.cfg --runner=nntp:0:1 mailman 10697 0.0 0.9 86476 74216 - S 11:08 0:01.77 | |-- /usr/local/bin/python3.7 /usr/local/bin/runner -C /usr/local/mailman/etc/mailman.cfg --runner=virgin:0:1 mailman 10698 0.0 0.9 86476 74212 - S 11:08 0:01.74 | |-- /usr/local/bin/python3.7 /usr/local/bin/runner -C /usr/local/mailman/etc/mailman.cfg --runner=pipeline:0:1 mailman 10699 0.0 0.9 88692 74364 - S 11:08 0:01.43 | |-- /usr/local/bin/python3.7 /usr/local/bin/runner -C /usr/local/mailman/etc/mailman.cfg --runner=lmtp:0:1 mailman 10700 0.0 0.9 86476 74240 - S 11:08 0:01.77 | `-- /usr/local/bin/python3.7 /usr/local/bin/runner -C /usr/local/mailman/etc/mailman.cfg --runner=command:0:1
Let’s create the initial list.
# mailman create --language no --owner postmaster@[REDACTED] -no-notify mailman Error: Illegal list name: mailman # mailman create --language no --owner postmaster@[REDACTED] -no-notify mailman@lists.[REDACTED] Created mailing list: mailman@lists.[REDACTED]
Note, the name of the list is its posting address, and there is only one leading hyphen in -no-notify
. The latter must be a bug in Mailman 3.3.1.
These are more or less the defaults as shown by mailman conf
:
[ARC] authserv_id: [ARC] dkim: yes [ARC] dmarc: yes [ARC] domain: [ARC] enabled: no [ARC] privkey: [ARC] selector: [ARC] 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 [ARC] trusted_authserv_ids: [antispam] header_checks: [antispam] jump_chain: hold [archiver.mail_archive] class: mailman.archiving.mailarchive.MailArchive [archiver.mail_archive] clobber_date: maybe [archiver.mail_archive] clobber_skew: 1d [archiver.mail_archive] configuration: python:mailman.config.mail_archive [archiver.mail_archive] enable: no [archiver.master] class: [archiver.master] clobber_date: maybe [archiver.master] clobber_skew: 1d [archiver.master] configuration: changeme [archiver.master] enable: no [archiver.mhonarc] class: mailman.archiving.mhonarc.MHonArc [archiver.mhonarc] clobber_date: maybe [archiver.mhonarc] clobber_skew: 1d [archiver.mhonarc] configuration: python:mailman.config.mhonarc [archiver.mhonarc] enable: no [archiver.prototype] class: mailman.archiving.prototype.Prototype [archiver.prototype] clobber_date: maybe [archiver.prototype] clobber_skew: 1d [archiver.prototype] configuration: changeme [archiver.prototype] enable: no [bounces] register_bounces_every: 15m [database] class: mailman.database.sqlite.SQLiteDatabase [database] debug: no [database] url: sqlite:///$DATA_DIR/mailman.db [devmode] enabled: no [devmode] recipient: [devmode] testing: no [devmode] wait: 60s [digests] 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 [digests] plain_digest_keep_headers: Message Date From Subject To Cc Message-ID Keywords Content-Type [dmarc] cache_lifetime: 7d [dmarc] org_domain_data_url: https://publicsuffix.org/list/public_suffix_list.dat [dmarc] resolver_lifetime: 5s [dmarc] resolver_timeout: 3s [language.ar] charset: utf-8 [language.ar] description: Arabic [language.ar] enabled: yes [language.ast] charset: iso-8859-1 [language.ast] description: Asturian [language.ast] enabled: yes [language.ca] charset: utf-8 [language.ca] description: Catalan [language.ca] enabled: yes [language.cs] charset: iso-8859-2 [language.cs] description: Czech [language.cs] enabled: yes [language.da] charset: iso-8859-1 [language.da] description: Danish [language.da] enabled: yes [language.de] charset: utf-8 [language.de] description: German [language.de] enabled: yes [language.el] charset: iso-8859-7 [language.el] description: Greek [language.el] enabled: yes [language.es] charset: iso-8859-1 [language.es] description: Spanish [language.es] enabled: yes [language.et] charset: iso-8859-15 [language.et] description: Estonian [language.et] enabled: yes [language.eu] charset: iso-8859-15 [language.eu] description: Euskara [language.eu] enabled: yes [language.fi] charset: iso-8859-1 [language.fi] description: Finnish [language.fi] enabled: yes [language.fr] charset: utf-8 [language.fr] description: French [language.fr] enabled: yes [language.gl] charset: utf-8 [language.gl] description: Galician [language.gl] enabled: yes [language.he] charset: utf-8 [language.he] description: Hebrew [language.he] enabled: yes [language.hr] charset: iso-8859-2 [language.hr] description: Croatian [language.hr] enabled: yes [language.hu] charset: iso-8859-2 [language.hu] description: Hungarian [language.hu] enabled: yes [language.ia] charset: iso-8859-15 [language.ia] description: Interlingua [language.ia] enabled: yes [language.it] charset: iso-8859-1 [language.it] description: Italian [language.it] enabled: yes [language.ja] charset: euc-jp [language.ja] description: Japanese [language.ja] enabled: yes [language.ko] charset: euc-kr [language.ko] description: Korean [language.ko] enabled: yes [language.lt] charset: iso-8859-13 [language.lt] description: Lithuanian [language.lt] enabled: yes [language.nl] charset: iso-8859-1 [language.nl] description: Dutch [language.nl] enabled: yes [language.no] charset: iso-8859-1 [language.no] description: Norwegian [language.no] enabled: yes [language.pl] charset: iso-8859-2 [language.pl] description: Polish [language.pl] enabled: yes [language.pt] charset: iso-8859-1 [language.pt] description: Protuguese [language.pt] enabled: yes [language.pt_BR] charset: iso-8859-1 [language.pt_BR] description: Protuguese (Brazil) [language.pt_BR] enabled: yes [language.ro] charset: iso-8859-2 [language.ro] description: Romanian [language.ro] enabled: yes [language.ru] charset: koi8-r [language.ru] description: Russian [language.ru] enabled: yes [language.sk] charset: utf-8 [language.sk] description: Slovak [language.sk] enabled: yes [language.sl] charset: iso-8859-2 [language.sl] description: Slovenian [language.sl] enabled: yes [language.sr] charset: utf-8 [language.sr] description: Serbian [language.sr] enabled: yes [language.sv] charset: iso-8859-1 [language.sv] description: Swedish [language.sv] enabled: yes [language.tr] charset: iso-8859-9 [language.tr] description: Turkish [language.tr] enabled: yes [language.uk] charset: utf-8 [language.uk] description: Ukrainian [language.uk] enabled: yes [language.vi] charset: utf-8 [language.vi] description: Vietnamese [language.vi] enabled: yes [language.zh_CN] charset: utf-8 [language.zh_CN] description: Chinese [language.zh_CN] enabled: yes [language.zh_TW] charset: utf-8 [language.zh_TW] description: Chinese (Taiwan) [language.zh_TW] enabled: yes [logging.archiver] datefmt: %b %d %H:%M:%S %Y [logging.archiver] format: %(asctime)s (%(process)d) %(message)s [logging.archiver] level: info [logging.archiver] path: mailman.log [logging.archiver] propagate: no [logging.bounce] datefmt: %b %d %H:%M:%S %Y [logging.bounce] format: %(asctime)s (%(process)d) %(message)s [logging.bounce] level: info [logging.bounce] path: bounce.log [logging.bounce] propagate: no [logging.config] datefmt: %b %d %H:%M:%S %Y [logging.config] format: %(asctime)s (%(process)d) %(message)s [logging.config] level: info [logging.config] path: mailman.log [logging.config] propagate: no [logging.database] datefmt: %b %d %H:%M:%S %Y [logging.database] format: %(asctime)s (%(process)d) %(message)s [logging.database] level: warn [logging.database] path: mailman.log [logging.database] propagate: no [logging.debug] datefmt: %b %d %H:%M:%S %Y [logging.debug] format: %(asctime)s (%(process)d) %(message)s [logging.debug] level: info [logging.debug] path: debug.log [logging.debug] propagate: no [logging.error] datefmt: %b %d %H:%M:%S %Y [logging.error] format: %(asctime)s (%(process)d) %(message)s [logging.error] level: info [logging.error] path: mailman.log [logging.error] propagate: no [logging.fromusenet] datefmt: %b %d %H:%M:%S %Y [logging.fromusenet] format: %(asctime)s (%(process)d) %(message)s [logging.fromusenet] level: info [logging.fromusenet] path: mailman.log [logging.fromusenet] propagate: no [logging.http] datefmt: %b %d %H:%M:%S %Y [logging.http] format: %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s" [logging.http] level: info [logging.http] path: mailman.log [logging.http] propagate: no [logging.locks] datefmt: %b %d %H:%M:%S %Y [logging.locks] format: %(asctime)s (%(process)d) %(message)s [logging.locks] level: info [logging.locks] path: mailman.log [logging.locks] propagate: no [logging.mischief] datefmt: %b %d %H:%M:%S %Y [logging.mischief] format: %(asctime)s (%(process)d) %(message)s [logging.mischief] level: info [logging.mischief] path: mailman.log [logging.mischief] propagate: no [logging.plugins] datefmt: %b %d %H:%M:%S %Y [logging.plugins] format: %(asctime)s (%(process)d) %(message)s [logging.plugins] level: info [logging.plugins] path: plugins.log [logging.plugins] propagate: no [logging.root] datefmt: %b %d %H:%M:%S %Y [logging.root] format: %(asctime)s (%(process)d) %(message)s [logging.root] level: info [logging.root] path: mailman.log [logging.root] propagate: no [logging.runner] datefmt: %b %d %H:%M:%S %Y [logging.runner] format: %(asctime)s (%(process)d) %(message)s [logging.runner] level: info [logging.runner] path: mailman.log [logging.runner] propagate: no [logging.smtp] datefmt: %b %d %H:%M:%S %Y [logging.smtp] every: $msgid smtp to $listname for $recip recips, completed in $time seconds [logging.smtp] failure: $msgid delivery to $recip failed with code $smtpcode, $smtpmsg [logging.smtp] format: %(asctime)s (%(process)d) %(message)s [logging.smtp] level: info [logging.smtp] path: smtp.log [logging.smtp] propagate: no [logging.smtp] refused: $msgid post to $listname from $sender, $size bytes, $refused failures [logging.smtp] success: $msgid post to $listname from $sender, $size bytes [logging.subscribe] datefmt: %b %d %H:%M:%S %Y [logging.subscribe] format: %(asctime)s (%(process)d) %(message)s [logging.subscribe] level: info [logging.subscribe] path: mailman.log [logging.subscribe] propagate: no [logging.vette] datefmt: %b %d %H:%M:%S %Y [logging.vette] format: %(asctime)s (%(process)d) %(message)s [logging.vette] level: info [logging.vette] path: mailman.log [logging.vette] propagate: no [mailman] cache_life: 7d [mailman] default_language: en [mailman] email_commands_max_lines: 10 [mailman] filtered_messages_are_preservable: no [mailman] html_to_plain_text_command: /usr/local/bin/lynx -dump $filename [mailman] layout: home [mailman] listname_chars: [-_.0-9a-z] [mailman] noreply_address: noreply [mailman] pending_request_life: 3d [mailman] post_hook: [mailman] pre_hook: [mailman] sender_headers: from from_ reply-to sender [mailman] site_owner: changeme@example.com [mta] configuration: python:mailman.config.postfix [mta] delivery_retry_period: 5d [mta] incoming: mailman.mta.postfix.LMTP [mta] lmtp_host: 127.0.0.1 [mta] lmtp_port: 8024 [mta] max_autoresponses_per_day: 10 [mta] max_delivery_threads: 0 [mta] max_recipients: 500 [mta] max_sessions_per_connection: 0 [mta] outgoing: mailman.mta.deliver.deliver [mta] remove_dkim_headers: no [mta] smtp_host: localhost [mta] smtp_pass: [mta] smtp_port: 25 [mta] smtp_secure_mode: smtp [mta] smtp_user: [mta] smtp_verify_cert: yes [mta] smtp_verify_hostname: yes [mta] verp_confirm_format: $address+$cookie [mta] verp_confirm_regexp: ^(.*<)?(?P[^+]+?)\+(?P [^@]+)@.*$ [mta] verp_confirmations: no [mta] verp_delimiter: + [mta] verp_delivery_interval: 0 [mta] verp_format: ${bounces}+${local}=${domain} [mta] verp_personalized_deliveries: no [mta] verp_probe_format: $bounces+$token@$domain [mta] verp_probe_regexp: ^(?P [^+]+?)\+(?P [^@]+)@.*$ [mta] verp_probes: no [mta] verp_regexp: ^(?P [^+]+?)\+(?P [^=]+)=(?P [^@]+)@.*$ [nntp] host: [nntp] password: [nntp] port: [nntp] remove_headers: nntp-posting-host nntp-posting-date x-trace x-complaints-to xref date-received posted posting-version relay-version received [nntp] rewrite_duplicate_headers: To X-Original-To CC X-Original-CC Content-Transfer-Encoding X-Original-Content-Transfer-Encoding MIME-Version X-MIME-Version [nntp] user: [passwords] configuration: python:mailman.config.passlib [passwords] password_length: 8 [plugin.master] class: [plugin.master] component_package: [plugin.master] configuration: [plugin.master] enabled: no 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. history_file: prompt: >>> use_ipython: no [styles] default: legacy-default [webservice] admin_pass: restpass [webservice] admin_user: restadmin [webservice] api_version: 3.1 [webservice] configuration: python:mailman.config.gunicorn [webservice] hostname: localhost [webservice] port: 8001 [webservice] show_tracebacks: yes [webservice] use_https: no [webservice] workers: 2
These are the settings that must be changed or emphasized in my opinion:
[mailman] default_language: no
[mailman] layout: home
[mailman] site_owner: postmaster@[REDACTED]
[mta] remove_dkim_headers: yes
(I hope FreeBSD’s future mailling list system will strip away DKIM headers.)
In other words, /usr/local/mailman/etc/mailman.cfg
should end up looking like this:
[mailman] default_language: no layout: home site_owner: postmaster@[REDACTED] [mta] remove_dkim_headers: yes
Postfix must be able to relay received mail over to Mailman. Thus, /usr/local/etc/postfix/main.cf
must be changed accordingly:
--- etc/postfix/main.cf.sample 2020-11-26 14:02:06.000000000 +0100 +++ etc/postfix/main.cf 2020-12-03 14:28:43.652690000 +0100 @@ -401,6 +401,8 @@ #alias_maps = hash:/etc/aliases #alias_maps = hash:/etc/aliases, nis:mail.aliases #alias_maps = netinfo:/aliases +#alias_maps = hash:/etc/mail/aliases +alias_maps = hash:/etc/mail/aliases, hash:/usr/local/mailman/data/postfix_lmtp # The alias_database parameter specifies the alias database(s) that # are built with "newaliases" or "sendmail -bi". This is a separate @@ -410,6 +412,7 @@ #alias_database = dbm:/etc/aliases #alias_database = hash:/etc/aliases #alias_database = hash:/etc/aliases, hash:/opt/majordomo/aliases +#alias_database = hash:/etc/mail/aliases, hash:/usr/local/mailman/data/postfix_lmtp # ADDRESS EXTENSIONS (e.g., user+foo) # @@ -501,6 +504,7 @@ #fallback_transport = lmtp:unix:/file/name #fallback_transport = cyrus #fallback_transport = +fallback_transport = lmtp:127.0.0.1:8024 # The luser_relay parameter specifies an optional destination address # for unknown recipients. By default, mail for unknown@$mydestination,
I admit I’m in unknown territory. Maybe simply the format of /usr/local/mailman/data/postfix_lmtp
is foreign to Postfix. At this point I’m able to send and receive mail. The next step is the web interface(s) for easier administration and for mail archives.
2020-12-04
It sure helps to follow the MTA guide, so this is how Postfix’ main.cf
configuration file differ from the sample file.
--- etc/postfix/main.cf.sample 2020-11-26 14:02:06.000000000 +0100 +++ etc/postfix/main.cf 2020-12-04 17:14:23.339697000 +0100 @@ -220,7 +220,7 @@ # In the left-hand side, specify a bare username, an @domain.tld # wild-card, or specify a user@domain.tld address. #. -#local_recipient_maps = unix:passwd.byname $alias_maps +local_recipient_maps = unix:passwd.byname $alias_maps hash:/usr/local/mailman/data/postfix_lmtp #local_recipient_maps = proxy:unix:passwd.byname $alias_maps #local_recipient_maps = @@ -397,9 +397,9 @@ # It will take a minute or so before changes become visible. Use # "postfix reload" to eliminate the delay. # -#alias_maps = dbm:/etc/aliases -#alias_maps = hash:/etc/aliases -#alias_maps = hash:/etc/aliases, nis:mail.aliases +#alias_maps = dbm:/etc/mail/aliases +alias_maps = hash:/etc/mail/aliases +#alias_maps = hash:/etc/mail/aliases, nis:mail.aliases #alias_maps = netinfo:/aliases # The alias_database parameter specifies the alias database(s) that @@ -407,9 +407,9 @@ # configuration parameter, because alias_maps (see above) may specify # tables that are not necessarily all under control by Postfix. # -#alias_database = dbm:/etc/aliases -#alias_database = hash:/etc/aliases -#alias_database = hash:/etc/aliases, hash:/opt/majordomo/aliases +#alias_database = dbm:/etc/mail/aliases +#alias_database = hash:/etc/mail/aliases +#alias_database = hash:/etc/mail/aliases, hash:/opt/majordomo/aliases # ADDRESS EXTENSIONS (e.g., user+foo) # @@ -420,7 +420,7 @@ # Basically, the software tries user+foo and .forward+foo before # trying user and .forward. # -#recipient_delimiter = + +recipient_delimiter = + # DELIVERY TO MAILBOX # @@ -501,6 +501,7 @@ #fallback_transport = lmtp:unix:/file/name #fallback_transport = cyrus #fallback_transport = +#fallback_transport = lmtp:127.0.0.1:8024 # The luser_relay parameter specifies an optional destination address # for unknown recipients. By default, mail for unknown@$mydestination, @@ -675,3 +676,10 @@ inet_protocols = ipv4 meta_directory = /usr/local/libexec/postfix shlib_directory = /usr/local/lib/postfix + +# https://docs.mailman3.org/projects/mailman/en/latest/src/mailman/docs/mta.html +owner_request_special = no +transport_maps = hash:/usr/local/mailman/data/postfix_lmtp +relay_domains = hash:/usr/local/mailman/data/postfix_domains + +# EOF
I wonder if I can find a description of the Python object representation of each list. Right now I feel I’m ready to edit some settings.
The to-do list include:
- Get Postorius up & running.
- Get some kind of archiver, maybe HyperKitty, up & running.
- Get rid of
footer_uri
(previously known asmsg_footer
). - Adjust other parameters of each list.
- Add members to each list.
- Inform the users on how to proceed from here.