chahinebrini 518510c088 feat(mail): IONOS-Detection + MX-Lookup-Fallback + humanisierte Error-Messages
- imap-providers: IONOS/1&1/1blu, msn.com, magenta.de, yahoo.co.uk, ymail.com, tutanota hinzugefügt
- detectImapProviderAsync: MX-Lookup-Fallback für Custom-Domains (IONOS kundenserver.de/ionos.de Pattern)
- connect.post.ts: nutzt jetzt detectImapProviderAsync statt sync-Variante
- ConnectMailSheet: rohe Server-Errors werden via humanizeMailError() + t() übersetzt
- useMailConnect: IONOS/t-online/freenet Domains in Client-Side-Detection ergänzt
- Locale de/en: provider_other, app_password_guide_other, host_unreachable, unknown Text präzisiert

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 05:15:29 +02:00

111 lines
2.9 KiB
TypeScript

import { useCallback, useState } from 'react';
import { apiFetch } from '../lib/api';
export type MailProvider =
| 'gmail'
| 'icloud'
| 'outlook'
| 'yahoo'
| 'gmx'
| 'other';
type ConnectBody = {
email: string;
password: string;
// Provider-Feld wird NICHT an das Backend gesendet — der Server erkennt
// den Provider automatisch via Email-Domain (detectImapProvider in connect.post.ts).
// Optionale Custom-IMAP-Felder für "other":
imapHost?: string;
imapPort?: number;
useTls?: boolean;
rejectUnauthorized?: boolean;
};
type ConnectResult = {
connected: boolean;
email: string;
provider: string;
custom: boolean;
};
export type UseMailConnectReturn = {
connect: (params: ConnectBody) => Promise<{ ok: boolean; error?: string }>;
connecting: boolean;
error: string | null;
/** Leitet aus der Email-Domain den Provider ab (rein client-seitig, zur UI-Hilfe). */
detectProvider: (email: string) => MailProvider;
};
const PROVIDER_DOMAIN_MAP: Record<string, MailProvider> = {
// Google
'gmail.com': 'gmail',
'googlemail.com': 'gmail',
// Apple
'icloud.com': 'icloud',
'me.com': 'icloud',
'mac.com': 'icloud',
// Microsoft
'outlook.com': 'outlook',
'hotmail.com': 'outlook',
'hotmail.de': 'outlook',
'live.com': 'outlook',
'live.de': 'outlook',
'msn.com': 'outlook',
// Yahoo
'yahoo.com': 'yahoo',
'yahoo.de': 'yahoo',
'yahoo.co.uk': 'yahoo',
'ymail.com': 'yahoo',
// GMX / Web.de
'gmx.de': 'gmx',
'gmx.net': 'gmx',
'gmx.at': 'gmx',
'gmx.ch': 'gmx',
'web.de': 'gmx',
// IONOS / 1&1 → als 'other' behandeln (Server-seitig korrekt erkannt)
'ionos.de': 'other',
'1und1.de': 'other',
'1and1.com': 'other',
'1and1.de': 'other',
'1blu.de': 'other',
// Telekom + Freenet → 'other' (kein eigenes Tile, aber Server kennt sie)
't-online.de': 'other',
'freenet.de': 'other',
};
export function detectProvider(email: string): MailProvider {
const domain = email.trim().toLowerCase().split('@')[1] ?? '';
return PROVIDER_DOMAIN_MAP[domain] ?? 'other';
}
/**
* Kapselt POST /api/mail/connect.
*
* Backend erwartet: { email, password, imapHost?, imapPort?, useTls?, rejectUnauthorized? }
* Provider-Detection passiert server-seitig — wir senden keinen provider-Key.
*/
export function useMailConnect(): UseMailConnectReturn {
const [connecting, setConnecting] = useState(false);
const [error, setError] = useState<string | null>(null);
const connect = useCallback(async (params: ConnectBody) => {
setConnecting(true);
setError(null);
try {
await apiFetch<ConnectResult>('/api/mail/connect', {
method: 'POST',
body: params,
});
return { ok: true };
} catch (e: any) {
const msg = e?.message ?? 'Verbindung fehlgeschlagen';
setError(msg);
return { ok: false, error: msg };
} finally {
setConnecting(false);
}
}, []);
return { connect, connecting, error, detectProvider };
}