Mailman is free software for managing electronic mail discussion and e-newsletter lists. Mailman is integrated with the web, making it easy for users to manage their accounts and for list owners to administer their lists. Mailman supports built-in archiving, automatic bounce processing, content filtering, digest delivery, spam filters, and more.
Mailman is free software, distributed under the GNU General Public License, and written in the Python programming language.
Index
- Preparing the virtual environment
- Installing
Mailman core - Set up
Mailman WebUI - Log rotation
- Adding domains
- Known issues
If you are looking for a more complete and advanced mailing list software than ezmlm-idx, whose future is also uncertain since it hasn't been updated for a very long time, Mailman is definitely one of the best options.
Concerning the documentation, it's not easy to find the best starting point at the beginning. This is the one that worked for me (I'll add further links to the documentation during the next steps):
Preparing the virtual environment
- More info here
The
venvmodule supports creating lightweight “virtual environments”, each with their own independent set of Python packages installed in theirsitedirectories. A virtual environment is created on top of an existing Python installation, known as the virtual environment’s “base” Python, and may optionally be isolated from the packages in the base environment, so only those explicitly installed in the virtual environment are available.
Add the mailman user:
groupadd mailman useradd -g mailman -d /usr/local/mailman mailman mkdir /usr/local/mailman chown -R mailman:mailman /usr/local/mailman
The mailman user's home directory /usr/local/mailman is the container where the virtual environment that we are going to build will live.
The creation of the virtual environment must be done as the mailman user:
su - mailman
First of all create the .profile file for the mailman user, so that the next time you call the pip binary it will be taken from its virtual environment (run the same from the command line or exit from the shell):
echo "export PATH=~/bin:\$PATH" > .profile
Prepare the virtual environment:
python3 -m venv --upgrade-deps /usr/local/mailman
This will create the virtual environment in /usr/local/mailman. Always as the mailman user activate the virtual environment:
cd source bin/activate
Your command prompt will slightly change its appearence to inform that you entered the virtual environment.
(mailman) mailman@qmail:~$
Activating the virtual environment will prepend the /usr/local/mailman directory to your PATH, so that running python will invoke the environment’s python interpreter and you can run installed scripts without having to use their full path.
Be aware that you have to activate the virtual environment each time you do an (un)installation/upgrade of a python package. To deactivate just run the deactivate command.
The rest of this documentation mostly assumes that the virtual environment is activated. Whether or not a certain command needs that the virtual environment is activated can be seen by a (mailman) before the $ shell prompt. It is also assumed that you activate the virtual environment as the mailman user.
Installing Mailman core
- Version: GNU Mailman 3.3.9 (Tom Sawyer)
- Official docs
Do not exit from the virtual environment as we have to do the Mailman core installation from the inside using the pip command, which is a copy of the pip3 in our virtual environment.
(mailman)$ pip install mailman
This command installs Mailman core with all its prerequisites in the virtual environment. If everything is ok it exits with a "Successfully installed" verb followed by the list of the packages installed.
Typing mailman info will show the details and version of the installed Mailman.
Configuration
By default Mailman will look for its configuration file in the ~/var/etc directory. Since I prefer to use ~/etc (also for other config files that have to come later), some adjustment is needed. We have to define the environment variable MAILMAN_CONFIG_FILE in the .profile file:
su - mailman source bin/activate (mailman)$ cat >> ~/.profile << __EOF__ export MAILMAN_CONFIG_FILE=~/etc/mailman.cfg export PYTHONPATH=~/etc export PYTHONHOME=~/ __EOF__
Create the etc directory
(mailman)$ mkdir -p ~/etc
Now edit the ~/etc/mailman.cfg, which overwrites the settings shown in schema.cfg.
(mailman)$ cat >> ~/etc/mailman.cfg << __EOF__ [devmode] enabled: no [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: postmaster@mydomain.tld # The default language for this server. default_language: en [paths.master] var_dir: /usr/local/mailman/var [logging.database] level: warn [logging.debug] path: debug.log level: warn [logging.http] level: warn [logging.smtp] path: smtp.log level: info [language.it] description: Italian charset: utf-8 enabled: yes [mta] # https://docs.mailman3.org/projects/mailman/en/latest/src/mailman/docs/mta.html#qmail # # NullMTA is just implementing the interface and thus satisfying Mailman # without doing anything fancy incoming: mailman.mta.null.NullMTA # Mailman should not be run as root. # Use any convenient port > 1024. 8024 is a convention, but can be # changed if there is a conflict with other software using that port. lmtp_host: 127.0.0.1 lmtp_port: 8024 # This will listen on localhost:8024 with LMTP and deliver outgoing messages to localhost:25. # 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: 10.0.0.4 # 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 __EOF__
Adjust the preferred language and the site owner's email to your needs.
Secure mailman.cfg as it has to store the database password:
chmod o-r ~/etc/mailman.cfg
Hooking up qmail to work with Mailman
The following commands must be run as root, so exit from the mailman shell (exit).
We'll host the lists on a virtual domain, let's say lists.mydomain.tld (if you want to use other domains as well or ordinary virtual domains for your lists read below towards the end of this article), and use the /var/qmail/control/virtualdomains file to put the mailman user in charge of this virtual domain:
echo lists.mydomain.tld:mailman >> /var/qmail/control/virtualdomains
Be aware that this virtual domain should not be created by the usual vadddomain program, as it exists just to bind the mailman user to the lists.mydomain.tld domain and its definition is different from the vpopmail's ordinary domains. In this context, mailman is a qmail user which has nothing to do with its counterpart in the Linux user space.
Make also sure to setup SPF, DKIM and DMARC for lists.mydomain.tld.
Add lists.mydomain.tld to rcpthosts so that qmail-smtpd will accept mails for that domain. Do not add it to control/locals otherwise the virtualdomains file will be ignored and the Mailman program won't be called.
echo lists.mydomain.tld >> /var/qmail/control/rcpthosts
The settings to make Mailman work with qmail are already in the mailman.cfg that we created above:
[mta] # NullMTA is just implementing the interface and thus satisfying Mailman # without doing anything fancy. Default would be postfix otherwise. incoming: mailman.mta.null.NullMTA # Use any convenient port > 1024. 8024 is a convention, but can be # changed if there is a conflict with other software using that port. # This will listen on localhost:8024 with LMTP and deliver outgoing messages # to localhost:25. lmtp_port: 8024
The qmail-lmtp script in the contrib directory is used to tell Mailman how many parts (separated by dashes) of the destination address to filter out. We'll not use the one available in the contrib directory because it doesn't work with mailman3, as explained here, where I found a patch to cure the problem. In fact, qmail-local sends bare LF for the end line, while the SMTP standards require CRLF, so the SMTP conversation between qmail and Mailman ends up with the error: "Line too long (see RFC5321 4.5.3.1.6)". According to what a developer said the patched qmail-lmtp file that we are going to install can have unpredictable results when binary files with \n and \r characters are sent (that would need qmail-local to be patched). Anyway it works fine here with my lists, although I've never tested them with binary files.
(mailman)$ wget -O ~/qmail-lmtp https://notes.sagredo.eu/files/qmail/mailman/qmail-lmtp
Now insert the call to that script in the default dot-qmail file
(mailman)$ echo "|~/qmail-lmtp 8024 1" > ~/.qmail-default
The first argument specifies the LMTP port of Mailman.
Since inbound messages are delivered by qmail to the mailman user, it's necessary to allow it to access its home directory ~mailman, that is to say qmail must have read access to the ~/mailman/.qmail-default file, which stores the informations about the program that will handle the delivery, Mailman in our case:
(mailman)$ chmod 644 ~/.qmail-default
Mailman will send via LMTP to our qmail MTA tons of concurrent mails and if you enabled a limit on the number of recipients specified per message, you need to change that limit to accomodate the number of recipients of your lists. If you are using the qmail-maxrcpt patch that is included in my qmail package, check the limit in the qmail/control/maxrcpt file. You can set DISABLE_MAXRCPT in your tcprules to disable the limit for local IPs (v. 2024.06.08 upwards).
Finally we have to avoid to run simscan's filters when qmail receives messages from the Mailman's LMTP service, as it may throw it into DKIM verification errors. Modify your tcp rules accordingly adding a QMAILQUEUE="/var/qmail/bin/qmail-queue" rule to your local IPs.
Here is an example of tcprules:
127.:allow,RELAYCLIENT="",DISABLE_MAXRCPT="",QMAILQUEUE="/var/qmail/bin/qmail-queue" 0.0.0.0:allow,RELAYCLIENT="",DISABLE_MAXRCPT="",QMAILQUEUE="/var/qmail/bin/qmail-queue" 10.0.0.:allow,RELAYCLIENT="",QMAILQUEUE="/var/qmail/bin/qmail-queue"
Then compile the tcp rules with qmailctl cdb.
Setting up MySQL
Mailman needs a relational database to provide persistence of data. If you prefer to store the data to SQLite proceed to the next step, as it is the default database. To use MySQL, install the pymysql module first:
(mailman)$ pip install pymysql
Then prepare the database and the MySQL mailman user:
CREATE USER 'mailman'@'localhost' IDENTIFIED VIA mysql_native_password USING '***'; GRANT USAGE ON *.* TO 'mailman'@'localhost' REQUIRE NONE WITH MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0; CREATE DATABASE IF NOT EXISTS `mailman` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; GRANT ALL PRIVILEGES ON `mailman`.* TO 'mailman'@'localhost';
Of course change localhost if the MySQL server is elsewhere in your net.
Add the database settings in the ~/etc/mailman.cfg file
(mailman)$ cat >> ~/etc/mailman.cfg << __EOF__ [database] class: mailman.database.mysql.MySQLDatabase url: mysql+pymysql://mailman:password@localhost/mailman?charset=utf8mb4&use_unicode=1 __EOF__
Running Mailman
To start/stop the server you can do mailman start/stop as the mailman user. If your system has systemd please refer to the official documentation here, otherwise download the init script, make it executable and load it into your rc.local.
This has to be done as root
wget -O /usr/local/bin/mmctl https://notes.sagredo.eu/files/qmail/mailman/mmctl chmod +x /usr/local/bin/mmctl mmctl start
The startup script needs to change to the ~mailman dir due to a bug.
If the mmctl info command returns no error Mailman core is configured successfully:
# mmctl info GNU Mailman 3.3.9 (Tom Sawyer) Python 3.9.19 (main, Mar 20 2024, 14:44:21) [GCC 11.2.0] config file: /usr/local/mailman/var/etc/mailman.cfg db url: mysql+pymysql://mailman:password@localhost/mailman?charset=utf8mb4&use_unicode=1 devmode: DISABLED REST root url: http://localhost:8001/3.1/ REST credentials: restadmin:restpass
You can do the same test as the mailman user in activated mode calling mailman info.
You can interact with Mailman via command line by typing mailman shell (help() for interactive help), but it will be easier to play with the Postorius web interface.
Cronjobs
Mailman requires the following cronjobs for periodic actions. Add the following to the mailman user cronjob (su - mailman && crontab -e):
@daily ID=mailman source /usr/local/mailman/bin/activate && /usr/local/mailman/bin/mailman -C /usr/local/mailman/etc/mailman.cfg notify >> /usr/local/mailman/var/logs/cron.log 2>&1 @daily ID=mailman source /usr/local/mailman/bin/activate && /usr/local/mailman/bin/mailman -C /usr/local/mailman/etc/mailman.cfg digests --periodic >> /usr/local/mailman/var/logs/cron.log 2>&1
Set up Mailman Web UI
PostoriusandHyperkittyareMailman’s official Web UI and Archiver.Mailman-webprovides a convenient single package to install both of these. You can runMailman3 without it, but most people prefer to use the web interface for changing list settings, viewing information about available lists, and subscribing or unsubscribing.Djangois thepythonweb framework used to buildPostoriusandHyperkitty.
Let's enter the virtual environment again and install Mailman web:
su - mailman source bin/activate (mailman)$ pip install mysqlclient mailman-web mailman-hyperkitty pylibmc
We'll use the MySQL database in a new mailman_web database (the owner will be mailman, who already owns the mailman database that we created earlier):
CREATE DATABASE `mailman_web` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
GRANT ALL PRIVILEGES ON `mailman_web`.* TO 'mailman'@'localhost';
The CHARACTER SET utf8mb4 parameter is important.
The ~/settings.py file will hold the settings for Mailman web. Download and adjust it to your needs:
(mailman)$ wget -O ~/etc/settings.py https://notes.sagredo.eu/files/qmail/mailman/settings.py (mailman)$ chmod o-r ~/etc/settings.py
It's important to add your domain to the variables ALLOWED_HOSTS and CSRF_TRUSTED_ORIGINS. Here lists.mydomain.tld is the web server's virtual host used for the Mailman web site; I'm supposing that it could be the same as the domain where we decided to define the lists, but it can be a different one.
#: See https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts ALLOWED_HOSTS = [ "localhost", # Archiving API from Mailman, keep it. "127.0.0.1", "0.0.0.0", "lists.mydomain.tld", # Add here all production domains you have. ] #: See https://docs.djangoproject.com/en/dev/ref/settings/#csrf-trusted-origins #: For Django <4.0 these are of the form 'lists.example.com' or #: '.example.com' to include subdomains and for Django >=4.0 they include #: the scheme as in 'https://lists.example.com' or 'https://*.example.com'. CSRF_TRUSTED_ORIGINS = [ "http://lists.mydomain.tld", "https://lists.mydomain.tld", # "lists.your-domain.org", # Add here all production domains you have. ]
Add its location to the mailman's user .profile (default would be /etc/settings.py otherwise):
(mailman)$ cat >> ~/.profile << __EOF__ export DJANGO_SETTINGS_MODULE=~/etc/settings __EOF__
Be carefull when setting SITE_ID. It is the ID of the Django Site being served, i.e. the site that will serve your Mailman web control panel.
#: Current Django Site being served. This is used to customize the web host #: being used to serve the current website. For more details about Django #: site, see: https://docs.djangoproject.com/en/dev/ref/contrib/sites/ SITE_ID = 2
When you open the Mailman web interface, you'll have an example.com site already created with SITE_ID = 1 that you may want to delete and replace with mydomain.tld, which will have SITE_ID = 2 or whatelse. Enter its value in settings.py file, presumibly it will be 2.
Create the directory where the web interface will live:
mkdir -p ~/web/logs
In the following commands we have to pass some variables to mailman-web. I don't know why it doesn't read those variables from env. Setup the database schema for Mailman’s web components:
(mailman)$ PYTHONPATH=~/etc/ DJANGO_SETTINGS_MODULE=settings mailman-web migrate
Copy all the static files (css, js, images) into the STATIC_ROOT:
(mailman)$ PYTHONPATH=~/etc/ DJANGO_SETTINGS_MODULE=settings mailman-web collectstatic
Compress the various CSS files offline (the sass package is needed):
(mailman)$ PYTHONPATH=~/etc/ DJANGO_SETTINGS_MODULE=settings mailman-web compress
Update the message catalogs for supported languages:
(mailman)$ PYTHONPATH=~/etc/ DJANGO_SETTINGS_MODULE=settings mailman-web compilemessages
Now set up the admin account. The superuser is assumed to be the Site Owner and has access to all the domains, mailing lists and their settings. You'll be asked to enter and confirm the email address of the admin account. Do not use an account such as postmaster@lists.mydomain.tld because it would be difficult to retrieve the confirmation message. Use something like postmaster@mydomain.tld instead.
(mailman)$ PYTHONPATH=~/etc/ DJANGO_SETTINGS_MODULE=settings mailman-web createsuperuser
memcached setup
Installing memcached and the pylibmc package that we have installed earlier is recommended to fix an issue concerning the erase of items in the archive (more info here), which can be solved installing a caching system that is common across all workers. memcached installation can be easily done with a package of the OS and is not covered here; just be sure that it is launched at boot time and that it is listening on the 11211 port. memcached settings are already stored in the settings.py file that we downloaded earlier:
# Using the cache infrastructure can significantly improve performance on a
# production setup. This is an example with a local Memcached server.
# pip install pylibmc
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
'LOCATION': '127.0.0.1:11211',
}
}
Setting up a WSGI server
WSGI gets Django to work behind apache or another web server. Django is the python web framework used to build Postorius and Hyperkitty.
(mailman)$ pip install uwsgi
Download the configuration file (there's no need to modify it):
wget -O ~/etc/uwsgi.ini https://notes.sagredo.eu/files/qmail/mailman/uwsgi.ini
Test (exit with ^C):
(mailman)$ uwsgi --ini ~/etc/uwsgi.ini
Startup script
Those under systemd should refer to the official documentation here. Users who can do what they want with their system can use this scriptlet:
wget -O /usr/local/bin/uwsgictl https://notes.sagredo.eu/files/qmail/mailman/uwsgi.ini chmod +x /usr/local/bin/uwsgictl
Add it to your rc.local or init.d. Test as root:
# uwsgictl
Usage: /usr/local/bin/uwsgictl {start|stop|restart|reload|force-reload}
# uwsgictl start
Starting uWSGI Server[uWSGI] getting INI configuration from /usr/local/mailman/etc/uwsgi.ini
The log files for both UWSGI and Mailman Web are under ~/web/logs.
Setting up Fulltext search (Xapian)
To install both xapian-core and xapian-bindings in the virtual environment check the latest version number in the source site and pass it as an argument to the install script:
(mailman)$ wget https://raw.githubusercontent.com/notanumber/xapian-haystack/master/install_xapian.sh (mailman)$ sh install_xapian.sh 1.4.25
Install Xapian-Haystack:
pip install xapian-haystack
Rebuild the index (force the rebuild):
(mailman)$ PYTHONPATH=~/etc/ DJANGO_SETTINGS_MODULE=settings mailman-web rebuild_index WARNING: This will irreparably remove EVERYTHING from your search index in connection 'default'. Your choices after this are to restore from backups or rebuild via the `rebuild_index` command. Are you sure you wish to continue? [y/N] Y Removing all documents from your index because you said so. All documents removed. Indexing 11 emails
The following are already set in your ~/etc/settings.py file that you downloaded earlier:
# xapian (full text search)
HAYSTACK_CONNECTIONS = {
'default': {
'HAYSTACK_XAPIAN_LANGUAGE': 'en',
'ENGINE': 'xapian_backend.XapianEngine',
'PATH': "/usr/local/mailman/web/xapian_index"
},
}
You can change the english default language modyfing the HAYSTACK_XAPIAN_LANGUAGE variable. The list of available languages can be found here.
Then restart the server:
uwsgictl restart
Cronjob setup for Mailman Web
As the mailman user edit the crontab (crontab -e) and install the following cronjobs:
@hourly ID=mailman PYTHONPATH=/usr/local/mailman/etc/ DJANGO_SETTINGS_MODULE=settings /usr/local/mailman/bin/mailman-web runjobs hourly >/dev/null 2>&1 @daily ID=mailman PYTHONPATH=/usr/local/mailman/etc/ DJANGO_SETTINGS_MODULE=settings /usr/local/mailman/bin/mailman-web runjobs daily >/dev/null 2>&1 @weekly ID=mailman PYTHONPATH=/usr/local/mailman/etc/ DJANGO_SETTINGS_MODULE=settings /usr/local/mailman/bin/mailman-web runjobs weekly >/dev/null 2>&1 @monthly ID=mailman PYTHONPATH=/usr/local/mailman/etc/ DJANGO_SETTINGS_MODULE=settings /usr/local/mailman/bin/mailman-web runjobs monthly >/dev/null 2>&1 @yearly ID=mailman PYTHONPATH=/usr/local/mailman/etc/ DJANGO_SETTINGS_MODULE=settings /usr/local/mailman/bin/mailman-web runjobs yearly >/dev/null 2>&1 * * * * * ID=mailman PYTHONPATH=/usr/local/mailman/etc/ DJANGO_SETTINGS_MODULE=settings /usr/local/mailman/bin/mailman-web runjobs minutely >/dev/null 2>&1 2,17,32,47 * * * * ID=mailman PYTHONPATH=/usr/local/mailman/etc/ DJANGO_SETTINGS_MODULE=settings /usr/local/mailman/bin/mailman-web runjobs quarter_hourly >/dev/null 2>&1
Test:
(mailman)$ PYTHONPATH=~/etc/ DJANGO_SETTINGS_MODULE=settings mailman-web runjobs -l Job List: 11 jobs appname - jobname - when - help -------------------------------------------------------------------------------- django_extensions - cache_cleanup - daily - Cache (db) cleanup Job django_extensions - daily_cleanup - daily - Django Daily Cleanup Job hyperkitty - empty_threads - monthly - Remove empty threads hyperkitty - new_lists_from_mailman - hourly - Import new lists from Mailman hyperkitty - orphan_emails - daily - Reattach orphan emails hyperkitty - recent_threads_cache - daily - Refresh the recent threads cache hyperkitty - sync_mailman - daily - Sync user and list properties with Mailman hyperkitty - thread_order_depth - yearly - Compute thread order and depth for all threads hyperkitty - thread_starting_email - hourly - Find the starting email when it is missing hyperkitty - update_and_clean_index - monthly - Update the full-text index and clean old entries hyperkitty - update_index - hourly - Update the full-text index
The HyperKitty archiver
HyperKitty is an application providing a web interface to access Mailman archives, and interact with the lists. To connect HyperKitty with Mailman, these are the lines already set in your mailman.cfg that you downloaded earlier:
# For the HyperKitty archiver. [archiver.hyperkitty] class: mailman_hyperkitty.Archiver enable: yes configuration: /usr/local/mailman/etc/mailman-hyperkitty.cfg
Now create mailman-hyperkitty.cfg (downolad)
(mailman)$ cat > ~/etc/mailman-hyperkitty.cfg << __EOF__ # This is the mailman extension configuration file to enable HyperKitty as an # archiver. Remember to add the following lines in the mailman.cfg file: # # [archiver.hyperkitty] # class: mailman_hyperkitty.Archiver # enable: yes # configuration: /path/to/here/mailman-hyperkitty.cfg # [general] # This is your HyperKitty installation, preferably on the localhost. This # address will be used by Mailman to forward incoming emails to HyperKitty # for archiving. It does not need to be publicly available, in fact it's # better if it is not. # However, if your Mailman installation is accessed via HTTPS, the URL needs # to match your SSL certificate (e.g. https://lists.example.com/hyperkitty). base_url: http://lists.mydomain.tld/archives/ # The shared api_key, must be identical except for quoting to the value of # MAILMAN_ARCHIVER_KEY in HyperKitty's settings. api_key: xxxxxxxxxxxxxxxxxxx __EOF__
It is important that the api_key value matches the MAILMAN_ARCHIVER_KEY value inside settings.py.
Apache configuration
Here is an example of apache virtual host. mod_proxy must be enabled:
Define MMDIR /usr/local/mailman
Define MMDOMAIN lists.mydomain.tld
<VirtualHost *:443>
ServerName ${MMDOMAIN}
# Include SSL stuff
CustomLog ${LOGDIR}/${MMDOMAIN}.log combined
ErrorLog ${LOGDIR}/${MMDOMAIN}_error.log
Alias /static "${MMDIR}/web/static"
Alias /favicon.ico $MMDIR/web/static/hyperkitty/img/favicon.ico
<Directory "${MMDIR}/web/static">
Require all granted
</Directory>
<IfModule mod_rewrite.c>
RewriteEngine On
# redirects / calls to /mailman3
RewriteRule ^/$ https://${MMDOMAIN}/mailman3 [R=302,L]
</IfModule>
<IfModule mod_proxy.c>
SSLProxyEngine On
ProxyRequests Off
ProxyPreserveHost On
ProxyPass "/mailman3" "http://127.0.0.1:8000/mailman3"
ProxyPass "/archives" "http://127.0.0.1:8000/archives"
ProxyPass "/accounts" "http://127.0.0.1:8000/accounts"
ProxyPass "/admin" "http://127.0.0.1:8000/admin"
ProxyPass "/user-profile" "http://127.0.0.1:8000/user-profile"
ProxyPassMatch ^/static/ !
</IfModule>
</VirtualHost>
Once finished browse to https://lists.mydomain.org/mailman3 and login with the superuser credentials. Then confirm the superuser's email address and login again.
logrotate
Here is a logrotate file to rotate both Mailman and Mailman web files:
cat > /etc/logrotate.d/mailman << __EOF__
#mailman
/usr/local/mailman/var/logs/*.log {
missingok
sharedscripts
su mailman mailman
postrotate
# /usr/local/bin/mmctl reopen &>/dev/null || true # users with no systemd
cd /usr/local/mailman
sudo -u mailman /usr/local/mailman/bin/mailman -C /usr/local/mailman/etc/mailman.cfg reopen &>/dev/null || true
endscript
}
# mailman-web
/usr/local/mailman/web/logs/*.log {
hourly
missingok
notifempty
delaycompress
su mailman mailman
}
__EOF__
Adding domains
With the previous instructions all the lists belong to the same domain (lists.mydomain.tld in our example). What do you need to do if you want to create lists on other domains, say otherdomain.tld?
Create a Linux user and link the virtualdomain otherdomain.tld to that user:
useradd -d /home/username username mkdir -p /home/username chown -R username:users /home/username echo otherdomain.tld:username >> /var/qmail/control/virtualdomains
In this way qmail will seek the dot-qmail file which is responsible to handle the delivery in the user's home directory. Therefore we have to save there the instructions to call the Mailman's LMTP server:
echo "|/usr/local/mailman/qmail-lmtp 8024 1" > /home/username/.qmail-default chown username:users /home/username/.qmail-default
You may think that the same result could be achieved simply creating an alias /var/qmail/alias/.qmail-username-default but this method woudn't work, because qmail would pass Mailman the recipient address username-listname@otherdomain.tld instead of listname@otherdomain.tld and you'll get a "mailbox not found" reject.
As you know Django comes with a “sites” framework. It’s a hook for associating objects and functionalities to particular websites, and it’s a holding place for the domain names and “verbose” names of your Django-powered sites.You should have already created the lists.mydomain.tld site with SITE_ID=2 or whatever as SITE_ID. When you create your lists belonging to the newly created domain in the Postorius web panel, you'll have to choose lists.mydomain.tld as its "Web server".
Adding mailing lists to your main domain
You may be wondering if you can define a list like list@mydomain.tld, where mydomain.tld is a virtual domain with ordinary qmail/vpopmail users and with its own .qmail-default file. The answer is yes. Just create the dot-qmail file with the name that you want to assign to the list and call Mailman in the usual way.
For example, if you want to create a list mylist@mydomain.tld you can do as follows:
echo "|/usr/local/mailman/qmail-lmtp 8024 1" > ~vpopmail/domains/mydomain.tld/.qmail-mylist chomod 644 ~vpopmail/domains/mydomain.tld/.qmail-mylist chown vpopmail:vchkpw ~vpopmail/domains/mydomain.tld/.qmail-mylist
Known issues
Mailman webcrashes with "AttributeError: 'NoneType' object has no attribute 'thread'" as soon as I click on the "Reattach this conversation" button in theHyperKittyarchive. I opened a ticket here.- As already mentioned, the original
qmail-lmptscript doesn't work withMailman3becauseqmail-localsends bare LF for the end line, while theSMTPstandards require CRLF, so theSMTPconversation betweenqmailandMailmanends up with the error: "Line too long (see RFC5321 4.5.3.1.6)". The patchedqmail-lmtpfile that we are using here can have unpredictable results when binary files with \n and \r characters are sent, according to what a developer says in this conversation. Anyhow it works fine here in my server so far.
List owner instructions
If your users ask you to provide a manual for the list administrator you can suggest this video guide, which covers everything.
The manual for the list member is in the official guide here.


