Email-Anhang: echte IMAP-Fehlermeldung durchreichen

Bug: Anhang-Download schlug mit "Fehler beim Herunterladen des
Anhangs: Command failed" fehl – ohne jeden Kontext, warum.

Ursache: imapflow wirft bei jedem IMAP-NO/BAD-Response nur
`new Error('Command failed')` und legt den echten Server-Grund
in `.responseText` / `.responseStatus` ab. Unser Code las nur
`.message` und verlor damit alle Information.

Fix:
- fetchAttachmentInner extrahiert responseText/responseStatus
  aus dem imapflow-Error und packt sie in die geworfene Meldung.
- downloadAttachment-Catch macht das gleiche, damit auch andere
  IMAP-Fehler (mailboxOpen, connect) mit sinnvollem Text
  durchkommen.
- Zusätzlicher Friendly-Mapping-Fall für "no longer exist" /
  "no such message" → klare Meldung, dass die E-Mail-Liste
  neu synchronisiert werden sollte.

Damit sieht der User im UI jetzt z.B. "NO Some of the requested
messages no longer exist" statt "Command failed" und weiß, dass
ein Resync hilft.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-07-11 14:32:42 +02:00
co-authored by Claude Opus 4.7
parent 96f8715e13
commit be19e60a1b
2 changed files with 19 additions and 3 deletions
@@ -797,7 +797,14 @@ export async function downloadAttachment(req: AuthRequest, res: Response): Promi
res.send(attachment.content);
} catch (error) {
console.error('downloadAttachment error:', error);
const rawMsg = error instanceof Error ? error.message : 'Unbekannter Fehler';
// imapflow versteckt die eigentliche Server-Antwort in
// `.responseText`/`.responseStatus` und setzt `.message` immer nur auf
// `'Command failed'`. Wenn wir nur die `.message` ausgeben, sieht der
// Endnutzer im UI nichts Verwertbares.
const anyErr = error as { message?: string; responseText?: string; responseStatus?: string };
const rawMsg = anyErr?.responseText
? `${anyErr.responseStatus ? anyErr.responseStatus + ' ' : ''}${anyErr.responseText}`
: error instanceof Error ? error.message : 'Unbekannter Fehler';
const lower = rawMsg.toLowerCase();
let friendly = rawMsg;
@@ -810,6 +817,8 @@ export async function downloadAttachment(req: AuthRequest, res: Response): Promi
friendly = 'Zeitüberschreitung beim Verbinden zum IMAP-Server. Bitte später erneut versuchen.';
} else if (lower.includes('authentication') || lower.includes('auth')) {
friendly = 'IMAP-Authentifizierung fehlgeschlagen. Bitte Zugangsdaten prüfen.';
} else if (lower.includes('no longer exist') || lower.includes('no such message') || lower.includes('unknown')) {
friendly = 'Nachricht existiert im IMAP-Postfach nicht mehr (wahrscheinlich verschoben oder gelöscht). Bitte E-Mail-Liste neu synchronisieren.';
}
res.status(500).json({
+9 -2
View File
@@ -530,9 +530,16 @@ async function fetchAttachmentInner(
}
}
} catch (fetchErr) {
console.error(`[fetchAttachment] fetch(UID ${uid}) failed:`, fetchErr);
// imapflow wirft bei IMAP-NO/BAD immer nur `new Error('Command failed')`,
// die eigentliche Server-Antwort steht in `.responseText`. Ohne die
// Anreicherung sähe der User oben im UI nur "Command failed" ohne
// Kontext (Ursache 2026-07-11).
const anyErr = fetchErr as { message?: string; responseText?: string; responseStatus?: string; response?: unknown };
const detail = anyErr?.responseText || anyErr?.message || 'unbekannter Fehler';
const statusTag = anyErr?.responseStatus ? `${anyErr.responseStatus} ` : '';
console.error(`[fetchAttachment] fetch(UID ${uid}) failed [${statusTag}${detail}]:`, fetchErr);
throw new Error(
`Nachricht mit UID ${uid} konnte nicht geladen werden (${fetchErr instanceof Error ? fetchErr.message : 'unbekannter Fehler'}). Möglicherweise wurde sie im IMAP-Postfach verschoben oder gelöscht.`,
`Nachricht mit UID ${uid} konnte nicht geladen werden: ${statusTag}${detail}. Möglicherweise wurde sie im IMAP-Postfach verschoben oder gelöscht.`,
);
}