fix(email): fail-fast IMAP timeouts + manual 'Check now' poll

- Root cause of the 502s: ImapFlow had no connect timeout, so a wrong host/port
  (e.g. IMAP on an SMTP port) hung the request until the proxy returned 502 with
  no message. Added connectionTimeout/greetingTimeout/socketTimeout + a hard
  connectWithTimeout() race on every IMAP client (detect/test/roundtrip/poll).
- Error routes now return 422 with the underlying reason (was 502, which
  collided with the proxy's own 502 and hid the message).
- New 'Check now' button + POST /incoming-config/poll runs the poller on demand
  (respects the incomingMail flag) and reports disabled/unconfigured/busy or N
  ingested — so 'nothing in Received' is diagnosable without waiting 60s.
- en/de strings
This commit is contained in:
Luca
2026-06-12 15:08:12 +02:00
parent e258472391
commit 8a54c6f6b1
6 changed files with 103 additions and 12 deletions
+10
View File
@@ -108,6 +108,11 @@ export interface ImapRoundTripResult {
recipient?: string;
}
export interface ImapPollResult {
processed?: number;
skipped?: 'disabled' | 'unconfigured' | 'busy';
}
export interface ReceivedEmail {
id: number;
message_id: string | null;
@@ -162,6 +167,11 @@ export const emailService = {
const response = await api.post<ImapRoundTripResult>('/admin/email/incoming-config/roundtrip', {});
return response.data;
},
// Run the poller on demand. Returns { processed } or { skipped: '…' }.
async pollIncoming(): Promise<ImapPollResult> {
const response = await api.post<ImapPollResult>('/admin/email/incoming-config/poll', {});
return response.data;
},
async listReceived(params: { page?: number; pageSize?: number } = {}): Promise<ReceivedEmailsResponse> {
const response = await api.get<ReceivedEmailsResponse>('/admin/email/received', { params });
return response.data;