raise imaplib._MAXLINE + broaden filter search

Live poll had been silently dying every 30s with
  "Fehler beim Abrufen von Ordner 'INBOX' — got more than 1000000 bytes"
Root cause: Python's imaplib hard-caps a single response at 1 MB. With
~150k UIDs in INBOX, "UID SEARCH ALL" returns a longer line than that,
imaplib throws, get_all_uids() returns [], the poll reports "0 Mail(s)
im Ordner, 0 Treffer" and nothing gets sorted. Bump _MAXLINE to 100 MB
(covers mailboxes with millions of mails).

Filter search haystack now also includes the German condition/action
labels ("am (exakt)", "ab / nach", "verschieben in Ordner", …) and a
"stop" token, so the user can spot mis-typed date rules by typing
"am" and see any on_date rules rather than having to know the
internal enum names.

Also audited every rule via SSH: no on_date/date-exact rules exist —
all 32 rules use `date after '2026-01-01'` correctly. cps datensysteme
still has its known duplicate conditions (harmless).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-17 18:59:19 +02:00
co-authored by Claude Opus 4.7
parent 1c30bffb5e
commit 9888a5749e
2 changed files with 22 additions and 2 deletions
+7
View File
@@ -13,6 +13,13 @@ from email.mime.text import MIMEText
logger = logging.getLogger(__name__)
# Python's imaplib limitiert einzelne IMAP-Antworten hart auf 1 MB. Bei größeren
# Postfächern (>~130k Mails) liefert `UID SEARCH ALL` eine Response mit allen
# UIDs, die dieses Limit reißt → Poll bricht mit "got more than 1000000 bytes" ab
# und nichts wird mehr sortiert. Auf 100 MB anheben — reicht für Postfächer mit
# Millionen Mails.
imaplib._MAXLINE = 100_000_000
@dataclass
class MailMessage:
+15 -2
View File
@@ -195,11 +195,24 @@ async function loadFilters() {
}
function filterHaystack(f) {
// Auch die deutschen Labels aufnehmen, damit Suche nach z.B. "am (exakt)",
// "ab / nach", "verschieben" funktioniert — nicht nur nach den englischen
// Schlüsseln wie "on_date" / "after" / "move".
const condLabels = (f.conditions || []).flatMap(c => {
const fieldLabel = FIELDS.find(x => x.value === c.field)?.label || '';
const matchLabel = ALL_MATCH_TYPES.find(x => x.value === c.match_type)?.label || '';
return [c.field, c.match_type, c.value, fieldLabel, matchLabel, c.negate ? 'NICHT NOT' : ''];
});
const actLabels = (f.actions || []).flatMap(a => {
const actLabel = ACTION_TYPES.find(x => x.value === a.action_type)?.label || '';
return [a.action_type, a.parameter || '', actLabel];
});
const parts = [
f.name || '',
f.source_folder || '',
...(f.conditions || []).flatMap(c => [c.field, c.match_type, c.value]),
...(f.actions || []).flatMap(a => [a.action_type, a.parameter || '']),
f.stop_processing ? 'stop stop_processing' : '',
...condLabels,
...actLabels,
];
return parts.join(' ').toLowerCase();
}