Page of
Mailman 3 Setup Using Ubuntu Bionic
Created on 2018-12-20
Last Updated on 2020-06-16
If this guide needs editing, contact Kelly Close at LRE Water kelly.close@lrewater.com
NOTE 6/16/2020 - I set up another Ubuntu 18.04 Mailman3 system today following this guide which is now 1-1/2 years old. It still works! I tried to improve or clarify things that caught me up but after several re-starts it’s done and working, so I’m confident these instructions work. There are however some really delicate steps that need to be followed to the letter, in sequence and syntax. I strongly recommend making regular images of your system in progress if you are able, so you can roll back to the last working version if things get out of line, just like back in the 90’s when you would save your game after achieving challenging milestones so you didn’t have to start over next time you died! In fact, setting up this server really was a lot like playing an old game of Legend of Zelda. “It’s dangerous to go alone! Take this...”
Table of Contents
Server Credentials Quick Reference 3
Setting Up the New Server - UBUNTU 18.04 4
Set the “Hosts” and “Hostname” 4
Installing the LAMP stack (Linux, Apache, MySQL and PHP) 5
MySQL (users planning to use PostgreSQL as the back end may opt to skip this) 6
Installing and Securing phpMyAdmin (only relevant if installing MySQL) 8
Installing PostgreSQL (for using PostgreSQL on the back end of Mailman 3) 9
Configure the pg_hba.conf file 10
Install Additional PostgreSQL Libraries 11
Adding Ubuntu User Roles and Groups (best practices) 11
Changing PHP Maximum Upload Limits To Enable Larger Uploads 11
Setting the Time Zone on New Servers 12
Setting up the DNS records for Postfix 12
Installing and Configuring Postfix: 12
UPDATE 6/16/2020 - Amazon Web Services (AWS) EC2 and Postfix 12
Recommended responses to prompts: 13
Tweak the Postfix Configuration 13
Map Mail Addresses to Linux Accounts 14
Setting the Environment and install and configure the mail client 14
Initialize the Maildir and Test the Client 15
Managing Mail with the Client 16
Sending Mail with the Client 16
Install Ubuntu mailman3-full package 18
Follow README instructions for final configuration steps 19
README.Debian in /usr/share/mailman3/ 19
README.Debian in /usr/share/mailman3-web/ 20
Set up matching keys to authorize Hyperkitty 21
A final check of configurations for SSL setups 21
First Set Global Server Name Directive 22
Go to yourdomain.org/mailman3/postorius/lists 24
Add a redirect from the root of your URL to the lists path 24
Hyperkitty Archiver permissions and troubleshooting 24
Keys and Passwords (Updated 2020-6-20) 24
Base URL setting (added 2020-6-20) 25
Non-https port 80 listener for Hyperkitty (added 2020-6-20) 25
UPDATE 6/16/2020 for hanging browser on login 25
Added 6/16/2020 - Mail Security and Deliverability Configurations 26
Configuring messages with Templates 27
Copying lists over from a different Mailman3 server (PostgreSQL specific) 28
Extra step to apply a new domain name to your migrated lists 29
(make a copy of this document and fill in your own information as you go for later reference)
Host IP Address _____________________
Additional Hosting Notes _____________________________________________________
Apache URL ______________________________
mailman listens by default on yourdomain.xxx/mailman3
Sudo SSH login user: ____________ password: ________________________
MySQL Root login user: root_______ password: ________________________
Mailman admin login user: ____________ password: ________________________
PostgreSQL super user user: _postgres____ password: ________________________
Postgresql port: 5432
Postgresql Mailman user user: _mailman3___ password: ________________________
Postorius super user user: mailman3web password: ________________________
You should see “Apache Full” in the list printed.
You should see “80,443/tcp” listed for the ports
<IfModule mod_dir.c>
DirectoryIndex index.php index.html index.cgi index.pl index.xhtml index.htm
</IfModule>
<?php
phpinfo();
?>
You should see that the root user authenticates using the auth_socket plugin
You can check that the authentication method has changed by retyping:
mysql > SELECT user,authentication_string,plugin,host FROM mysql.user;
NOTE: Once you have password authentication enabled, you will use a different command to access the MySQL shell:
sudo ln -s /usr/share/phpmyadmin /var/www/html/phpmyadmin
(note the above command is lower case letter ‘el’ and n (not a capital i)
CREATE EXTENSION adminpack;
# Your Connection
host all all 98.76.54.321/32 md5
host all postgres 0.0.0.0/0 md5
Uncomment and modify the the listen_addresses line to be:
listen_addresses = '*'
You will also need to add support for Python (Mailman3 requires that) and possibly other thing. There are lots of PostgreSQL add-in packages and libraries but the two additional ones I always add are for PHP and PostGIS.
Enable Python libraries for PostgreSQL (Required by Mailman3)
Enable PHP libraries for PostgreSQL (optional)
Enable the postGIS libraries for PG 10
(at this point, best practices dictate logging out of the server, and back in as a non-root user in the sudo group, created above)
Will be using Postfix on this server - to properly configure Postfix, you will need a Fully Qualified Domain Name (https://en.wikipedia.org/wiki/Fully_qualified_domain_name) pointed at the server (A records for @ and www) - for help with this you may need to contact your Domain host.
Source: https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-postfix-on-ubuntu-18-04 Postfix is a popular open-source Mail Transfer Agent (MTA) that can be used to route and deliver email on a Linux system. It is estimated that around 25% of public mail servers on the internet run Postfix. In order to properly configure Postfix, you will need a Fully Qualified Domain Name pointed at your Ubuntu 18.04 server. You can find help on setting up your domain name with DigitalOcean by following this guide. If you plan on accepting mail, you will need to make sure you have an MX record pointing to your mail server as well. For the purposes of this tutorial, we will assume that you are configuring a host that has the FQDN of mail.example.com.
Run the following commands to install (priority set to force more prompts at setup - this is very important!)
To return and re-adjust these settings type:
Set the home_mailbox variable to Maildir/ which will create a directory within the user's home directory (user specified above). The postconf command is used to set the configuration setting by typing:
Set the location of the virtual_alias_maps table:
The virtual alias map table allows you to list any other addresses that you wish to accept email for and map them to the primary address (set above).
For example, if you would like to accept email at contact@example.com and admin@example.com and would like to have those emails delivered to the ubuntu Linux user, you could set up your file like this:
contact@example.com ubuntu
admin@example.com ubuntu
Save and close the file. Apply the mapping by typing:
Restart Postfix to be sure that all of our changes have been applied:
If you are running the UFW firewall, as configured in the initial server setup guide, we'll have to allow an exception for Postfix.
To add the variable to these files, type:
To read the variable into current session, source the /etc/profile.d/mail.sh file:
To install the s-nail package, type:
Adjust a few settings. Open the /etc/s-nail.rc file in your editor:
Search the file for “set emptystart” (CTRL-W in nano to search), and add the following options below it:
set emptystart
set folder=Maildir
set record=+sent
This will allow the client to open even with an empty inbox. It will also set the Maildir directory to the internal folder variable and then use this to create a sent mbox file within that, for storing sent mail. Save and close the file when you are finished (CTRL-O, CTRL-X).
Send the email by piping a string to the s-nail command. Adjust the command to mark your Linux user as the recipient:
You may get the following response:
Can't canonicalize "/home/ubuntu/Maildir"
This is normal and may only appear when sending this first message. We can check to make sure the directory was created by looking for our ~/Maildir directory:
You should see the directory structure has been created and that a new message file is in the ~/Maildir/new directory:
/home/sammy/Maildir/:
cur new tmp
/home/sammy/Maildir/cur:
/home/sammy/Maildir/new:
1463177269.Vfd01I40e4dM691221.mail.example.com
/home/sammy/Maildir/tmp:
It looks like our mail has been delivered!
Use the client to check your mail:
You should see your new message waiting:
s-nail version v14.8.6. Type ? for help.
"/home/sammy/Maildir": 1 message 1 new
>N 1 sammy@example.com Wed Dec 31 19:00 14/369 init
Hitting ENTER should display your message:
[-- Message 1 -- 14 lines, 369 bytes --]:
From sammy@example.com Wed Dec 31 19:00:00 1969
Date: Fri, 13 May 2016 18:07:49 -0400
To: sammy@example.com
Subject: init
Message-Id: <20160513220749.A278F228D9@mail.example.com>
From: sammy@example.com
init
You can get back to your message list by typing h, and then ENTER:
s-nail version v14.8.6. Type ? for help.
"/home/sammy/Maildir": 1 message 1 new
>R 1 sammy@example.com Wed Dec 31 19:00 14/369 init
Since this message isn't very useful, we can delete it with d, and then ENTER:
Quit to get back to the terminal by typing q and then ENTER:
You can test sending mail by typing a message in a text editor:
Enter some text you'd like to email:
Hello,
This is a test. Please confirm receipt!
Using the cat command, we can pipe the message to the s-nail process. This will send the message as your Linux user by default. You can adjust the "From" field with the -r flag if you want to modify that value to something else:
The options above are:
You can view your sent messages within your s-nail client. Start the interactive client again by typing:
Afterwards, view your sent messages by typing:
You can manage sent mail using the same commands you use for incoming mail.
NOTE - This is a good time to back up the server in case you want to roll back to here!
This package installed the mailman3 core, mailman3-web interface, all needed dependencies including python (not the python library for PostgreSQL previously installed above however) and set up most of the configuration needed to integrate hyperkitty and postorious.
This guide assumes use of PostgreSQL for the database back end to Mailman 3
NOTE: Setting the priority in the command below to Low is ESSENTIAL, otherwise all prompts are not provided during install and it becomes a config file nightmare to get things working! Below are recommended replies to prompts (the ones I used that worked!) - note than many of these prompts appear to be asked multiple times but the text on the prompt pages are subtly different, some for mailman3, some for postorius, some for hyperkitty.
Be careful and be consistent. If you can make it through this part cleanly, it’s pretty clear sailing but one little typo here is hard to recover from. Also note, the prompts don’t necessarily show up in the order below, as they repeat for the different components.
(Save your image before proceeding if possible!)
To re-configure later use sudo dpkg-reconfigure mailman3 (select NOT to reinstall db unless that process was unsuccessful the first time through)
The Mailman 3 deployment folder on Ubuntu Bionic is /etc/mailman3/...
NOTE: the config files live here
The Django-project folder is /usr/share/mailman3-web
NOTE: the settings_local.py file here is a symboloic link to mailman3-web.py in the deployment folder, so all configuring can be done from the Mailman 3 deployment folder!
The mailman3-full packages drops README files into /usr/share/doc/mailman3 and mailman3-web. These describe additional configuration steps to enable the Mailman3 setup. Relevant excerpts are included below for easier reference.
# Mailman related settings
owner_request_special = no
transport_maps = hash:/var/lib/mailman3/data/postfix_lmtp
(note the following MUST be on all one line in the .cf file - do not include this note)
local_recipient_maps = proxy:unix:passwd.byname $alias_maps hash:/var/lib/mailman3/data/postfix_lmtp
(note the following MUST be on all one line in the .cf file - do not include this note)
relay_domains = ${{$compatibility_level} < {2} ? {$mydestination} : {}} hash:/var/lib/mailman3/data/postfix_domains
Your section of code will look something like this, 4 lines:
At this point, verify that the postfix lookup tables (aka hash or alias files) were created. Look in the folder /var/lib/mailman3/data/ and verify the hash (aka alias) files are there. You should see:
If there are no files in that folder then something is probably wrong with the lines of code just added to the postfix main.cf file - verify those first. And then to fix the issue type:
This should create the 4 needed files in /var/lib/mailman3/data/.
NOTE: The following was already done when installing on 6/16/202
Verify these lines are present at the bottom of the mailman.cfg file:
[archiver.hyperkitty]
class: mailman_hyperkitty.Archiver
enable: yes
configuration: /etc/mailman3/mailman-hyperkitty.cfg
NOTE: The following was already done when installing on 6/16/2020
/etc/mailman3/mailman-web.py (set the ‘SECRET_KEY’ - include single quotes around the key)
If you are using a system configured with https:// (SSL certificates) you may run into HyperKitty permissions when it tries to archive messages. Here is a list of configuration checks to review that will save you some time up front. There are more details on how to troubleshoot HyperKitty permission errors in a later section in this doc.
mailman-hyperkitty.cfg:
[general]
base_url: https://lists.mailman3.org/archives
api_key: xxx
settings_local.py:
MAILMAN_ARCHIVER_KEY = 'xxx'
ALLOWED_HOSTS = ['localhost',
'127.0.0.1',
'104.239.228.201',
] (Or set ALLOWED_HOSTS to * but being explicit is more secure)
MAILMAN_ARCHIVER_FROM = ('127.0.0.1',
'::1',
'::ffff:127.0.0.1',
'104.239.228.201',
)
ACCOUNT_DEFAULT_HTTP_PROTOCOL = 'https'
Can use “Let’s Encrypt” to install a free SSL Certificate on the server - follow the Digital Ocean guide here: https://www.digitalocean.com/community/tutorials/how-to-secure-apache-with-let-s-encrypt-on-ubuntu-18-04
NOTE: This guide does NOT use a virtual apache host setup; using the default apache setup is appropriate if the server will only be used for a single Mailman 3 site. To accomplish this, we needed to create a global server name directive (below) to eliminate the apache warning “Could not reliably determine the server’s fully qualified domain name”. (Error can be seen or checked that it’s gone by running sudo apache2ctl configtest).
First, add the repository: sudo add-apt-repository ppa:certbot/certbot
Then install Certbot's Apache package with apt: sudo apt install python-certbot-apache
Certbot is now ready to use. Be sure your domain has had time to propagate before configuring.
SSL Cert Configuration process:
Note the example below associates the SSL with both the www form and non www form of the URL. You can include as many subdomains as you want.
sudo certbot --apache -d xxxxxxxxxxx.xxx -d www.xxxxxxxxxxxx.xxx
Enter email address (used for urgent renewal and security notices) (Enter 'c' to
cancel): yourprojectemail@domain.xxx
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf. You must
agree in order to register with the ACME server at
https://acme-v02.api.letsencrypt.org/directory
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(A)gree/(C)ancel: A
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Would you be willing to share your email address with the Electronic Frontier
Foundation, a founding partner of the Let's Encrypt project and the non-profit
organization that develops Certbot? We'd like to send you email about our work
encrypting the web, EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: N
Obtaining a new certificate
.....stuff....
Which virtual host would you like to choose?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: 000-default.conf | | | Enabled
2: 000-default-le-ssl.conf | udfcd-lists.org | HTTPS | Enabled
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: No redirect - Make no further changes to the webserver configuration.
2: Redirect - Make all requests redirect to secure HTTPS access...
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
...final confirmation stuff will print out on the screen, with info on how to test the certificate
There are more sophisticated ways to do this but this is a quick way to make sure users that try to go to your domain yourdomain.com end up at the lists. Mailman 3 listens on the mailman3 subfolder and redirects on its own to yourdomain.org/mailman3/postorius/lists. This redirects from the root in a way that (in my experience) all browsers support without complaint.
The root of your web folder on your server (/var/www/html/ on Ubununtu) will have an index.html file in it that comes with apache. Copy that to a backup (sudo cp index.html index_apache_backup.html) and replace it with one that has only the content shown below.
sudo nano index.html (to open the file - then hold down CTRL-K to delete all existing content)
Type in the content:
<head>
<meta http-equiv="refresh" content="0; URL='https://yourdomain.org/mailman3'" />
</head>
CTRL-O (to save) CTRL-X (to exit)
There are a number of keys and passwords in the 3 configuration files found in the deployment folder:
mailman-hyperkitty.cfg
api_key = xxx
mailman-web.py
SECRET_KEY = ‘aaaaaa’
MAILMAN_REST_API_PASS = ‘bbbbbb’
MAILMAN_ARCHIVER_KEY = ‘xxx’
DATABASES = .... ‘PASSWORD’ (for mailman3web database user): ‘yyy’
mailman.cfg
admin_pass: bbbbbb
url: postgres://mailman3:zzz@localhost/mailman3 (mailman3 database user)
Most of these populate on their own correctly during the setup steps but you will probably need to set the xxx passwords, or at least one of them (copy from the other file if it’s there in one file and not the other, or set your own in both places). It is crucial these match or your messages will not archive! You will see a HyperKitty Authorization error in /var/log/mailman3/mailman.log if these don’t match.
Using an SSL certificate means you are also using Virtual Hosts. Using certbot as described in this guide sets all that up for you but mailman3 needs a little more help to navigate.
In the
base_url: http://udfcd-lists.org/mailman3/hyperkitty/
#base_url: http://localhost/mailman3/hyperkitty/
If the 403 Forbidden error still persists AFTER making sure the archiver keys match and the base url is set to the actual domain and the server public ip is in the MAIL_FROM variable, then you probably need a “non-https port 80 listener” to let the local conversations with hyperkitty happen.
Add the following to the top of the file /etc/apache2/sites-available/000-default.conf
<VirtualHost 127.0.0.1:80 [::1]:80>
# non-https port 80 listener for localhost so hyperkitty can archive
ServerName localhost
Include conf-available/mailman3.conf
</VirtualHost>
After saving the file and exiting, reload apache2.
The 4 lines that you added to the postfix main.cf file are critical to success. If you reach the end of this setup and cannot log into your new Mailman website (if trying to log in results in the browser hanging and eventually going to a Server Error 500 page) check your logs with this command to see if the “hash tables” were created:
sudo tail /var/log/mail.log
If you see a line saying something like “error: open database /var/lib/mailman3/data/postfix_lmtp.db: No such file or directory” then your hash tables did not get created. Verify the 4 lines below in your /etc/postfix/main.cf file and fix if necessary. REstart postfix. Then follow these steps to fix the rest of the problem:
Create the hash tables manually: sudo -u list mailman aliases
(note that as of 2020-6-16 these hash files did not automatically get created, even with the correct lines of code in the Postfix config file so this manual step was required regardless)
To improve the chances that messages sent from the server will make it past people’s spam filters, configure some additional mail server protocols.
Create the following TXT record in the domains DNS records. This allows receiving mail servers to verify that the mssage really came from the udfcd-lists.org server (and wasn’t spoofed). Almost all receiving mail services look for this now, and without this record messages from this mail server will get caught by spam filters routinely.
Note the IP address shown below should be a backwards version of the ip address for the Mailman3 server (the place that udfcd-lists.org is pointing to in the DNS A record).
191.179.152.5.in-addr.arpa.udfcd-lists.org 14400 IN TXT yourdomain.com
Create the following TXT records in the udfcd-lists.org DNS records. This is another common filter applied by receiving mail services - without this record messages from this mail server will get caught by spam filters routinely.
Note the IP address shown below should match the ip address for the Mailman3 server (the place that udfcd-lists.org is pointing to in the DNS A record).
Install and configure DKIM on the Ubuntu server - great walkthru here that includes special instructions for Ubuntu 18: https://www.linuxbabe.com/mail-server/setting-up-dkim-and-spf
This also involves putting a public key (paired with a private key on the server) into a DNS record: (note - remember the semi-colon at the end of the key!
This has not yet been configured. Use this guide if it should be:
Text files can be provided to the Mailman3 system and tied to template settings so that content is automatically appended to messages. Templates can also be used to define content in auto generated messages such as welcome messages.
Official documentation:
https://docs.mailman3.org/projects/mailman/en/latest/src/mailman/rest/docs/templates.html
Excerpt from docs: The naming scheme for templates includes colon-separated sections following the form <context>:<recipient>:<type>:<name> where context would be “domain” or “list”, <recipient> would be “admin”, “user”, or “member”, and <type> can be a number of different things like “footer”. All template names used internally by Mailman are given in the docs linked above.
Key information for Ubuntu 18.04:
The default list templates live here, and affect all lists:
usr/lib/python3/dist-packages/mailman/templates/en/
Custom templates by list live here:
(note /var/lib/mailman3 is the “var_dir” variable set in /etc/mailman3/mailman.cfg)
/var/lib/mailman3/templates/lists
Subfolders under this folder match specific lists and within each list specific folder are .txt files. These files are named using the scheme above indicating how they are applied.
Database records tell Mailman which template .txt files go with which list. The table public.template stores these records.
In the version of Postorius installed with mailman3-full as of 2020-6-16 these must be added manually:
(Note - these records *should* be added automatically once they have been added on the file system but my experience as of 2020-6-16 was that they were not. I added the records to the database table in PostgreSQL (I use pgAdmin IV to interact with the db) and then the overrides worked.)
It’s actually super easy to migrate all your lists from one Mailman3 server to another. You can also move the lists over to a different server that uses a different domain with an extra step (note: I have seen a reference to there being a python script included with the mailman install that will rename all lists to a new domain but I couldn’t find it - add a comment here if you know where that is!
You will need to use a PostgreSQL SQL window to apply these changes from within PostgreSQL. Ideally you will have pgAdmin installed and be able to do this through the GUI but it can be done at the pgsql command line too:
Tables in mailman3 that reference the domain need to be updated:
For each of these, update the appropriate fields using search/replace.
EXAMPLE:
UPDATE member SET list_id=replace(list_id,’udfcd-lists’,’mhfd-lists’);
Tables in mailman3web that reference the domain need to be updated:
For each of these update the appropriate fields using search/replace.
EXAMPLE:
UPDATE member SET list_id=replace(list_id,’udfcd-lists’,’mhfd-lists’);