feat: add quota-triggered per-user mailbox cleanup so get an always below-quota relay experience#927
feat: add quota-triggered per-user mailbox cleanup so get an always below-quota relay experience#927
Conversation
Inflate the Dovecot-visible quota to 140% of the configured max_mailbox_size so that Delta Chat clients (which warn at 80% of IMAP-reported quota) never show quota warnings. A quota_warning at 72% of the inflated limit triggers chatmail-quota-expire, which trims the mailbox to 80% of the configured limit. Existing over-quota mailboxes start receiving mail again immediately after deploy without any manual operator action needed.
|
|
||
| def parse_size_mb(limit): | ||
| """Parse a size string like ``500M`` or ``2G`` and return megabytes.""" | ||
| value = limit.strip().upper().rstrip("B") |
There was a problem hiding this comment.
I suggest using .removesuffix("B") here instead of rstrip since MBB is not a valid unit name.
removesuffix was added in Python 3.9 which is already EOL so I suppose we're not trying to support old versions.
There was a problem hiding this comment.
| value = limit.strip().upper().rstrip("B") | |
| value = limit.strip().upper().removesuffix("B") |
| # Trigger when usage reaches the configured max_mailbox_size | ||
| # (72% of inflated = ~100% of configured), then expire oldest | ||
| # messages down to 80% of the configured max_mailbox_size. | ||
| quota_warning = storage=72%% quota-warning {{ config.max_mailbox_size_mb * 80 // 100 }} {{ config.mailboxes_dir }}/%u |
There was a problem hiding this comment.
I guess 140 (above, in quota_rule) is chosen arbitrarily to be above 100 / 0.8 = 125. And 72% is 100 / 140. But now that you have inflated actual quota to 140 * max_mailbox_size, you can set target_mb to max_mailbox_size_mb instead of 0.8 of max_mailbox_size_mb.
Currently you have both inflated the quota to the 140% of what the user configured and trim the mailbox to 80% of what the user configured. Should it be one or the other? Otherwise quota is 140 MB, but you truncate to 80 MB which is 60% of actual quota.
I think if user configured max_mailbox_size_mb, this should be the quota, not 140% of what the config says. Admin configured 1 GB, it should allow 1 GB and not 400 MB more.
| # Inflate the dovecot-visible quota so that Delta Chat clients | ||
| # (which warn at 80% of the IMAP-reported limit) never see | ||
| # quota warnings -- expire kicks in well before that point. | ||
| quota_rule = *:storage={{ config.max_mailbox_size_mb * 140 // 100 }}M |
There was a problem hiding this comment.
tl;dr for my comment below, i think it is wrong to configure the quota not to the value from the config, and it seems to have already resulted in a mistake
There was a problem hiding this comment.
Dovecot allow the last delivered mail to go over quota already with https://doc.dovecot.org/2.3/configuration_manual/quota/#quota-grace You only need quota_grace that is a size of the largest accepted message size. Can maybe set it to multiple of max message size or so, in case the script takes time to remove messages and multiple messages arrive before the script finishes.
So there is no need to set the quota over 100%. It will also look weird in connectivity view that you set it to 100 MB and 140 MB show up in Delta Chat.
Delivered message should make the mailbox over quota, at which point it can trigger the script and bring the mailbox to 80%, it is ok to trigger only on over quota.
There was a problem hiding this comment.
tl;dr for my comment below, i think it is wrong to configure the quota not to the value from the config, and it seems to have already resulted in a mistake
from the template chatmail.ini docs:
# maximum mailbox size of a chatmail address
max_mailbox_size = 500M
I consider dovecot quota to be an implementation detail, and there is no promise here that this goes directly to dovecot config. Cmdeploy relays are using dovecot in a particular way, and this PR uses a threshold-activated quota_expire action, to ensure that max_mailboxsize is the limit of what is used per mailbox. In the getting-started and setup docs we basically don't mention the word "quota" at all.
There was a problem hiding this comment.
I consider dovecot quota to be an implementation detail, and there is no promise here that this goes directly to dovecot config.
It goes to the connectivity view.
In the current state of the PR if you set mailbox size to 500 M, in the connectivity view user will see 700 M limit, the script gets triggered at 504 MB and brings the mailbox down to 400 MB usage.
|
I'd really rather have a single line explaining where 140% comes from instead of the list of "benefits" repeating the commit changes and citing the changelog. |
If we pass through the chatmil.ini Example:
So 140% could be slightly lower but the actual important bit is when quota-expire kicks in and it should be the |
| """ | ||
| mbox = Path(mailbox_dir) | ||
| messages = scan_mailbox_messages(mbox) | ||
| total_size = sum(m.size for m in messages) |
There was a problem hiding this comment.
This is the wrong size for quota calculation. In get_file_entry the size is st_size from stat call, just the file size. But for quota Dovecot uses the size stored in the filename:
https://doc.dovecot.org/2.3/configuration_manual/zlib_plugin/#maildir-mbox-format
We use zlib plugin here:
By just looking at the file sizes you underestimate quota usage, likely by more than 25% because of ASCII armoring.
| (mbox / "maildirsize").unlink(missing_ok=True) | ||
| cache = mbox / "dovecot.index.cache" | ||
| try: | ||
| cache_bytes = cache.stat().st_size |
There was a problem hiding this comment.
And adding to my comment about S= parameter in the filename, this should likely not be counted. I think it does not contribute to quota. For reference there is https://github.com/dovecot/core/blob/2.3.21.1/src/plugins/quota/quota-maildir.c, have not read it thoroughly but i think dovecot only counts S= for maildir, and also writes maildirsize so there is no need to sum things up manually just to check how the quota is doing.
Also need to unlink maildirsize after unlinking the files directly from the maildir, otherwise dovecot will keep adding to outdated quota and user will get over quota and a warning in Delta Chat: https://doc.dovecot.org/2.3/configuration_manual/quota/quota_maildir/
|
So the goal is not to just avoid getting over quota, but avoiding the warning that triggers at 80%, and end goal is that 60% (from #927 (comment)) is below the triggering threshold and triggering threshold is below 80%. I think it would be better to have actual quota at There is indeed a problem of already over quota users because Here is how maildirsize exampleFirst line is the limit ( |
|
Replaced by #929 :) |
Inflate the Dovecot-visible quota to 140% of the chatmail-ini configured max_mailbox_size so that Delta Chat clients (which warn at 80% of IMAP-reported quota) never show quota warnings. A quota_warning at 72% of the inflated limit triggers chatmail-quota-expire, which trims the mailbox to 80% of the configured limit. The PR provides the following benefits: