fix: Mails vor der Einrichtung waren fuer immer ausserhalb des Suchfensters

Der Zeitstempel des letzten Abrufs wird auch dann gesetzt, wenn ein Abruf
nichts fand – und danach sucht Certain nur noch ab gestern. Wer das Postfach
einrichtet, nachdem die Mails schon da waren, findet sie nie: Der erste,
ergebnislose Abruf schiebt das Fenster an ihnen vorbei.

Jetzt gibt es "Aelteres nachholen": Es sucht die letzten 90 Tage und uebergeht
den Zeitstempel. Dass dabei nichts doppelt ankommt, sichert wie bisher die
Message-ID.

Ausserdem sagt die Meldung jetzt, AB WANN gesucht wurde. Bisher stand dort
"Stimmt der Ordner?" – die Frage war fast immer die falsche.

Und ein latenter Fehler, der im August nicht auffaellt: Das Suchdatum wurde mit
strftime("%b") gebaut, also mit dem Monatskuerzel in der Sprache des Servers.
IMAP verlangt die englischen; auf einem deutschen System haette die Suche im
Maerz, Mai, Oktober und Dezember nichts gefunden. Die Kuerzel stehen jetzt fest
im Code.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Guido
2026-08-27 12:59:08 +02:00
co-authored by Claude Opus 5
parent ca63fef5c4
commit 60b8178c57
7 changed files with 115 additions and 21 deletions
+5 -1
View File
@@ -184,7 +184,11 @@ export const api = {
updateMailSource: (id, body) => request(`/mail/sources/${id}`, { method: "PUT", body }),
deleteMailSource: (id) => request(`/mail/sources/${id}`, { method: "DELETE" }),
testMailSource: (id) => request(`/mail/sources/${id}/test`, { method: "POST" }),
fetchMailSource: (id) => request(`/mail/sources/${id}/fetch`, { method: "POST" }),
// `tage` uebergeht den letzten Abruf – fuer Mails, die schon vor der
// Einrichtung im Postfach lagen und sonst ausserhalb des Fensters blieben.
fetchMailSource: (id, tage) =>
request(`/mail/sources/${id}/fetch${tage ? `?tage=${tage}` : ""}`,
{ method: "POST" }),
listMailSenders: (id) => request(`/mail/sources/${id}/senders`),
createMailSender: (id, body) => request(`/mail/sources/${id}/senders`, { method: "POST", body }),
updateMailSender: (id, body) => request(`/mail/senders/${id}`, { method: "PUT", body }),
+3 -2
View File
@@ -568,11 +568,12 @@
"edit": "Postfach bearbeiten",
"skippedTitle": "Diese Mails wurden übergangen",
"skippedHint": "Für sie passt keine Absender-Zuordnung. Trag einen Teil der Adresse oder des Betreffs unten ein, dann werden sie beim nächsten Abruf übernommen.",
"fetchedNone": "Keine Mails im gewählten Ordner gefunden. Stimmt der Ordner? Beim ersten Abruf werden die letzten 14 Tage durchsucht.",
"fetchedNone": "Keine Mails seit {{seit}} gefunden. Liegen die Mails länger zurück, nimm „Älteres nachholen“ – oder prüfe den Ordner.",
"senderHint": "Gesucht wird in Absender, Betreff und im Anfang des Textes – das greift auch bei weitergeleiteten Mails. Die Währung ist optional: Revolut schickt für Euro und Franken dieselbe Mail, erst sie sagt, welches Konto gemeint ist. Zuordnungen mit Währung gehen den allgemeinen vor.",
"deleteSender": "Zuordnung entfernen",
"deleteSenderConfirm": "Zuordnung „{{text}}“ entfernen? Bereits erfasste Zahlungen bleiben.",
"anyCurrency": "jede Währung"
"anyCurrency": "jede Währung",
"fetchOlder": "Älteres nachholen"
},
"bank": {
"title": "Bankkonten Anbindung",
+3 -2
View File
@@ -568,11 +568,12 @@
"edit": "Edit mailbox",
"skippedTitle": "These emails were skipped",
"skippedHint": "No sender mapping matched them. Enter part of the address or the subject below and they will be picked up on the next fetch.",
"fetchedNone": "No emails found in the selected folder. Is the folder right? The first fetch looks at the last 14 days.",
"fetchedNone": "No mail found since {{seit}}. If the mails are older, use “Catch up on older” – or check the folder.",
"senderHint": "Searched in sender, subject and the start of the body – that also works for forwarded emails. The currency is optional: Revolut sends the same email for euros and francs, and only it tells which account is meant. Mappings with a currency take precedence over general ones.",
"deleteSender": "Remove mapping",
"deleteSenderConfirm": "Remove mapping “{{text}}”? Payments already captured stay.",
"anyCurrency": "any currency"
"anyCurrency": "any currency",
"fetchOlder": "Catch up on older"
},
"bank": {
"title": "Bank account connection",
+13 -4
View File
@@ -1,6 +1,7 @@
import { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { api } from "../../api";
import { formatDate } from "../../format";
import { useToast } from "../../toast";
import { useConfirm } from "../../confirm";
import Icon from "../../components/Icon";
@@ -86,13 +87,15 @@ export default function Postfaecher() {
}
}
async function abrufen(quelle) {
async function abrufen(quelle, tage) {
setBusy(true);
try {
const r = await api.fetchMailSource(quelle.id);
// „0 neu" allein sagt nicht, ob nichts da war oder nichts passte.
const r = await api.fetchMailSource(quelle.id, tage);
// „0 neu" allein sagt nicht, ob nichts da war oder nichts passte. Und
// wenn nichts da war, ist die Frage nicht „stimmt der Ordner", sondern
// „wie weit wurde überhaupt gesucht" – deshalb steht das Datum dabei.
toast(r.gefunden === 0
? t("mailbox.fetchedNone")
? t("mailbox.fetchedNone", { seit: r.seit ? formatDate(r.seit) : "?" })
: t("mailbox.fetched", { gefunden: r.gefunden, neu: r.neu, unklar: r.unklar }));
setUebergangen(r.ohne_zuordnung || []);
laden();
@@ -174,6 +177,12 @@ export default function Postfaecher() {
<div className="mail-actions">
<button className="btn sm" disabled={busy} onClick={() => testen(q)}>{t("mailbox.test")}</button>
<button className="btn sm primary" disabled={busy} onClick={() => abrufen(q)}>{t("mailbox.fetchNow")}</button>
{/* Der Zeitstempel wird auch gesetzt, wenn ein Abruf nichts fand.
Ohne diesen Weg blieben ältere Mails für immer ausserhalb des
Fensters, obwohl sie im Postfach liegen. */}
<button className="btn sm" disabled={busy} onClick={() => abrufen(q, 90)}>
{t("mailbox.fetchOlder")}
</button>
<button className="btn sm ghost" title={t("common.edit")}
onClick={() => { setForm({ ...LEER, ...q, password: "" }); setOrdner(null); }}>
<Icon name="edit" size={15} />