From 20bfd2cf6b10cabbe7dab89d0b7b4456f676b58d Mon Sep 17 00:00:00 2001 From: KanjiG Date: Tue, 28 Jul 2026 20:56:05 +0200 Subject: [PATCH] Initial commit: Outlook-competitor desktop mail client Tauri v2 (Rust backend, React/TypeScript frontend). IMAP/POP3/SMTP core, Google OAuth (mail/calendar/contacts sync), CalDAV, local calendar with recurrence, rules engine, contacts, tasks, unified inbox, context menus, drag & drop, snooze, templates, and more. --- .gitignore | 33 + .oxlintrc.json | 8 + README.md | 52 + index.html | 13 + package-lock.json | 2468 +++++++++ package.json | 36 + public/favicon.svg | 1 + public/icons.svg | 24 + src-tauri/.gitignore | 4 + src-tauri/Cargo.lock | 5979 +++++++++++++++++++++ src-tauri/Cargo.toml | 43 + src-tauri/build.rs | 3 + src-tauri/capabilities/default.json | 17 + src-tauri/icons/128x128.png | Bin 0 -> 11059 bytes src-tauri/icons/128x128@2x.png | Bin 0 -> 23137 bytes src-tauri/icons/32x32.png | Bin 0 -> 2225 bytes src-tauri/icons/Square107x107Logo.png | Bin 0 -> 9202 bytes src-tauri/icons/Square142x142Logo.png | Bin 0 -> 12530 bytes src-tauri/icons/Square150x150Logo.png | Bin 0 -> 13032 bytes src-tauri/icons/Square284x284Logo.png | Bin 0 -> 25943 bytes src-tauri/icons/Square30x30Logo.png | Bin 0 -> 2078 bytes src-tauri/icons/Square310x310Logo.png | Bin 0 -> 28507 bytes src-tauri/icons/Square44x44Logo.png | Bin 0 -> 3419 bytes src-tauri/icons/Square71x71Logo.png | Bin 0 -> 6027 bytes src-tauri/icons/Square89x89Logo.png | Bin 0 -> 7551 bytes src-tauri/icons/StoreLogo.png | Bin 0 -> 3971 bytes src-tauri/icons/icon.icns | Bin 0 -> 277003 bytes src-tauri/icons/icon.ico | Bin 0 -> 37710 bytes src-tauri/icons/icon.png | Bin 0 -> 49979 bytes src-tauri/src/accounts.rs | 71 + src-tauri/src/caldav.rs | 205 + src-tauri/src/commands.rs | 1851 +++++++ src-tauri/src/db.rs | 1530 ++++++ src-tauri/src/error.rs | 50 + src-tauri/src/gcal.rs | 200 + src-tauri/src/gcontacts.rs | 228 + src-tauri/src/ics.rs | 303 ++ src-tauri/src/idle.rs | 118 + src-tauri/src/imap_client.rs | 259 + src-tauri/src/lib.rs | 137 + src-tauri/src/mailutil.rs | 162 + src-tauri/src/main.rs | 6 + src-tauri/src/mbox.rs | 91 + src-tauri/src/models.rs | 359 ++ src-tauri/src/oauth.rs | 217 + src-tauri/src/pop3_client.rs | 176 + src-tauri/src/recurrence.rs | 125 + src-tauri/src/reminders.rs | 70 + src-tauri/src/smtp_client.rs | 121 + src-tauri/src/vcard.rs | 85 + src-tauri/tauri.conf.json | 42 + src/App.tsx | 2069 +++++++ src/ComposeWindow.tsx | 104 + src/components/AccountModal.tsx | 293 + src/components/AccountSettingsModal.tsx | 413 ++ src/components/AttachmentPreviewModal.tsx | 63 + src/components/Avatar.tsx | 17 + src/components/BlockedSendersModal.tsx | 149 + src/components/CaldavModal.tsx | 219 + src/components/CalendarDayView.tsx | 126 + src/components/CalendarView.tsx | 231 + src/components/ClassicRibbonUI.tsx | 170 + src/components/ComposePane.tsx | 497 ++ src/components/ComposeRibbon.tsx | 301 ++ src/components/ContactGroupModal.tsx | 195 + src/components/ContactModal.tsx | 176 + src/components/ContactsView.tsx | 334 ++ src/components/ContextMenu.tsx | 139 + src/components/EventModal.tsx | 395 ++ src/components/GoogleCalendarMenu.tsx | 73 + src/components/GoogleContactsMenu.tsx | 81 + src/components/ImportModal.tsx | 174 + src/components/MessageList.tsx | 414 ++ src/components/NewMailPopup.tsx | 53 + src/components/Popover.tsx | 96 + src/components/ProviderIcons.tsx | 97 + src/components/ReadingPane.tsx | 306 ++ src/components/RecipientInput.tsx | 91 + src/components/RecurrenceScopeModal.tsx | 52 + src/components/Ribbon.tsx | 564 ++ src/components/RibbonButton.tsx | 35 + src/components/RichTextEditor.tsx | 68 + src/components/RulesModal.tsx | 325 ++ src/components/SettingsModal.tsx | 90 + src/components/ShortcutsModal.tsx | 51 + src/components/Sidebar.tsx | 496 ++ src/components/SnoozedModal.tsx | 99 + src/components/TaskModal.tsx | 218 + src/components/TasksView.tsx | 141 + src/components/TemplatesModal.tsx | 213 + src/components/UndoSendBanner.tsx | 40 + src/index.css | 121 + src/lib/addresses.ts | 11 + src/lib/api.ts | 147 + src/lib/categories.ts | 19 + src/lib/format.ts | 42 + src/lib/providers.ts | 86 + src/lib/richtext.ts | 7 + src/lib/settings.ts | 28 + src/lib/signature.ts | 92 + src/lib/theme.ts | 52 + src/main.tsx | 11 + src/types.ts | 285 + tsconfig.app.json | 26 + tsconfig.json | 7 + tsconfig.node.json | 23 + vite.config.ts | 16 + 107 files changed, 25728 insertions(+) create mode 100644 .gitignore create mode 100644 .oxlintrc.json create mode 100644 README.md create mode 100644 index.html create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 public/favicon.svg create mode 100644 public/icons.svg create mode 100644 src-tauri/.gitignore create mode 100644 src-tauri/Cargo.lock create mode 100644 src-tauri/Cargo.toml create mode 100644 src-tauri/build.rs create mode 100644 src-tauri/capabilities/default.json create mode 100644 src-tauri/icons/128x128.png create mode 100644 src-tauri/icons/128x128@2x.png create mode 100644 src-tauri/icons/32x32.png create mode 100644 src-tauri/icons/Square107x107Logo.png create mode 100644 src-tauri/icons/Square142x142Logo.png create mode 100644 src-tauri/icons/Square150x150Logo.png create mode 100644 src-tauri/icons/Square284x284Logo.png create mode 100644 src-tauri/icons/Square30x30Logo.png create mode 100644 src-tauri/icons/Square310x310Logo.png create mode 100644 src-tauri/icons/Square44x44Logo.png create mode 100644 src-tauri/icons/Square71x71Logo.png create mode 100644 src-tauri/icons/Square89x89Logo.png create mode 100644 src-tauri/icons/StoreLogo.png create mode 100644 src-tauri/icons/icon.icns create mode 100644 src-tauri/icons/icon.ico create mode 100644 src-tauri/icons/icon.png create mode 100644 src-tauri/src/accounts.rs create mode 100644 src-tauri/src/caldav.rs create mode 100644 src-tauri/src/commands.rs create mode 100644 src-tauri/src/db.rs create mode 100644 src-tauri/src/error.rs create mode 100644 src-tauri/src/gcal.rs create mode 100644 src-tauri/src/gcontacts.rs create mode 100644 src-tauri/src/ics.rs create mode 100644 src-tauri/src/idle.rs create mode 100644 src-tauri/src/imap_client.rs create mode 100644 src-tauri/src/lib.rs create mode 100644 src-tauri/src/mailutil.rs create mode 100644 src-tauri/src/main.rs create mode 100644 src-tauri/src/mbox.rs create mode 100644 src-tauri/src/models.rs create mode 100644 src-tauri/src/oauth.rs create mode 100644 src-tauri/src/pop3_client.rs create mode 100644 src-tauri/src/recurrence.rs create mode 100644 src-tauri/src/reminders.rs create mode 100644 src-tauri/src/smtp_client.rs create mode 100644 src-tauri/src/vcard.rs create mode 100644 src-tauri/tauri.conf.json create mode 100644 src/App.tsx create mode 100644 src/ComposeWindow.tsx create mode 100644 src/components/AccountModal.tsx create mode 100644 src/components/AccountSettingsModal.tsx create mode 100644 src/components/AttachmentPreviewModal.tsx create mode 100644 src/components/Avatar.tsx create mode 100644 src/components/BlockedSendersModal.tsx create mode 100644 src/components/CaldavModal.tsx create mode 100644 src/components/CalendarDayView.tsx create mode 100644 src/components/CalendarView.tsx create mode 100644 src/components/ClassicRibbonUI.tsx create mode 100644 src/components/ComposePane.tsx create mode 100644 src/components/ComposeRibbon.tsx create mode 100644 src/components/ContactGroupModal.tsx create mode 100644 src/components/ContactModal.tsx create mode 100644 src/components/ContactsView.tsx create mode 100644 src/components/ContextMenu.tsx create mode 100644 src/components/EventModal.tsx create mode 100644 src/components/GoogleCalendarMenu.tsx create mode 100644 src/components/GoogleContactsMenu.tsx create mode 100644 src/components/ImportModal.tsx create mode 100644 src/components/MessageList.tsx create mode 100644 src/components/NewMailPopup.tsx create mode 100644 src/components/Popover.tsx create mode 100644 src/components/ProviderIcons.tsx create mode 100644 src/components/ReadingPane.tsx create mode 100644 src/components/RecipientInput.tsx create mode 100644 src/components/RecurrenceScopeModal.tsx create mode 100644 src/components/Ribbon.tsx create mode 100644 src/components/RibbonButton.tsx create mode 100644 src/components/RichTextEditor.tsx create mode 100644 src/components/RulesModal.tsx create mode 100644 src/components/SettingsModal.tsx create mode 100644 src/components/ShortcutsModal.tsx create mode 100644 src/components/Sidebar.tsx create mode 100644 src/components/SnoozedModal.tsx create mode 100644 src/components/TaskModal.tsx create mode 100644 src/components/TasksView.tsx create mode 100644 src/components/TemplatesModal.tsx create mode 100644 src/components/UndoSendBanner.tsx create mode 100644 src/index.css create mode 100644 src/lib/addresses.ts create mode 100644 src/lib/api.ts create mode 100644 src/lib/categories.ts create mode 100644 src/lib/format.ts create mode 100644 src/lib/providers.ts create mode 100644 src/lib/richtext.ts create mode 100644 src/lib/settings.ts create mode 100644 src/lib/signature.ts create mode 100644 src/lib/theme.ts create mode 100644 src/main.tsx create mode 100644 src/types.ts create mode 100644 tsconfig.app.json create mode 100644 tsconfig.json create mode 100644 tsconfig.node.json create mode 100644 vite.config.ts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..89ab82b --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Rust / Tauri build output +src-tauri/target + +# Local secrets, never commit +.env +.env.* +*.pem +*.p12 + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/.oxlintrc.json b/.oxlintrc.json new file mode 100644 index 0000000..6fa991d --- /dev/null +++ b/.oxlintrc.json @@ -0,0 +1,8 @@ +{ + "$schema": "./node_modules/oxlint/configuration_schema.json", + "plugins": ["react", "typescript", "oxc"], + "rules": { + "react/rules-of-hooks": "error", + "react/only-export-components": ["warn", { "allowConstantExport": true }] + } +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..db750ec --- /dev/null +++ b/README.md @@ -0,0 +1,52 @@ +# Mail Client + +Ein nativer Desktop-Mail-Client (Tauri + Rust + React/Tailwind) mit eigenem IMAP-, POP3- und SMTP-Backend. Mehrere Konten (Gmail, Outlook, Yahoo, iCloud, beliebige custom IMAP/POP3-Server), Passwörter liegen im System-Keychain (nicht in einer Datei). + +## Setup (einmalig) + +Systempakete für den Tauri-Build unter Linux: + +``` +sudo apt update && sudo apt install -y libwebkit2gtk-4.1-dev libssl-dev libdbus-1-dev libgtk-3-dev libayatana-appindicator3-dev librsvg2-dev libsoup-3.0-dev build-essential curl wget file pkg-config +``` + +Rust-Toolchain: mind. 1.77 (per `rustup`, siehe https://rustup.rs). + +## Entwicklung starten + +``` +cd mail-client +npm install +npm run tauri dev +``` + +Das öffnet das App-Fenster mit Hot-Reload für Frontend und Backend. + +## Produktions-Build + +``` +npm run tauri build +``` + +## Konto hinzufügen + +Beim Hinzufügen eines Kontos über die Sidebar (`+`) ein Provider-Preset wählen. Für **Gmail** und **Yahoo** wird ein App-Passwort benötigt (nicht das normale Account-Passwort): + +- Gmail: Google-Konto → Sicherheit → 2-Faktor-Authentifizierung aktivieren → App-Passwörter +- Yahoo: Account Security → App-Passwörter generieren + +## Architektur + +- `src-tauri/src/imap_client.rs` — IMAP (Ordner, Nachrichtenliste, Volltext) via `imap` + `native-tls` +- `src-tauri/src/pop3_client.rs` — handgeschriebener minimaler POP3-Client (TLS, USER/PASS/LIST/TOP/RETR/DELE) +- `src-tauri/src/smtp_client.rs` — SMTP-Versand via `lettre` (implizites TLS oder STARTTLS) +- `src-tauri/src/db.rs` — SQLite-Cache für Nachrichten (Offline-Ansicht, schnelles erstes Laden) +- `src-tauri/src/accounts.rs` — Kontoverwaltung, Passwörter im OS-Keychain (`keyring` crate) +- `src/` — React/Tailwind-UI: 3-Spalten-Layout (Sidebar, Nachrichtenliste, Lesefenster) + Compose-Modal + +## Bekannte Einschränkungen (MVP) + +- POP3 verwendet die Server-seitige Nachrichtennummer als ID (keine stabile `UIDL`-basierte ID) — für ein Minimal-POP3-Setup ausreichend, aber nicht robust gegenüber Nachrichten-Neuordnung zwischen Sessions. +- Gmail/Outlook/Yahoo laufen über klassisches IMAP+Passwort-Login, nicht OAuth2 (einfacher Einstieg, funktioniert mit App-Passwörtern; für einen "Verified by Google"-OAuth-Flow müsste man eine Google-Cloud-App registrieren). +- Kein Ordner-Unread-Counter (Sidebar zeigt aktuell 0), keine Volltextsuche, keine Regeln/Filter. +- HTML-Mails werden in einem sandboxed `