---
title: Catch-all addresses
lastUpdated: 2025-11-02
slug: ispmail-trixie/catch-all
sidebar:
  order: 320
---

import { Aside } from "@astrojs/starlight/components";

<Aside type="tip" title="Optional feature">
  This page is entirely optional. Skip it if you are not interested in catching all emails in a domain that otherwise
  have no alias or mailbox.
</Aside>

As explained earlier in the tutorial there is way to forward all undefined email addresses in a domain to a certain
destination email address. This is called a _catch-all_ alias. Those aliases catch all emails for a domain if there is
no specific _virtual user_ or _virtual alias_ for that email address. The drawback is that you will get more spam
because spammers will send their stuff to any address of your domain. Or perhaps a sender mixed up the proper spelling
of a recipient but the mail server will forward the email instead of rejecting it for a good reason.

You still want to use catch-all addresses? Well, okay. Let’s do it then. A catchall alias looks like “@example.org” and
forwards email for the whole domain to other addresses. We have created the `john@example.org` user and would like to
forward all other email on the domain to `kerstin@example.com`. So we would add a catchall alias like:

| source         | destination           |
| -------------- | --------------------- |
| `@example.org` | `kerstin@example.com` |

But there is a small catch. Postfix will apply the aliases (_virtual_alias_maps_) before delivering an email. So the
catch-all alias will "steal" all emails. But we can add this to the aliases table to prevent that:

| email                  | destination            |
| ---------------------- | ---------------------- |
| `@example.org`         | `kerstin@example.com`  |
| **`john@example.org`** | **`john@example.org`** |

Postfix will consider more specific aliases first. And `john@example.org` is more specific than `@example.org`. Consider
that someone is trying to reach `john@example.org`'s mailbox. So to make a mixture of catch-all addresses and specific
addresses work, we need this little trickery.

Postfix will lookup all these mappings for each of:

- john@example.org (most specific)
- @example.org (catchall – least specific)

This is outlined in the [virtual(5) man page](http://www.postfix.org/virtual.5.html) in the *TABLE SEARCH
ORDER* section.

We do not want to add that “more specific” entry for each email address manually. Fortunately we can easily automate
that. For that “john-to-himself” mapping you need to create another “.cf” file `/etc/postfix/mysql-email2email.cf`:

```sh title="Run this on your server"
# Create the john-to-himself mapping
cat > /etc/postfix/mariadb-email2email.cf << EOF
user = mailserver
password = MAILSERVER-PASSWORD-HERE
hosts = 127.0.0.1
dbname = mailserver
query = SELECT email FROM virtual_users WHERE email='%s'
EOF

# Fix the permissions of that file
chgrp postfix /etc/postfix/mariadb-*.cf
chmod u=rw,g=r,o= /etc/postfix/mariadb-*.cf

# Add the new mapping to the virtual_alias_maps
# (The order is not important. Postfix will check all mapping files.)
postconf virtual_alias_maps=mysql:/etc/postfix/mariadb-virtual-alias-maps.cf,mysql:/etc/postfix/mariadb-email2email.cf
```

Check that you get John’s email address back when you ask Postfix if there are any aliases for him:

```sh title="Run this on your server"
postmap -q john@example.org mysql:/etc/postfix/mariadb-email2email.cf
```

The result should be the same address:

```
john@example.org
```

Now you are ready to add catch-all aliases.
