Merge branch 'stage' into prod
This commit is contained in:
commit
13ebcc1cd5
4 changed files with 148 additions and 31 deletions
|
|
@ -12,7 +12,8 @@ import { Aside } from "@astrojs/starlight/components";
|
|||
This feature is completely optional. If you are eager to get finished then skip this page and maybe come back later.
|
||||
</Aside>
|
||||
|
||||
Quotas are size limits for users. You can make sure that users do not waste arbitrary amounts of disk space but are forced to clean up old emails every now and then.
|
||||
Quotas are size limits for users. You can make sure that users do not waste arbitrary amounts of disk space but are
|
||||
forced to clean up old emails every now and then.
|
||||
|
||||
The magic happens in two places:
|
||||
|
||||
|
|
@ -21,7 +22,8 @@ The magic happens in two places:
|
|||
|
||||
### Dovecot quota policy service
|
||||
|
||||
Let’s start with Dovecot. Find the file `/etc/dovecot/conf.d/90-quota.conf` and edit it. There are several `plugin {}` sections. Take one and make it look like:
|
||||
Let’s start with Dovecot. Find the file `/etc/dovecot/conf.d/90-quota.conf` and edit it. There are several `plugin {}`
|
||||
sections. Take one and make it look like:
|
||||
|
||||
```
|
||||
plugin {
|
||||
|
|
@ -34,9 +36,17 @@ plugin {
|
|||
}
|
||||
```
|
||||
|
||||
The first line defines that you want to calculate the used space in a user’s _maildir_. There are several [backends](https://doc.dovecot.org/configuration_manual/quota_plugin/) like that but the _[count](https://doc.dovecot.org/configuration_manual/quota/quota_count/#quota-backend-count)_ is the best choice in this context. (Previous guides used _maildir_ here.) The string “User quota” is just an arbitrary string that may be queried from a mail user agent.
|
||||
The first line defines that you want to calculate the used space in a user’s _maildir_. There are several
|
||||
[backends](https://doc.dovecot.org/configuration_manual/quota_plugin/) like that but the
|
||||
_[count](https://doc.dovecot.org/configuration_manual/quota/quota_count/#quota-backend-count)_ is the best choice in
|
||||
this context. (Previous guides used _maildir_ here.) The string “User quota” is just an arbitrary string that may be
|
||||
queried from a mail user agent.
|
||||
|
||||
The lines starting with “`quota_status_…`” set return values for the service that you will set up in a minute. It will tell Postfix that it will not interfere (_DUNNO_ – colloquial way to say “I don’t know”). And it will return a string with a return code 452 if the user is over quota. Codes starting with “4” mean temporary errors. It will tell the sending party that it is worth retrying at a later time. However if the user does not resolve the issue it will lead to a _bounce_ error email after three days.
|
||||
The lines starting with “`quota_status_…`” set return values for the service that you will set up in a minute. It will
|
||||
tell Postfix that it will not interfere (_DUNNO_ – colloquial way to say “I don’t know”). And it will return a string
|
||||
with a return code 452 if the user is over quota. Codes starting with “4” mean temporary errors. It will tell the
|
||||
sending party that it is worth retrying at a later time. However if the user does not resolve the issue it will lead to
|
||||
a _bounce_ error email after three days.
|
||||
|
||||
In the same file (_90-quota.conf_) add another section:
|
||||
|
||||
|
|
@ -49,22 +59,34 @@ service quota-status {
|
|||
}
|
||||
```
|
||||
|
||||
This creates a new [Dovecot service](https://doc.dovecot.org/configuration_manual/service_configuration/) responding to requests from other processes. You surely recognize that we put it into the jail that Postfix runs in (_/var/spool/postfix_), so that Postfix can access it.
|
||||
This creates a new [Dovecot service](https://doc.dovecot.org/configuration_manual/service_configuration/) responding to
|
||||
requests from other processes. You surely recognize that we put it into the jail that Postfix runs in
|
||||
(_/var/spool/postfix_), so that Postfix can access it.
|
||||
|
||||
Time to restart Dovecot:
|
||||
|
||||
```
|
||||
systemctl restart dovecot
|
||||
```
|
||||
Take a look at the /var/spool/postfix/private directory. If all went as intended you will find a socket file called `quota-status` there. Otherwise please check the `/var/log/mail.log` file for errors.
|
||||
|
||||
Take a look at the /var/spool/postfix/private directory. If all went as intended you will find a socket file called
|
||||
`quota-status` there. Otherwise please check the `/var/log/mail.log` file for errors.
|
||||
|
||||
### Postfix recipient restrictions
|
||||
|
||||
If we stopped here, then Dovecot would reject emails for users who have no space left. However Postfix would still happily receive new emails and attempt to forward them to Dovecot via LMTP. Dovecot however will deny that. It will then keep the email in its queue and retry for a while. In the end it will send a _bounce_ back to the sender telling them about the problem. So why is this bad?
|
||||
If we stopped here, then Dovecot would reject emails for users who have no space left. However Postfix would still
|
||||
happily receive new emails and attempt to forward them to Dovecot via LMTP. Dovecot however will deny that. It will then
|
||||
keep the email in its queue and retry for a while. In the end it will send a _bounce_ back to the sender telling them
|
||||
about the problem. So why is this bad?
|
||||
|
||||
1. The sender will assume that the email was delivered while it is stuck in the queue for up to three days.
|
||||
2. Spam emails use forged senders. So at the time that Postfix generates the _bounce email_ it will likely send it to an innocent person. This is called _backscatter_ and considered a mail server misconfiguration. Such a problem may get your mail server blacklisted. You don’t want that.
|
||||
2. Spam emails use forged senders. So at the time that Postfix generates the _bounce email_ it will likely send it to an
|
||||
innocent person. This is called _backscatter_ and considered a mail server misconfiguration. Such a problem may get
|
||||
your mail server blacklisted. You don’t want that.
|
||||
|
||||
So the next logical step is to make Postfix check whether a mailbox is over quota whenever a new email arrives. Let’s hook up into the “RCPT TO” phase of the SMTP dialog when a new email comes in. Postfix checks its _smtpd\_recipient\_restrictions_ configuration at this stage. Run this command in the shell:
|
||||
So the next logical step is to make Postfix check whether a mailbox is over quota whenever a new email arrives. Let’s
|
||||
hook up into the “RCPT TO” phase of the SMTP dialog when a new email comes in. Postfix checks its
|
||||
_smtpd_recipient_restrictions_ configuration at this stage. Run this command in the shell:
|
||||
|
||||
```
|
||||
postconf smtpd_recipient_restrictions=reject_unauth_destination, \
|
||||
|
|
@ -73,22 +95,26 @@ postconf smtpd_recipient_restrictions=reject_unauth_destination, \
|
|||
|
||||
This adds two checks:
|
||||
|
||||
1. `reject_unauth_destination` checks whether the mail server is the final destination for the recipient’s email address. This is pretty much the default behavior if you do not define any restrictions.
|
||||
2. `check_policy_service` connects to the socket file at `/var/spool/postfix/private/quota-status` that was put there by Dovecot. It will use it to ask Dovecot whether the user is over quota in which case the email would get rejected.
|
||||
1. `reject_unauth_destination` checks whether the mail server is the final destination for the recipient’s email
|
||||
address. This is pretty much the default behavior if you do not define any restrictions.
|
||||
2. `check_policy_service` connects to the socket file at `/var/spool/postfix/private/quota-status` that was put there by
|
||||
Dovecot. It will use it to ask Dovecot whether the user is over quota in which case the email would get rejected.
|
||||
|
||||
### Test it
|
||||
|
||||
If you are curious to see this working, then set John’s mailbox quota to 5 KB:
|
||||
|
||||
```sql
|
||||
# mysql mailserver
|
||||
# mariadb mailserver
|
||||
mysql> update virtual_users set quota=4000 where email='john@example.org';
|
||||
```
|
||||
|
||||
Send him a few emails using the ‘swaks’ tool:
|
||||
|
||||
```
|
||||
swaks --server localhost --to john@example.org
|
||||
```
|
||||
|
||||
After a few emails you will see the rejection message:
|
||||
|
||||
```
|
||||
|
|
@ -100,16 +126,23 @@ After a few emails you will see the rejection message:
|
|||
|
||||
These are things you should consider if quotas do not seem to work properly:
|
||||
|
||||
- Check if you have enabled “quota” in the “mail\_plugins” in the 10-mail.conf file.
|
||||
- Your users may complain that they have deleted many emails but are still over quota. Let them check if they actually emptied the _Trash_ folder. Of course emails in that folder also contribute to the disk space usage. Once the Trash folder is expunged the problem should be gone. You may also allow your users more space in the Trash folder. That’s explained in the [Dovecot documentation](https://doc.dovecot.org/configuration_manual/quota/#quota-rules).
|
||||
- If you directly remove files from a user’s Maildir instead of properly accessing the mailbox using IMAP then you will screw up the quota calculation. In that case let Dovecot recalculate the quota:
|
||||
- Check if you have enabled “quota” in the “mail_plugins” in the 10-mail.conf file.
|
||||
- Your users may complain that they have deleted many emails but are still over quota. Let them check if they actually
|
||||
emptied the _Trash_ folder. Of course emails in that folder also contribute to the disk space usage. Once the Trash
|
||||
folder is expunged the problem should be gone. You may also allow your users more space in the Trash folder. That’s
|
||||
explained in the [Dovecot documentation](https://doc.dovecot.org/configuration_manual/quota/#quota-rules).
|
||||
- If you directly remove files from a user’s Maildir instead of properly accessing the mailbox using IMAP then you will
|
||||
screw up the quota calculation. In that case let Dovecot recalculate the quota:
|
||||
`doveadm quota recalc -u john@example.org`
|
||||
|
||||
### Automatic warning emails
|
||||
|
||||
The last step is to inform the poor users if they accidentally went over quota. After all they do not necessarily recognize that on their own. Let’s do that by sending them an email with a warning. Yes, we will make sure that the email gets through even if the quota is reached.
|
||||
The last step is to inform the poor users if they accidentally went over quota. After all they do not necessarily
|
||||
recognize that on their own. Let’s do that by sending them an email with a warning. Yes, we will make sure that the
|
||||
email gets through even if the quota is reached.
|
||||
|
||||
Edit the `90-quota.conf` file again. Add this section to the file (derived from the [Dovecot documentation](https://doc.dovecot.org/configuration_manual/quota/#quota-warning-scripts)):
|
||||
Edit the `90-quota.conf` file again. Add this section to the file (derived from the
|
||||
[Dovecot documentation](https://doc.dovecot.org/configuration_manual/quota/#quota-warning-scripts)):
|
||||
|
||||
```
|
||||
plugin {
|
||||
|
|
@ -126,13 +159,17 @@ service quota-warning {
|
|||
}
|
||||
```
|
||||
|
||||
This section defines two automatic quota warnings. The first (quota\_warning) is triggered if the user reaches 95% of the quota. The second (quota\_warning2) at 80%. These lines follow this schema:
|
||||
This section defines two automatic quota warnings. The first (quota_warning) is triggered if the user reaches 95% of the
|
||||
quota. The second (quota_warning2) at 80%. These lines follow this schema:
|
||||
|
||||
- **Trigger** (e.g. “storage=95%”). The “%” sign needs to be used twice if you want to emit a literal percent sign. So this is not a typo.
|
||||
- **Trigger** (e.g. “storage=95%”). The “%” sign needs to be used twice if you want to emit a literal percent sign. So
|
||||
this is not a typo.
|
||||
- The **socket** you want to call in that case. Our socket is the “service quota-warning” that calls a shell script.
|
||||
- Additional **parameters** that are passed to the shell script in our case. They tell the script the percentage that has been reached (e.g. 95) and the address of the user who should get the warning.
|
||||
- Additional **parameters** that are passed to the shell script in our case. They tell the script the percentage that
|
||||
has been reached (e.g. 95) and the address of the user who should get the warning.
|
||||
|
||||
Apparently we need the script to run. So please create a new file at `/usr/local/bin/quota-warning.sh` and put these lines into it:
|
||||
Apparently we need the script to run. So please create a new file at `/usr/local/bin/quota-warning.sh` and put these
|
||||
lines into it:
|
||||
|
||||
```
|
||||
#!/bin/sh
|
||||
|
|
@ -153,8 +190,12 @@ Make this file executable:
|
|||
```
|
||||
chmod +x /usr/local/bin/quota-warning.sh
|
||||
```
|
||||
|
||||
Time to restart Dovecot again:
|
||||
|
||||
```
|
||||
systemctl restart dovecot
|
||||
```
|
||||
Dovecot’s quota limits can be configured in many ways. If you have special needs then give [their documentation](https://doc.dovecot.org/configuration_manual/quota/) a look.
|
||||
|
||||
Dovecot’s quota limits can be configured in many ways. If you have special needs then give
|
||||
[their documentation](https://doc.dovecot.org/configuration_manual/quota/) a look.
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ mysqldump mailserver > mailserver.sql
|
|||
Copy that file to the new server (using *scp*) and import it there:
|
||||
|
||||
```
|
||||
mysql mailserver < mailserver.sql
|
||||
mariadb mailserver < mailserver.sql
|
||||
```
|
||||
|
||||
Obviously any database changes on the old server from now on will have to be done on the new server as well until the
|
||||
|
|
@ -89,7 +89,7 @@ mysqldump roundcube > roundcube.sql
|
|||
Copy that file to the new server and import it:
|
||||
|
||||
```
|
||||
mysql roundcube < roundcube.sql
|
||||
mariadb roundcube < roundcube.sql
|
||||
```
|
||||
|
||||
One caveat though. To distinguish multiple mail servers Roundcube stores the server’s name in the mail_host column of
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
title: Catch-all addresses
|
||||
lastUpdated: 2025-11-01
|
||||
lastUpdated: 2025-11-02
|
||||
slug: ispmail-trxie/catch-all
|
||||
sidebar:
|
||||
order: 320
|
||||
|
|
@ -8,8 +8,77 @@ sidebar:
|
|||
|
||||
import { Aside } from "@astrojs/starlight/components";
|
||||
|
||||
<Aside type="tip" title="Coming soon">
|
||||
This page is currently rewritten. It will be online in a couple of days.
|
||||
<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/mysql-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/mysql-*.cf
|
||||
chmod u=rw,g=r,o= /etc/postfix/mysql-*.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/mysql-virtual-alias-maps.cf,mysql:/etc/postfix/mysql-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/mysql-email2email.cf
|
||||
```
|
||||
|
||||
The result should be the same address:
|
||||
|
||||
```
|
||||
john@example.org
|
||||
```
|
||||
|
||||
Now you are ready to add catch-all aliases.
|
||||
|
|
|
|||
|
|
@ -29,6 +29,13 @@ sed -i "s|MAILSERVER-PASSWORD-HERE|$PW_MAILSERVER|g" \
|
|||
# Restart the services
|
||||
systemctl restart postfix dovecot
|
||||
|
||||
# Update MariaDB user passwords
|
||||
mariadb <<EOF
|
||||
ALTER USER 'mailadmin'@'localhost' IDENTIFIED BY '${PW_MAILADMIN}';
|
||||
ALTER USER 'mailserver'@'127.0.0.1' IDENTIFIED BY '${PW_MAILSERVER}';
|
||||
FLUSH PRIVILEGES;
|
||||
EOF
|
||||
|
||||
# Print the passwords for us to write down
|
||||
echo "mailadmin password: $PW_MAILADMIN"
|
||||
echo "mailserver password: $PW_MAILSERVER"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue