707 lines
22 KiB
Markdown
707 lines
22 KiB
Markdown
# EMLy Application Documentation
|
|
|
|
EMLy is a desktop email viewer application built for 3gIT, designed to open and display `.eml` and `.msg` email files on Windows. It provides a modern, user-friendly interface for viewing email content, attachments, and metadata.
|
|
|
|
## Table of Contents
|
|
|
|
1. [Architecture Overview](#architecture-overview)
|
|
2. [Technology Stack](#technology-stack)
|
|
3. [Project Structure](#project-structure)
|
|
4. [Backend (Go)](#backend-go)
|
|
5. [Frontend (SvelteKit)](#frontend-sveltekit)
|
|
6. [State Management](#state-management)
|
|
7. [Internationalization (i18n)](#internationalization-i18n)
|
|
8. [UI Components](#ui-components)
|
|
9. [Key Features](#key-features)
|
|
10. [Build & Development](#build--development)
|
|
|
|
---
|
|
|
|
## Architecture Overview
|
|
|
|
EMLy is built using the **Wails v2** framework, which combines a Go backend with a web-based frontend. This architecture allows:
|
|
|
|
- **Go Backend**: Handles file operations, Windows API calls, email parsing, and system interactions
|
|
- **Web Frontend**: Provides the user interface using SvelteKit with Svelte 5
|
|
- **Bridge**: Wails automatically generates TypeScript bindings for Go functions, enabling seamless communication
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────┐
|
|
│ EMLy Application │
|
|
├─────────────────────────────────────────────────────────┤
|
|
│ Frontend (SvelteKit + Svelte 5) │
|
|
│ ├── Routes & Pages │
|
|
│ ├── UI Components (shadcn-svelte) │
|
|
│ ├── State Management (Svelte 5 Runes) │
|
|
│ └── i18n (ParaglideJS) │
|
|
├─────────────────────────────────────────────────────────┤
|
|
│ Wails Bridge (Auto-generated TypeScript bindings) │
|
|
├─────────────────────────────────────────────────────────┤
|
|
│ Backend (Go) │
|
|
│ ├── App Logic (app.go) │
|
|
│ ├── Email Parsing (backend/utils/mail/) │
|
|
│ ├── Windows APIs (screenshot, debugger detection) │
|
|
│ └── File Operations │
|
|
└─────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## Technology Stack
|
|
|
|
### Backend
|
|
- **Go 1.21+**: Primary backend language
|
|
- **Wails v2**: Desktop application framework
|
|
- **Windows Registry API**: For checking default file handlers
|
|
- **GDI/User32 APIs**: For screenshot functionality
|
|
|
|
### Frontend
|
|
- **SvelteKit**: Application framework
|
|
- **Svelte 5**: UI framework with Runes ($state, $derived, $effect, $props)
|
|
- **TypeScript**: Type-safe JavaScript
|
|
- **shadcn-svelte**: UI component library
|
|
- **Tailwind CSS**: Utility-first CSS framework
|
|
- **ParaglideJS**: Internationalization
|
|
- **Lucide Icons**: Icon library
|
|
- **Bun**: JavaScript runtime and package manager
|
|
|
|
---
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
EMLy/
|
|
├── app.go # Main application logic
|
|
├── main.go # Application entry point
|
|
├── logger.go # Logging utilities
|
|
├── wails.json # Wails configuration
|
|
├── backend/
|
|
│ └── utils/
|
|
│ ├── mail/
|
|
│ │ ├── eml_reader.go # EML file parsing
|
|
│ │ ├── msg_reader.go # MSG file parsing
|
|
│ │ ├── mailparser.go # MIME email parsing
|
|
│ │ └── file_dialog.go # File dialog utilities
|
|
│ ├── screenshot_windows.go # Windows screenshot capture
|
|
│ ├── debug_windows.go # Debugger detection
|
|
│ ├── ini-reader.go # Configuration file parsing
|
|
│ ├── machine-identifier.go # System info collection
|
|
│ └── file-metadata.go # File metadata utilities
|
|
├── frontend/
|
|
│ ├── src/
|
|
│ │ ├── routes/ # SvelteKit routes
|
|
│ │ │ ├── +layout.svelte # Root layout
|
|
│ │ │ ├── +error.svelte # Error page
|
|
│ │ │ ├── (app)/ # Main app route group
|
|
│ │ │ │ ├── +layout.svelte # App layout with sidebar
|
|
│ │ │ │ ├── +page.svelte # Mail viewer page
|
|
│ │ │ │ └── settings/
|
|
│ │ │ │ └── +page.svelte # Settings page
|
|
│ │ │ ├── image/ # Image viewer route
|
|
│ │ │ │ ├── +layout.svelte
|
|
│ │ │ │ └── +page.svelte
|
|
│ │ │ └── pdf/ # PDF viewer route
|
|
│ │ │ ├── +layout.svelte
|
|
│ │ │ └── +page.svelte
|
|
│ │ ├── lib/
|
|
│ │ │ ├── components/ # Svelte components
|
|
│ │ │ │ ├── MailViewer.svelte
|
|
│ │ │ │ ├── SidebarApp.svelte
|
|
│ │ │ │ ├── UnsavedBar.svelte
|
|
│ │ │ │ └── ui/ # shadcn-svelte components
|
|
│ │ │ ├── stores/ # State management
|
|
│ │ │ │ ├── app.ts
|
|
│ │ │ │ ├── mail-state.svelte.ts
|
|
│ │ │ │ └── settings.svelte.ts
|
|
│ │ │ ├── paraglide/ # i18n runtime
|
|
│ │ │ ├── wailsjs/ # Auto-generated Go bindings
|
|
│ │ │ ├── types/ # TypeScript types
|
|
│ │ │ └── utils/ # Utility functions
|
|
│ │ └── messages/ # i18n translation files
|
|
│ │ ├── en.json
|
|
│ │ └── it.json
|
|
│ ├── static/ # Static assets
|
|
│ └── package.json
|
|
└── config.ini # Application configuration
|
|
```
|
|
|
|
---
|
|
|
|
## Backend (Go)
|
|
|
|
### Entry Point (`main.go`)
|
|
|
|
The application starts in `main.go`, which:
|
|
|
|
1. Initializes the logger
|
|
2. Parses command-line arguments for:
|
|
- `.eml` or `.msg` files to open on startup
|
|
- `--view-image=<path>` for image viewer mode
|
|
- `--view-pdf=<path>` for PDF viewer mode
|
|
3. Configures Wails with window options
|
|
4. Sets up single-instance lock to prevent multiple main windows
|
|
5. Binds the `App` struct for frontend access
|
|
|
|
```go
|
|
// Single instance with unique ID based on mode
|
|
uniqueId := "emly-app-lock"
|
|
if strings.Contains(arg, "--view-image") {
|
|
uniqueId = "emly-viewer-" + arg
|
|
windowTitle = "EMLy Image Viewer"
|
|
}
|
|
```
|
|
|
|
### Application Core (`app.go`)
|
|
|
|
The `App` struct is the main application controller, exposed to the frontend via Wails bindings.
|
|
|
|
#### Key Properties
|
|
|
|
```go
|
|
type App struct {
|
|
ctx context.Context
|
|
StartupFilePath string // File opened via command line
|
|
CurrentMailFilePath string // Currently loaded mail file
|
|
openImages map[string]bool // Track open image viewers
|
|
openPDFs map[string]bool // Track open PDF viewers
|
|
openEMLs map[string]bool // Track open EML viewers
|
|
}
|
|
```
|
|
|
|
#### Core Methods
|
|
|
|
| Method | Description |
|
|
|--------|-------------|
|
|
| `GetConfig()` | Returns application configuration from `config.ini` |
|
|
| `GetStartupFile()` | Returns file path passed via command line |
|
|
| `SetCurrentMailFilePath()` | Updates the current mail file path |
|
|
| `ReadEML(path)` | Parses an EML file and returns email data |
|
|
| `ReadMSG(path)` | Parses an MSG file and returns email data |
|
|
| `ReadPEC(path)` | Parses PEC (Italian certified email) files |
|
|
| `ShowOpenFileDialog()` | Opens native file picker for EML/MSG files |
|
|
| `OpenImageWindow(data, filename)` | Opens image in new viewer window |
|
|
| `OpenPDFWindow(data, filename)` | Opens PDF in new viewer window |
|
|
| `OpenEMLWindow(data, filename)` | Opens EML attachment in new window |
|
|
| `TakeScreenshot()` | Captures window screenshot as base64 PNG |
|
|
| `SubmitBugReport(input)` | Creates bug report with screenshot and system info |
|
|
| `ExportSettings(json)` | Exports settings to JSON file |
|
|
| `ImportSettings()` | Imports settings from JSON file |
|
|
| `IsDebuggerRunning()` | Checks if a debugger is attached |
|
|
| `QuitApp()` | Terminates the application |
|
|
|
|
### Email Parsing (`backend/utils/mail/`)
|
|
|
|
#### EML Reader (`eml_reader.go`)
|
|
Reads standard `.eml` files using the `mailparser.go` MIME parser.
|
|
|
|
#### MSG Reader (`msg_reader.go`)
|
|
Handles Microsoft Outlook `.msg` files using external conversion.
|
|
|
|
#### Mail Parser (`mailparser.go`)
|
|
A comprehensive MIME email parser that handles:
|
|
- Multipart messages (mixed, alternative, related)
|
|
- Text and HTML bodies
|
|
- Attachments with proper content-type detection
|
|
- Embedded files (inline images)
|
|
- Various content transfer encodings (base64, quoted-printable, 7bit, 8bit)
|
|
|
|
The `EmailData` structure returned to the frontend:
|
|
```go
|
|
type EmailData struct {
|
|
Subject string
|
|
From string
|
|
To []string
|
|
Cc []string
|
|
Bcc []string
|
|
Body string // HTML or text body
|
|
Attachments []AttachmentData
|
|
IsPec bool // Italian certified email
|
|
}
|
|
```
|
|
|
|
### Screenshot Utility (`backend/utils/screenshot_windows.go`)
|
|
|
|
Captures the application window using Windows GDI APIs:
|
|
- Uses `FindWindowW` to locate window by title
|
|
- Uses `DwmGetWindowAttribute` for DPI-aware window bounds
|
|
- Creates compatible DC and bitmap for capture
|
|
- Returns image as base64-encoded PNG
|
|
|
|
---
|
|
|
|
## Frontend (SvelteKit)
|
|
|
|
### Route Structure
|
|
|
|
SvelteKit uses file-based routing. The `(app)` folder is a route group that applies the main app layout.
|
|
|
|
```
|
|
routes/
|
|
├── +layout.svelte # Root layout (minimal)
|
|
├── +error.svelte # Global error page
|
|
├── (app)/ # Main app group
|
|
│ ├── +layout.svelte # App layout with titlebar, sidebar, footer
|
|
│ ├── +layout.ts # Server data loader
|
|
│ ├── +page.svelte # Main mail viewer page
|
|
│ └── settings/
|
|
│ ├── +page.svelte # Settings page
|
|
│ └── +layout.ts # Settings data loader
|
|
├── image/ # Standalone image viewer
|
|
│ ├── +layout.svelte
|
|
│ └── +page.svelte
|
|
└── pdf/ # Standalone PDF viewer
|
|
├── +layout.svelte
|
|
└── +page.svelte
|
|
```
|
|
|
|
### Main App Layout (`(app)/+layout.svelte`)
|
|
|
|
The app layout provides:
|
|
|
|
1. **Custom Titlebar**: Windows-style titlebar with minimize/maximize/close buttons
|
|
- Draggable for window movement
|
|
- Double-click to maximize/restore
|
|
|
|
2. **Sidebar Provider**: Collapsible navigation sidebar
|
|
|
|
3. **Footer Bar**: Quick access icons for:
|
|
- Toggle sidebar
|
|
- Navigate to home
|
|
- Navigate to settings
|
|
- Open bug report dialog
|
|
- Reload application
|
|
|
|
4. **Bug Report Dialog**: Complete bug reporting system with:
|
|
- Screenshot capture on dialog open
|
|
- Name, email, description fields
|
|
- System info collection
|
|
- Creates ZIP archive with all data
|
|
|
|
5. **Toast Notifications**: Using svelte-sonner
|
|
|
|
6. **Debugger Protection**: Detects attached debuggers and can quit if detected
|
|
|
|
### Mail Viewer (`(app)/+page.svelte` + `MailViewer.svelte`)
|
|
|
|
The mail viewer is split into two parts:
|
|
- `+page.svelte`: Page wrapper that initializes mail state from startup file
|
|
- `MailViewer.svelte`: Core email viewing component
|
|
|
|
#### MailViewer Features
|
|
|
|
- **Empty State**: Shows "Open EML/MSG File" button when no email loaded
|
|
- **Email Header**: Displays subject, from, to, cc, bcc fields
|
|
- **PEC Badge**: Shows green badge for Italian certified emails
|
|
- **Attachments Bar**: Horizontal scrollable list of attachments with type-specific icons
|
|
- **Email Body**: Rendered in sandboxed iframe for security
|
|
- **Loading Overlay**: Shows spinner during file loading
|
|
|
|
#### Attachment Handling
|
|
|
|
```typescript
|
|
// Different handlers based on file type
|
|
if (att.contentType.startsWith("image/")) {
|
|
// Opens in built-in or external viewer based on settings
|
|
await OpenImageWindow(base64Data, filename);
|
|
} else if (att.filename.toLowerCase().endsWith(".pdf")) {
|
|
// Opens in built-in or external PDF viewer
|
|
await OpenPDFWindow(base64Data, filename);
|
|
} else if (att.filename.toLowerCase().endsWith(".eml")) {
|
|
// Opens in new EMLy instance
|
|
await OpenEMLWindow(base64Data, filename);
|
|
} else {
|
|
// Download as file
|
|
<a href={dataUrl} download={filename}>...</a>
|
|
}
|
|
```
|
|
|
|
### Settings Page (`(app)/settings/+page.svelte`)
|
|
|
|
Organized into cards with various configuration options:
|
|
|
|
1. **Language Settings**
|
|
- Radio buttons for English/Italian
|
|
- Triggers full page reload on change
|
|
|
|
2. **Export/Import Settings**
|
|
- Export current settings to JSON file
|
|
- Import settings from JSON file
|
|
|
|
3. **Preview Page Settings**
|
|
- Supported image types (JPG, JPEG, PNG)
|
|
- Toggle built-in image viewer
|
|
- Toggle built-in PDF viewer
|
|
|
|
4. **Danger Zone** (Hidden by default, revealed by clicking settings 10 times rapidly)
|
|
- Open DevTools hint
|
|
- Reload application
|
|
- Reset to defaults
|
|
- Debugger protection toggle (disabled in production)
|
|
- Version information display
|
|
|
|
#### Unsaved Changes Detection
|
|
|
|
The settings page tracks changes and shows a persistent toast when there are unsaved modifications:
|
|
|
|
```typescript
|
|
$effect(() => {
|
|
const dirty = !isSameSettings(normalizeSettings(form), lastSaved);
|
|
unsavedChanges.set(dirty);
|
|
if (dirty) {
|
|
showUnsavedChangesToast({
|
|
onSave: saveToStorage,
|
|
onReset: resetToLastSaved,
|
|
});
|
|
}
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## State Management
|
|
|
|
EMLy uses a combination of Svelte 5 Runes and traditional Svelte stores.
|
|
|
|
### Mail State (`stores/mail-state.svelte.ts`)
|
|
|
|
Uses Svelte 5's `$state` rune for reactive email data:
|
|
|
|
```typescript
|
|
class MailState {
|
|
currentEmail = $state<internal.EmailData | null>(null);
|
|
|
|
setParams(email: internal.EmailData | null) {
|
|
this.currentEmail = email;
|
|
}
|
|
|
|
clear() {
|
|
this.currentEmail = null;
|
|
}
|
|
}
|
|
|
|
export const mailState = new MailState();
|
|
```
|
|
|
|
### Settings Store (`stores/settings.svelte.ts`)
|
|
|
|
Manages application settings with localStorage persistence:
|
|
|
|
```typescript
|
|
class SettingsStore {
|
|
settings = $state<EMLy_GUI_Settings>({ ...defaults });
|
|
hasHydrated = $state(false);
|
|
|
|
load() { /* Load from localStorage */ }
|
|
save() { /* Save to localStorage */ }
|
|
update(newSettings: Partial<EMLy_GUI_Settings>) { /* Merge and save */ }
|
|
reset() { /* Reset to defaults */ }
|
|
}
|
|
```
|
|
|
|
Settings schema:
|
|
```typescript
|
|
interface EMLy_GUI_Settings {
|
|
selectedLanguage: "en" | "it";
|
|
useBuiltinPreview: boolean;
|
|
useBuiltinPDFViewer: boolean;
|
|
previewFileSupportedTypes: string[];
|
|
enableAttachedDebuggerProtection: boolean;
|
|
}
|
|
```
|
|
|
|
### App Store (`stores/app.ts`)
|
|
|
|
Traditional Svelte writable stores for UI state:
|
|
|
|
```typescript
|
|
export const dangerZoneEnabled = writable<boolean>(false);
|
|
export const unsavedChanges = writable<boolean>(false);
|
|
export const sidebarOpen = writable<boolean>(true);
|
|
export const bugReportDialogOpen = writable<boolean>(false);
|
|
export const events = writable<AppEvent[]>([]);
|
|
```
|
|
|
|
---
|
|
|
|
## Internationalization (i18n)
|
|
|
|
EMLy uses **ParaglideJS** for compile-time type-safe translations.
|
|
|
|
### Translation Files
|
|
|
|
Located in `frontend/messages/`:
|
|
- `en.json` - English translations
|
|
- `it.json` - Italian translations
|
|
|
|
### Message Format
|
|
|
|
```json
|
|
{
|
|
"$schema": "https://inlang.com/schema/inlang-message-format",
|
|
"mail_no_email_selected": "No email selected",
|
|
"mail_open_eml_btn": "Open EML/MSG File",
|
|
"settings_title": "Settings",
|
|
"settings_language_english": "English",
|
|
"settings_language_italian": "Italiano"
|
|
}
|
|
```
|
|
|
|
### Usage in Components
|
|
|
|
```typescript
|
|
import * as m from "$lib/paraglide/messages";
|
|
|
|
// In template
|
|
<h1>{m.settings_title()}</h1>
|
|
<button>{m.mail_open_eml_btn()}</button>
|
|
```
|
|
|
|
### Changing Language
|
|
|
|
```typescript
|
|
import { setLocale } from "$lib/paraglide/runtime";
|
|
|
|
await setLocale("it", { reload: false });
|
|
location.reload(); // Page reload required for full update
|
|
```
|
|
|
|
---
|
|
|
|
## UI Components
|
|
|
|
EMLy uses **shadcn-svelte**, a port of shadcn/ui for Svelte. Components are located in `frontend/src/lib/components/ui/`.
|
|
|
|
### Available Components
|
|
|
|
| Component | Usage |
|
|
|-----------|-------|
|
|
| `Button` | Primary buttons with variants (default, destructive, outline, ghost) |
|
|
| `Card` | Container with header, content, footer sections |
|
|
| `Dialog` | Modal dialogs for bug reports, confirmations |
|
|
| `AlertDialog` | Confirmation dialogs with cancel/continue actions |
|
|
| `Switch` | Toggle switches for boolean settings |
|
|
| `Checkbox` | Multi-select checkboxes |
|
|
| `RadioGroup` | Single-select options (language selection) |
|
|
| `Label` | Form labels |
|
|
| `Input` | Text input fields |
|
|
| `Textarea` | Multi-line text input |
|
|
| `Separator` | Visual dividers |
|
|
| `Sidebar` | Collapsible navigation sidebar |
|
|
| `Tooltip` | Hover tooltips |
|
|
| `Sonner` | Toast notifications |
|
|
| `Badge` | Status badges |
|
|
| `Skeleton` | Loading placeholders |
|
|
|
|
### Custom Components
|
|
|
|
| Component | Purpose |
|
|
|-----------|---------|
|
|
| `MailViewer.svelte` | Email display with header, attachments, body |
|
|
| `SidebarApp.svelte` | Navigation sidebar with menu items |
|
|
| `UnsavedBar.svelte` | Unsaved changes notification bar |
|
|
|
|
---
|
|
|
|
## Key Features
|
|
|
|
### 1. Email Viewing
|
|
|
|
- Parse and display EML and MSG files
|
|
- Show email metadata (from, to, cc, bcc, subject)
|
|
- Render HTML email bodies in sandboxed iframe
|
|
- List and handle attachments with type-specific actions
|
|
|
|
### 2. Attachment Handling
|
|
|
|
- **Images**: Open in built-in viewer or external app
|
|
- **PDFs**: Open in built-in viewer or external app
|
|
- **EML files**: Open in new EMLy window
|
|
- **Other files**: Download directly
|
|
|
|
### 3. Multi-Window Support
|
|
|
|
The app can spawn separate viewer windows:
|
|
- Image viewer (`--view-image=<path>`)
|
|
- PDF viewer (`--view-pdf=<path>`)
|
|
- EML viewer (new app instance with file path)
|
|
|
|
Each viewer has a unique instance ID to allow multiple concurrent viewers.
|
|
|
|
### 4. Bug Reporting
|
|
|
|
Complete bug reporting system:
|
|
1. Captures screenshot when dialog opens
|
|
2. Collects user input (name, email, description)
|
|
3. Includes current mail file if loaded
|
|
4. Gathers system information
|
|
5. Creates ZIP archive in temp folder
|
|
6. Shows path and allows opening folder
|
|
|
|
### 5. Settings Management
|
|
|
|
- Language selection (English/Italian)
|
|
- Built-in viewer preferences
|
|
- Supported file type configuration
|
|
- Export/import settings as JSON
|
|
- Reset to defaults
|
|
|
|
### 6. Security Features
|
|
|
|
- Debugger detection and protection
|
|
- Sandboxed iframe for email body
|
|
- Single-instance lock for main window
|
|
- Disabled link clicking in email body
|
|
|
|
### 7. PEC Support
|
|
|
|
Special handling for Italian Posta Elettronica Certificata (PEC):
|
|
- Detects PEC emails
|
|
- Shows signed mail badge
|
|
- Handles P7S signature files
|
|
- Processes daticert.xml metadata
|
|
|
|
---
|
|
|
|
## Build & Development
|
|
|
|
### Prerequisites
|
|
|
|
- Go 1.21+
|
|
- Node.js 18+ or Bun
|
|
- Wails CLI v2
|
|
|
|
### Development
|
|
|
|
```bash
|
|
# Install frontend dependencies
|
|
cd frontend && bun install
|
|
|
|
# Run in development mode
|
|
wails dev
|
|
```
|
|
|
|
### Building
|
|
|
|
```bash
|
|
# Build for Windows
|
|
wails build -platform windows/amd64
|
|
|
|
# Output: build/bin/EMLy.exe
|
|
```
|
|
|
|
### Configuration
|
|
|
|
`wails.json` configures the build:
|
|
```json
|
|
{
|
|
"name": "EMLy",
|
|
"frontend:install": "bun install",
|
|
"frontend:build": "bun run build",
|
|
"frontend:dev:watcher": "bun run dev",
|
|
"fileAssociations": [
|
|
{
|
|
"ext": "eml",
|
|
"name": "Email Message",
|
|
"description": "EML File"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### File Association
|
|
|
|
The app registers as a handler for `.eml` files via Windows file associations, configured in `wails.json`.
|
|
|
|
---
|
|
|
|
## Wails Bindings
|
|
|
|
Wails automatically generates TypeScript bindings for Go functions. These are located in `frontend/src/lib/wailsjs/`.
|
|
|
|
### Generated Files
|
|
|
|
- `go/main/App.ts` - TypeScript functions calling Go methods
|
|
- `go/models.ts` - TypeScript types for Go structs
|
|
- `runtime/runtime.ts` - Wails runtime functions
|
|
|
|
### Usage Example
|
|
|
|
```typescript
|
|
import { ReadEML, ShowOpenFileDialog } from "$lib/wailsjs/go/main/App";
|
|
import type { internal } from "$lib/wailsjs/go/models";
|
|
|
|
// Open file dialog
|
|
const filePath = await ShowOpenFileDialog();
|
|
|
|
// Parse email
|
|
const email: internal.EmailData = await ReadEML(filePath);
|
|
```
|
|
|
|
### Runtime Events
|
|
|
|
Wails provides event system for Go-to-JS communication:
|
|
|
|
```typescript
|
|
import { EventsOn } from "$lib/wailsjs/runtime/runtime";
|
|
|
|
// Listen for second instance launch
|
|
EventsOn("launchArgs", (args: string[]) => {
|
|
// Handle file opened from second instance
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## Error Handling
|
|
|
|
### Frontend
|
|
|
|
Toast notifications for user-facing errors:
|
|
```typescript
|
|
import { toast } from "svelte-sonner";
|
|
import * as m from "$lib/paraglide/messages";
|
|
|
|
try {
|
|
await ReadEML(filePath);
|
|
} catch (error) {
|
|
toast.error(m.mail_error_opening());
|
|
}
|
|
```
|
|
|
|
### Backend
|
|
|
|
Errors are returned to frontend and logged:
|
|
```go
|
|
func (a *App) ReadEML(filePath string) (*internal.EmailData, error) {
|
|
data, err := internal.ReadEmlFile(filePath)
|
|
if err != nil {
|
|
Log("Failed to read EML:", err)
|
|
return nil, err
|
|
}
|
|
return data, nil
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Debugging
|
|
|
|
### Development Mode
|
|
|
|
In dev mode (`wails dev`):
|
|
- Hot reload enabled
|
|
- Debug logs visible
|
|
- DevTools accessible via Ctrl+Shift+F12
|
|
- Danger Zone always visible in settings
|
|
|
|
### Production
|
|
|
|
- Debugger protection can terminate app if debugger detected
|
|
- Danger Zone hidden by default
|
|
- Access Danger Zone by clicking settings link 10 times within 4 seconds
|
|
|
|
---
|
|
|
|
## License & Credits
|
|
|
|
EMLy is developed by FOISX @ 3gIT. |