import dns from "node:dns/promises"; /** * IMAP-Provider Konfigurationen * Automatisch erkennen anhand der Email-Domain */ export interface ImapConfig { host: string; port: number; name: string; } const PROVIDER_MAP: Record = { // Google "gmail.com": { host: "imap.gmail.com", port: 993, name: "Gmail" }, "googlemail.com": { host: "imap.gmail.com", port: 993, name: "Gmail" }, // Apple "icloud.com": { host: "imap.mail.me.com", port: 993, name: "iCloud" }, "me.com": { host: "imap.mail.me.com", port: 993, name: "iCloud" }, "mac.com": { host: "imap.mail.me.com", port: 993, name: "iCloud" }, // Microsoft "outlook.com": { host: "outlook.office365.com", port: 993, name: "Outlook" }, "hotmail.com": { host: "outlook.office365.com", port: 993, name: "Hotmail" }, "hotmail.de": { host: "outlook.office365.com", port: 993, name: "Hotmail" }, "live.com": { host: "outlook.office365.com", port: 993, name: "Live" }, "live.de": { host: "outlook.office365.com", port: 993, name: "Live" }, "msn.com": { host: "outlook.office365.com", port: 993, name: "Outlook" }, // Yahoo "yahoo.com": { host: "imap.mail.yahoo.com", port: 993, name: "Yahoo" }, "yahoo.de": { host: "imap.mail.yahoo.com", port: 993, name: "Yahoo" }, "yahoo.co.uk": { host: "imap.mail.yahoo.com", port: 993, name: "Yahoo" }, "ymail.com": { host: "imap.mail.yahoo.com", port: 993, name: "Yahoo" }, // GMX / Web.de (United Internet) "gmx.de": { host: "imap.gmx.net", port: 993, name: "GMX" }, "gmx.net": { host: "imap.gmx.net", port: 993, name: "GMX" }, "gmx.at": { host: "imap.gmx.net", port: 993, name: "GMX" }, "gmx.ch": { host: "imap.gmx.net", port: 993, name: "GMX" }, "web.de": { host: "imap.web.de", port: 993, name: "Web.de" }, // Telekom "t-online.de": { host: "secureimap.t-online.de", port: 993, name: "T-Online" }, "magenta.de": { host: "secureimap.t-online.de", port: 993, name: "T-Online" }, // Freenet "freenet.de": { host: "mx.freenet.de", port: 993, name: "Freenet" }, // Posteo "posteo.de": { host: "posteo.de", port: 993, name: "Posteo" }, // Tutanota / Tuta "tutanota.com": { host: "mail.tutanota.com", port: 993, name: "Tutanota" }, "tuta.io": { host: "mail.tutanota.com", port: 993, name: "Tutanota" }, // IONOS / 1&1 (direkte Consumer-Domains) "ionos.de": { host: "imap.ionos.de", port: 993, name: "IONOS" }, "1und1.de": { host: "imap.ionos.de", port: 993, name: "IONOS" }, "1and1.com": { host: "imap.ionos.de", port: 993, name: "IONOS" }, "1and1.de": { host: "imap.ionos.de", port: 993, name: "IONOS" }, "1blu.de": { host: "imap.1blu.de", port: 993, name: "1blu" }, }; /** * MX-Record-Patterns die IONOS-Hosting-Infrastruktur identifizieren. * IONOS-Kunden mit eigener Domain nutzen mx00.ionos.de oder kundenserver.de. * Quelle: IONOS Hilfe-Seite + eigene DNS-Lookups (verifiziert 2026-05). */ const MX_IONOS_PATTERNS = [ "ionos.de", "kundenserver.de", "perfora.net", "ui-dns.de", "ui-dns.org", "ui-dns.biz", "ui-dns.com", ]; /** * Versucht via MX-Record-Lookup den Provider einer Custom-Domain zu erkennen. * Wird nur aufgerufen wenn PROVIDER_MAP keinen direkten Treffer hat. * Timeout: 3s (schnell genug für Connect-Flow, kein User-Impact). */ async function detectImapProviderByMx(domain: string): Promise { try { const mxRecords = await Promise.race([ dns.resolveMx(domain), new Promise((_, reject) => setTimeout(() => reject(new Error("timeout")), 3000)), ]); for (const mx of mxRecords) { const exchange = mx.exchange.toLowerCase(); if (MX_IONOS_PATTERNS.some((pattern) => exchange.endsWith(pattern))) { return { host: "imap.ionos.de", port: 993, name: "IONOS" }; } } } catch { // DNS-Lookup fehlgeschlagen oder Timeout — kein Problem, Fallback greift } return null; } export function detectImapProvider(email: string): ImapConfig { const domain = email.split("@")[1]?.toLowerCase() ?? ""; return ( PROVIDER_MAP[domain] ?? { host: `imap.${domain}`, port: 993, name: domain, } ); } /** * Async-Variante mit MX-Lookup-Fallback für Custom-Domains. * Nutzen wenn detectImapProvider keinen bekannten Provider zurückgibt * (erkennbar daran dass name === domain, also kein Friendly-Name). */ export async function detectImapProviderAsync(email: string): Promise { const domain = email.split("@")[1]?.toLowerCase() ?? ""; const direct = PROVIDER_MAP[domain]; if (direct) return direct; const byMx = await detectImapProviderByMx(domain); if (byMx) return byMx; // Letzter Fallback: imap. — Standard-Konvention return { host: `imap.${domain}`, port: 993, name: domain }; } const SMTP_MAP: Record = { "imap.gmail.com": { host: "smtp.gmail.com", port: 587 }, "imap.mail.me.com": { host: "smtp.mail.me.com", port: 587 }, "imap.gmx.net": { host: "mail.gmx.net", port: 587 }, "imap.web.de": { host: "smtp.web.de", port: 587 }, "outlook.office365.com": { host: "smtp-mail.outlook.com", port: 587 }, "imap.mail.yahoo.com": { host: "smtp.mail.yahoo.com", port: 587 }, "secureimap.t-online.de": { host: "securesmtp.t-online.de", port: 587 }, "mx.freenet.de": { host: "mx.freenet.de", port: 587 }, "posteo.de": { host: "posteo.de", port: 587 }, }; export function detectSmtpProvider(imapHost: string): { host: string; port: number } { return SMTP_MAP[imapHost] ?? { host: imapHost.replace("imap.", "smtp."), port: 587 }; } /** * Leitet einen normalisierten Provider-Key + Label aus dem gespeicherten * providerName/imapHost einer MailConnection ab. * Wird in List-Endpoints + Stats-Endpoints für Filterung und Donut-Chart genutzt. * * Gibt { provider, providerLabel, isCustomDomain } zurück: * provider = slug (z.B. "gmail", "outlook", "icloud", "custom") * providerLabel = human-readable (z.B. "Gmail", "Outlook", "iCloud Mail") * isCustomDomain = true wenn kein bekannter großer Provider */ const HOST_TO_PROVIDER: Record = { "imap.gmail.com": { provider: "gmail", providerLabel: "Gmail" }, "outlook.office365.com": { provider: "outlook", providerLabel: "Outlook" }, "imap.mail.me.com": { provider: "icloud", providerLabel: "iCloud Mail" }, "imap.gmx.net": { provider: "gmx", providerLabel: "GMX" }, "imap.web.de": { provider: "webde", providerLabel: "Web.de" }, "imap.mail.yahoo.com": { provider: "yahoo", providerLabel: "Yahoo" }, "secureimap.t-online.de": { provider: "tonline", providerLabel: "T-Online" }, "mx.freenet.de": { provider: "freenet", providerLabel: "Freenet" }, "posteo.de": { provider: "posteo", providerLabel: "Posteo" }, "imap.ionos.de": { provider: "ionos", providerLabel: "IONOS" }, }; export function resolveProviderMeta(imapHost: string): { provider: string; providerLabel: string; isCustomDomain: boolean; } { const match = HOST_TO_PROVIDER[imapHost]; if (match) return { ...match, isCustomDomain: false }; return { provider: "custom", providerLabel: imapHost, isCustomDomain: true }; }