2026年11月12日
2026年11月12日
Create a Mailing List with Postfix: aliases :include: and Mailman 3
This article is a localized edition of the Japanese original. Read the Japanese original
There are two main ways to create a mailing list with Postfix.
| Method | Best for | What it does |
|---|---|---|
:include: in /etc/aliases |
Forwarding to a small group, such as staff | Forwards mail sent to one address to everyone listed in a file |
| Integration with Mailman 3 | Membership-based mailing lists | Subscribe and unsubscribe, holding posts from non-members, notifications to the list owner, archives |
The steps in this article were tested through actual delivery with the Debian 13 packages of Postfix 3.10 and mailman3 3.3.10 (as of November 2026). Ubuntu 24.04 also has a package with the same name (mailman3 3.3.8).
Note that the older Mailman 2 (the newlist and add_members commands, mm_cfg.py) was written for Python 2 and is not included in current Debian and Ubuntu releases. Use Mailman 3 for new lists.
Prerequisites
- Postfix is running and can send and receive mail with the outside world
- The MX record of the domain you use for lists (for example
lists.example.com) points to this server - You work with root privileges
If you have not finished the basic Postfix setup, do that first.
Method 1: Create a forwarding list with /etc/aliases
Write the list members
Create a file with one member address per line.
# /etc/postfix/lists/staff
alice@example.com
bob@example.net
Register the alias
Add the following two lines to /etc/aliases. owner-staff is the address that receives delivery error notices.
# Append to /etc/aliases
staff: :include:/etc/postfix/lists/staff
owner-staff: root
newaliases
Mail sent to staff@(this server's domain) is now forwarded to everyone in the file. The member file is read on every delivery, so adding or removing members only requires editing the file (newaliases is needed only when you change /etc/aliases).
Check it
printf 'Subject: staff test\n\ntest\n' | sendmail staff@example.com
grep 'orig_to=<staff@' /var/log/mail.log | tail
If the log shows orig_to=<staff@…> and status=sent for each member, forwarding works.
With this method, anyone (including outsiders) who sends to this address reaches every member. There is no way to accept subscriptions and unsubscriptions or to stop posts from non-members. If you need that, use Method 2.
Method 2: Integrate with Mailman 3
Mailman 3 receives incoming mail from Postfix over LMTP (port 8024 by default) and hands delivery to members back to Postfix.
Step 1: Install
apt update
apt install mailman3
If you also want the web admin interface (Postorius) and archives (HyperKitty), install the mailman3-full package. The web interface needs its own web server and database setup, so this article covers command-line operation.
Step 2: Check the Mailman settings
The configuration file is /etc/mailman3/mailman.cfg. In the Debian package, the [mta] settings for Postfix integration are already in place.
[mta]
incoming: mailman.mta.postfix.LMTP
outgoing: mailman.mta.deliver.deliver
smtp_host: localhost
smtp_port: 25
lmtp_host: 127.0.0.1
lmtp_port: 8024
configuration: python:mailman.config.postfix
site_owner in the [mailman] section is still set to changeme@example.com, so change it to the administrator's address.
[mailman]
site_owner: postmaster@example.com
Then restart Mailman.
systemctl restart mailman3
systemctl status mailman3
Step 3: Change the Postfix settings
Every time a list is created, Mailman writes lookup tables for Postfix (postfix_lmtp and postfix_domains, each with a .db file) to /var/lib/mailman3/data/. Make Postfix read these tables so that mail for list addresses is handed to Mailman.
# Add the list domain to the domains this server receives for (append to the existing value)
postconf mydestination
postconf -e 'mydestination = $myhostname, localhost, lists.example.com'
# Use + as the address delimiter (Mailman uses it for bounce handling)
postconf -e 'recipient_delimiter = +'
# Hand mail for list addresses to Mailman (LMTP)
postconf -e 'transport_maps = hash:/var/lib/mailman3/data/postfix_lmtp'
# Add list addresses to the accepted recipients (appended to the default value)
postconf -e 'local_recipient_maps = proxy:unix:passwd.byname $alias_maps hash:/var/lib/mailman3/data/postfix_lmtp'
The mydestination example adds lists.example.com to an existing value. Check the current value with postconf mydestination and add to it without removing anything. If you already use transport_maps or local_recipient_maps, append to the existing values as well (the official Mailman documentation also says to add to existing settings).
The table files are created when you create a list in Step 4, so reload Postfix after creating the list.
Step 4: Create a list and add members
On Debian, run the mailman command as the list user.
# Create the list (-o sets the owner)
sudo -u list mailman create -o owner@example.com team@lists.example.com
# Confirm the Postfix table was created
postmap -q team@lists.example.com hash:/var/lib/mailman3/data/postfix_lmtp
# Make Postfix reload its configuration
postfix check && postfix reload
If postmap -q returns lmtp:[127.0.0.1]:8024, the table was created correctly. Creating a list also registers administrative addresses such as team-owner@, team-request@, team-join@ and team-leave@.
Add members from a file with one address per line (- for standard input).
printf 'alice@example.com\nbob@example.net\n' | sudo -u list mailman addmembers - team@lists.example.com
# List the members
sudo -u list mailman members team@lists.example.com
# List the mailing lists
sudo -u list mailman lists
Step 5: Post and check
Send mail from a member address to the list address. Use the logs to confirm the handoff to Mailman and the delivery to members.
grep 'to=<team@lists.example.com>' /var/log/mail.log | tail -n 3
tail -n 20 /var/log/mailman3/mailman.log
If the Postfix log shows relay=127.0.0.1[127.0.0.1]:8024 and status=sent, and the Mailman log shows post to team@lists.example.com from …, the message was delivered to the members.
With the default settings, posts like the following are held instead of delivered, and the owner (the address given with -o) is notified.
Mailman log (after HOLD:) |
Reason |
|---|---|
The message is not from a list member |
Post from an address that is not a member |
Message has implicit destination |
The list address is not in To or Cc (for example, sent as BCC) |
Approve or reject held messages and change detailed list settings in the web interface (Postorius in mailman3-full) or through the Mailman REST API.
Troubleshooting
| Symptom | What to check |
|---|---|
Mail to the list is rejected with User unknown |
Whether you added postfix_lmtp to local_recipient_maps, ran postfix reload after creating the list, and have the list domain in mydestination |
The Postfix log shows connect to 127.0.0.1[127.0.0.1]:8024: Connection refused |
Whether Mailman is running (systemctl status mailman3) |
| Posts to the list reach no one | Whether the Mailman log shows HOLD: |
postmap -q returns nothing |
The spelling of the list name and domain, and whether the address is in /var/lib/mailman3/data/postfix_lmtp |
Summary
- If you only need to forward to a small group,
:include:in/etc/aliasesis enough. Editing the member file takes effect immediately. - If you need subscriptions and posting restrictions, use Mailman 3 and integrate it by adding
/var/lib/mailman3/data/postfix_lmtptotransport_mapsandlocal_recipient_maps. - Mailman 2 commands such as
newlistare not available on current Debian and Ubuntu.
Related articles
- How to forward mail for a specific domain in Postfix (virtual_alias_maps)
- Postfix performance tuning
Questions about WordPress? The publisher of this site is based in Japan and replies in Japanese. Contact (Japanese)