mirror of
https://github.com/MAKS-IT-COM/maksit-postclient.git
synced 2026-09-30 03:18:09 +02:00
209 lines
13 KiB
Markdown
209 lines
13 KiB
Markdown
# Postclient
|
||
|
||

|
||

|
||

|
||

|
||

|
||

|
||
|
||
**Language:** [English](README.md) · [Italiano](README.it.md) · [Français](README.fr.md) · [Deutsch](README.de.md) · [Español](README.es.md)
|
||
|
||
The application UI is English or Italian. These documents describe the same client for people who use certified electronic mail (Italian PEC and eIDAS REM) as private users or as a practice / agency.
|
||
|
||
Postclient is a desktop mail client for Windows, Linux, and macOS (Apple Silicon and Intel). It connects with **IMAP**, **POP3**, and **SMTP** to mailboxes you already have: ordinary mail, Italian **PEC** at a qualified gestore, and European **REM** (registered electronic mail) when the operator publishes IMAP/SMTP.
|
||
|
||
It is **not** a qualified trust service provider (QTSP), **not** a PEC operator, **not** a timestamp authority, and **not** a cloud mailbox. Receipts and transport envelopes come from the gestore / QTSP. This client unwraps them, shows the operator’s evidence, and keeps a copy on the machine.
|
||
|
||
| | |
|
||
|--|--|
|
||
| Kind | Desktop mail client |
|
||
| OS | Windows, Linux, macOS |
|
||
| Stack | C#, .NET 10, Avalonia, MailKit |
|
||
| License | [Apache 2.0](LICENSE.md) |
|
||
| Not | A QTSP, a new PEC/REM address, hosted mail, or a scanner |
|
||
|
||
Changes: [CHANGELOG.md](CHANGELOG.md). Contributing: [CONTRIBUTING.md](CONTRIBUTING.md).
|
||
|
||
## Who it is for
|
||
|
||
### Private individuals
|
||
|
||
Use it as the daily client for one or more addresses: Gmail or Microsoft 365 next to a personal PEC (Italy) or an IMAP REM mailbox (EU). Mail is indexed on this PC so you can search a condominium notice, a tax file, or a PA communication years later without leaving the originals on someone else’s server.
|
||
|
||
Typical private use: keep the certified mailbox and the ordinary mailbox in one window; see whether a PEC was accepted and deposited; print or save a PDF of a message; export the original `.eml` if a municipality, bank, or court asks for it.
|
||
|
||
### Practices and agencies
|
||
|
||
Use it when several certified identities must not be mixed: personal PEC, studio PEC, and ordinary mail (Gmail / Microsoft 365). **From** is a picker of connected mailboxes, not a free-typed address. A commercialista, avvocato, notaio, CAF, condominium administrator, or EU practice that files with PA can:
|
||
|
||
- keep each gestore mailbox separate, with its own IMAP quota in the status bar;
|
||
- label messages on this PC by practice (for example a condominium or a client file) — labels are **local**, not a shared studio database;
|
||
- group a send with the gestore ricevute that refer to it;
|
||
- export selected originals as a **fascicolo** of `.eml` files for a notaio, a court, or a PA desk;
|
||
- open **FatturaPA** XML attachments as a readable view (XML parser, not AI);
|
||
- import a colleague’s Thunderbird profile or an Outlook **PST/OST** without installing Outlook.
|
||
|
||
The program does not replace the gestore, does not issue a qualified ricevuta, and does not share the practice table across the office.
|
||
|
||
## Accounts and protocols
|
||
|
||
Incoming: **IMAP** (full folder tree) or **POP3** (Inbox only). Outgoing: **SMTP**. Encryption: Auto, SSL/TLS, STARTTLS, STARTTLS if available, or none. MailKit uses the SASL methods the server advertises.
|
||
|
||
Several mailboxes can be stored at once. Presets fill hosts and ports:
|
||
|
||
| Preset | Role |
|
||
|--|--|
|
||
| Gmail | IMAP/SMTP; sign in with Google (OAuth2 / XOAUTH2) or a Gmail app password |
|
||
| Outlook / Microsoft 365 | IMAP/SMTP; sign in with Microsoft. Most of these accounts reject a mailbox password |
|
||
| IT PEC — Aruba | `imaps.pec.aruba.it` / `smtps.pec.aruba.it` (POP3: `pop3s.pec.aruba.it`) |
|
||
| IT PEC — InfoCert Legalmail | `mbox.cert.legalmail.it` / `sendm.cert.legalmail.it`. Username is often the InfoCert User ID, not the address |
|
||
| IT/EU PEC — Namirial | `imaps.sicurezzapostale.it` / `smtps.sicurezzapostale.it` |
|
||
| IT PEC — Poste Italiane | `mail.postecert.it` |
|
||
| IT PEC — Register.it | `imap.pec-email.com` / `smtp.pec-email.com` |
|
||
| IT PEC — Libero | `mail.postacert.it.net` |
|
||
| EU — Intesi Group | `imap.ig-trustmail.com` / `smtp.ig-trustmail.com` |
|
||
| IMAP / POP3 | Any other host the operator gave you |
|
||
|
||
Certified IMAP mailboxes use the gestore password, or an app password if the gestore has 2FA. **AR24** (France), **De-Mail** (Germany), **IncaMail** (Switzerland), and **Lleida** (Spain) are usually not IMAP. If that operator gave you IMAP/POP3 hosts, choose **IMAP / POP3** and enter them. Otherwise this client cannot open that mailbox; it can still display ETSI REM evidence on messages you import as `.eml`.
|
||
|
||
OAuth needs a Google client ID (ends with `.apps.googleusercontent.com`) and, for **Web** clients, the **client secret** — paste both in Account Settings (the secret is stored in `secrets.bin`, not as the mailbox password). Desktop public clients need no secret. Environment variables `POSTCLIENT_GOOGLE_CLIENT_ID` / `POSTCLIENT_GOOGLE_CLIENT_SECRET` are also accepted. Enable the **Gmail API**, add scope `https://mail.google.com/` on the consent screen, allow loopback `http://127.0.0.1`, and enable **IMAP** in Gmail. Microsoft: Azure Application (client) ID (a GUID); public client; redirect `http://localhost`; IMAP/SMTP permissions.
|
||
|
||
Passwords and OAuth refresh tokens stay next to settings (`DPAPI` on Windows, file mode `600` on Linux/macOS), never in `settings.json`.
|
||
|
||
## Italian PEC
|
||
|
||
Italian certified mail is a **busta** (envelope) produced by the gestore:
|
||
|
||
- transport message with `X-Trasporto: posta-certificata`, `daticert.xml`, and the original as `postacert.eml`;
|
||
- ricevute (`X-Ricevuta`) in **Inbox** and **Ricevute**: accettazione, presa-in-carico, avvenuta-consegna, non-accettazione, mancata-consegna, rilevazione-virus, preavviso-errore-consegna.
|
||
|
||
View → **Unwrap PEC/REM envelope** shows the inner `postacert.eml` (the message the recipient was meant to read) instead of the outer gestore wrapper. The Type column marks **PEC** (transport) or **RIC** (ricevuta).
|
||
|
||
Italian PEC has **no read receipt**. **Avvenuta consegna** means the message was deposited in the recipient’s certified mailbox, not that a person opened it.
|
||
|
||
## European REM (eIDAS)
|
||
|
||
When the message carries ETSI REM evidence (`REMEvidence` / `urn:etsi:rem`, or a part name such as `remevidence` / `rem-md`), the client treats it as **REM** (region Europe). Event types are mapped onto the same delivery column as PEC:
|
||
|
||
- `SubmissionAcceptance` → accepted by the QTSP;
|
||
- `Delivery` / LRE or AR24 avis de réception / De-Mail Zustellung / acuse de recibo → deposited;
|
||
- `ContentConsignment` / `Retrieval` / De-Mail `Abholbestätigung` → the recipient retrieved the content (closest European equivalent of “read”);
|
||
- rejection, virus, non-delivery, `DeliveryExpiration` → failed.
|
||
|
||
S/MIME (`smime.p7s` / `smime.p7m`) is shown as digitally signed; it is not PEC and not REM.
|
||
|
||
## Delivery column after send
|
||
|
||
After SMTP send, Postclient stores the outbound **Message-Id** and, when you open **Sent**, reconciles gestore ricevute from **Inbox** and **Ricevute**. Matching uses, in order: `daticert.xml` `<msgid>`, `X-Riferimento-Message-ID`, `In-Reply-To`, PEC `identificativo`, then subject prefixes (`ACCETTAZIONE:`, `CONSEGNA:`, `AVIS DE RECEPTION:`, `ACUSE DE RECIBO:`, `ZUSTELLBESTAETIGUNG:`, `ABHOLBESTAETIGUNG:`, …).
|
||
|
||
| Evidence | Mark | Meaning |
|
||
|--|--|--|
|
||
| PEC `accettazione` / `presa-in-carico`, ETSI `SubmissionAcceptance` | Accepted | The gestore took the message |
|
||
| PEC `avvenuta-consegna`, ETSI `Delivery`, LRE/AR24 avis, De-Mail Zustellung | Delivered | Deposited in the recipient **certified mailbox** — Italian PEC has **no read receipt** |
|
||
| ETSI `ContentConsignment` / `Retrieval`, De-Mail `Abholbestätigung` | Retrieved | Recipient picked up the content |
|
||
| `non-accettazione`, `mancata-consegna`, virus, ETSI rejection | Failed | Gestore reported non-acceptance or failed delivery |
|
||
|
||
This client **shows** operator evidence. It does not issue a qualified ricevuta, PEC envelope, or timestamp.
|
||
|
||
Desktop notices fire for new PEC, ricevute, and REM (Windows toast, macOS notification, Linux `notify-send`).
|
||
|
||
## Reading, folders, compose
|
||
|
||
- Folder tree follows the server (Inbox, Ricevute/Receipts, Drafts, Sent, Archive, Junk, Trash, plus custom folders). System folders cannot be deleted. You can create a folder, empty one (to Trash, or permanently in Trash), mark all read/unread, delete a custom folder, and drag messages onto a folder.
|
||
- List columns: unread, flag, attachments, delivery, type (PEC / RIC / REM / SIG), from, subject, date (local `yyyy-MM-dd HH:mm`), practice label.
|
||
- View: HTML (OS web engine), plain text, raw source, or **FatturaPA**. Layout: list above reading, or three columns (folders, list, reading).
|
||
- **Group conversations** indents replies in the folder list using Message-ID / In-Reply-To / References (depth up to 8). PEC ricevute that share the same original sit together. There is no separate conversation pane.
|
||
- Message actions: reply, reply all, forward, open in a new window, read/unread, flag, priority, delete.
|
||
- Compose is **plain text**. To, Cc, Bcc are address chips. Attachments are listed on the composer. Send uses the selected mailbox’s SMTP identity only.
|
||
|
||
HTML uses the OS engine: **WebView2** on Windows (profile under the data folder), **WebKitGTK** on Linux, **WKWebView** on macOS. If the engine is missing, the text body is shown instead.
|
||
|
||
Linux packages for the HTML view:
|
||
|
||
```bash
|
||
sudo apt install libgtk-3-0 libwebkit2gtk-4.1-0 libsoup-3.0-0
|
||
```
|
||
|
||
Fedora: `gtk3 webkit2gtk4.1 libsoup3`.
|
||
|
||
## Archive, search, labels
|
||
|
||
Get Messages indexes the **whole IMAP folder** into a local SQLite store (`mail.db`) plus `.eml` objects on disk. POP3 only fills Inbox. Indexing runs in the background; the status bar shows progress.
|
||
|
||
Search (current folder) covers subject, body, attachment text (PDF and text/XML/HTML/CSV/JSON), and practice labels. Labels exist only on this PC.
|
||
|
||
The archive is **only on this PC**. File → Open archive folder / Export archive copies `mail.db` and the `.eml` files. Paths:
|
||
|
||
| OS | Config | Data |
|
||
|--|--|--|
|
||
| Windows | `%AppData%\Postclient\` | `%LocalAppData%\Postclient\` |
|
||
| Linux | `~/.config/postclient/` | `~/.local/share/postclient/` |
|
||
| macOS | `~/Library/Application Support/Postclient/` | same |
|
||
|
||
Override with `POSTCLIENT_CONFIG` / `POSTCLIENT_DATA_DIR`. A portable Windows zip that contains `settings.json` with `installType: portable` keeps config next to the executable.
|
||
|
||
IMAP **QUOTA** from the gestore (when the server supports it) is shown in the status bar. That is the operator mailbox, not cloud storage from this application.
|
||
|
||
## Import, export, print
|
||
|
||
| Action | What you get |
|
||
|--|--|
|
||
| Import EML | Originals into the current folder |
|
||
| Import Thunderbird | Local mbox stores from the Thunderbird profile |
|
||
| Import Outlook PST/OST | Mail without installing Outlook |
|
||
| Print | Readable HTML of the (optionally unwrapped) message |
|
||
| Save PDF | Same content as a PDF |
|
||
| Save attachments ZIP | All attachments of the open message |
|
||
| Export selected EML (fascicolo) | The original `.eml` files — what a notaio or PA can keep as the message |
|
||
|
||
Opened messages are also stored as `.eml` under the data folder. The `.eml` files are the originals; PDF/print are a reading copy.
|
||
|
||
## Interface language
|
||
|
||
View → Language: **English** or **Italiano**. Folder names from the server (Posta in arrivo, Gesendet, Messages envoyés, Enviados, …) are mapped to Inbox/Sent/… in the UI language.
|
||
|
||
## Downloads
|
||
|
||
When a GitHub Release exists: Windows portable zip and setup (`postclient-{version}.exe`, self-contained — no .NET SDK on the PC), Linux Flatpak, macOS DMG (`osx-arm64` and `osx-x64`). macOS builds are unsigned: first launch is **Open** from the context menu. WinGet listing comes later from the same setup exe.
|
||
|
||
### Linux (Flatpak)
|
||
|
||
GitHub releases include `postclient-{version}.flatpak` when the Windows release run finds WSL Debian + Flatpak builder.
|
||
|
||
```bash
|
||
flatpak install --user ./postclient-{version}.flatpak
|
||
flatpak run eu.postclient.desktop
|
||
```
|
||
|
||
## Run from source
|
||
|
||
```powershell
|
||
dotnet run --project src/MaksIT.PostClient.UI
|
||
```
|
||
|
||
From `src/` so `global.json` applies:
|
||
|
||
```powershell
|
||
cd src
|
||
dotnet build MaksIT.PostClient.slnx
|
||
```
|
||
|
||
## Tests
|
||
|
||
```powershell
|
||
utils\Invoke-TestEngine.bat
|
||
```
|
||
|
||
Coverage shields at the top of this file are maintained by the test engine (**CoverageBadges**).
|
||
|
||
## Release
|
||
|
||
1. Update [CHANGELOG.md](CHANGELOG.md) and bump `<Version>` in [src/Directory.Build.props](src/Directory.Build.props).
|
||
2. Tag `v{version}` on `main` when a remote exists.
|
||
3. Run `utils\Invoke-ReleasePackage.bat` (self-contained Windows zip + setup exe, Linux Flatpak via WSL). Publishing the GitHub Release starts [macOS release assets](.github/workflows/macos-release.yml), which attaches unsigned `osx-arm64` and `osx-x64` DMGs.
|
||
|
||
## License
|
||
|
||
Apache License 2.0. Copyright 2026 Maksym Sadovnychyy (MAKS-IT).
|