Dateien nach "/" hochladen

This commit is contained in:
2026-08-14 23:11:41 +02:00
parent 14672c3a9a
commit 70afda86bf
+832 -125
View File
@@ -1,145 +1,58 @@
# SMTPGraphRelay 1.8.0 # SMTPGraphRelay
V1.8 ergänzt zwei Betriebsfunktionen: SMTPGraphRelay ist ein nativer Windows-SMTP-Relay für interne Geräte und Anwendungen.
- Failed-Queue-Verwaltung im Setup-/Manager Er nimmt klassische SMTP-Mails von Druckern, Scannern, NAS-Systemen, Servern, Monitoring-Tools und anderen Legacy-Geräten entgegen und versendet sie anschließend über **Microsoft Graph** mit **App-only OAuth2** über Microsoft 365.
- kooperativer Graceful Shutdown für Update, Repair und manuelles Stoppen über den Manager
Alle Funktionen aus V1.7 bleiben erhalten, insbesondere SMTP AUTH LOGIN/PLAIN, Der Relay läuft vollständig unter **Windows PowerShell 5.1** und benötigt keinen Docker-Container, keinen lokalen Exchange-Server und keinen klassischen SMTP-Smarthost.
Queue-ID, Retry/Backpressure, Zertifikatsrotation, Health Check und Online-Update.
## Installation ---
**Windows PowerShell 5.1 als Administrator**: ## Überblick
```text
Drucker / Scanner / NAS / Server / Monitoring
|
| SMTP
v
SMTPGraphRelay
|
| Store-and-Forward Queue
v
Microsoft Graph
|
| OAuth2 App-only
v
Microsoft 365
```
SMTPGraphRelay wurde für den Betrieb in internen Netzwerken entwickelt.
---
# Installation
## Schnellinstallation
Auf dem Zielsystem **Windows PowerShell 5.1 als Administrator** öffnen und ausführen:
```powershell ```powershell
$u='https://me-gitea.maieredv.cloud/MAIEREDV/SMTPGraphRelay/raw/branch/main/Setup-SMTPGraphRelay.ps1';$f="$env:TEMP\Setup-SMTPGraphRelay.ps1";Invoke-WebRequest $u -UseBasicParsing -OutFile $f;& $f $u='https://me-gitea.maieredv.cloud/MAIEREDV/SMTPGraphRelay/raw/branch/main/Setup-SMTPGraphRelay.ps1';$f="$env:TEMP\Setup-SMTPGraphRelay.ps1";Invoke-WebRequest $u -UseBasicParsing -OutFile $f;& $f
``` ```
## Failed Queue verwalten Der Bootstrap-Installer lädt automatisch den aktuellen Stand aus dem Gitea-Repository und installiert SMTPGraphRelay nach:
Im Manager:
```text ```text
[10] Failed Queue verwalten C:\Program Files\SMTPGraphRelay
``` ```
Untermenü: Es muss kein ZIP manuell heruntergeladen oder entpackt werden.
```text ---
[1] Failed Queue anzeigen
[2] Details einer Mail anzeigen
[3] Eine Mail erneut zustellen
[4] Alle Mails erneut zustellen
[5] Eine Mail endgültig löschen
[6] Alle Failed-Mails endgültig löschen
[0] Zurück
```
Die Übersicht zeigt u. a.: # Setup / Manager
- Queue-ID Nach dem Start erscheint das Verwaltungsmenü:
- Zeitpunkt
- RetryCount
- Envelope-From
- Empfänger
- letzten HTTP-/Graph-Status
- Größe
In den Details steht zusätzlich die letzte Fehlermeldung und falls vorhanden
der SMTP-AUTH-Benutzer.
### Requeue
Beim erneuten Zustellen wird die `.eml` samt Metadaten von `failed` nach
`queue\pending` verschoben.
Dabei werden:
```text
RetryCount = 0
NextAttemptUtc = jetzt
RequeuedUtc = jetzt
```
gesetzt. Die alte Fehlerbeschreibung bleibt in den Metadaten erhalten, bis ein
neuer Versandversuch sie aktualisiert.
Der laufende Queue-Worker nimmt die Mail anschließend automatisch wieder auf.
## Graceful Shutdown
Update und Repair verwenden nicht mehr zuerst `Stop-ScheduledTask`.
Stattdessen erstellt der Manager:
```text
C:\Program Files\SMTPGraphRelay\shutdown.request
```
Der Relay erkennt das Signal kurzfristig und führt diesen Ablauf aus:
```text
Shutdown angefordert
|
v
SMTP-Listener schließen
|
+--> keine neuen Verbindungen mehr
|
v
laufende SMTP-Sessions auslaufen lassen
|
v
Queue-/Graph-Worker beendet aktuellen Versand
|
+--> startet keine weitere Queue-Mail
|
v
Runspaces schließen
|
v
Graph-Verbindung trennen
|
v
Relay beendet sich selbst
```
Standard-Timeout:
```json
"Smtp": {
"GracefulShutdownSeconds": 30
}
```
Zulässiger Bereich:
```text
5 bis 300 Sekunden
```
Wenn der Relay innerhalb dieses Zeitraums nicht selbst beendet ist, verwendet
der Manager als Fallback einen harten `Stop-ScheduledTask`.
Beim nächsten Start wird ein eventuell altes `shutdown.request` vorsorglich
entfernt.
## Warum das für Updates wichtig ist
Ein Update/Repair kann damit nicht mehr unnötig mitten in:
- einer SMTP-DATA-Übertragung
- einer aktiven SMTP-Session
- oder einem laufenden Graph-sendMail-Aufruf
den Prozess beenden.
Wenn ein Client oder Graph länger als das konfigurierte Grace-Timeout hängt,
wird nach Ablauf des Timeouts kontrolliert auf den bisherigen harten Stop
zurückgefallen.
## Manager
```text ```text
[1] Neuinstallation aus Gitea [1] Neuinstallation aus Gitea
@@ -152,5 +65,799 @@ zurückgefallen.
[8] Status anzeigen [8] Status anzeigen
[9] SMTP-AUTH verwalten [9] SMTP-AUTH verwalten
[10] Failed Queue verwalten [10] Failed Queue verwalten
[11] Failure-Mode QA
[0] Beenden [0] Beenden
``` ```
---
# Neuinstallation
Die Neuinstallation erledigt automatisch:
- Prüfung auf Windows PowerShell 5.1
- Prüfung auf Administratorrechte
- Download der aktuellen Programmdateien aus Gitea
- Installation nach `C:\Program Files\SMTPGraphRelay`
- Installation der benötigten Microsoft-Graph-PowerShell-Module
- Installation von `ExchangeOnlineManagement`
- Erstellung eines lokalen Zertifikats
- Erstellung der Entra ID App Registration
- Erstellung des Entra Service Principals
- Einrichtung von Exchange Online Application RBAC
- Beschränkung von `Application Mail.Send` auf das konfigurierte Absenderpostfach
- Erstellung der `config.json`
- Erstellung der Queue-/Failed-/Log-Verzeichnisse
- Erstellung der Windows-Firewallregel
- Erstellung des Scheduled Tasks unter `SYSTEM`
- Start des Relay
- abschließender Health Check
---
# Microsoft 365 / Graph
SMTPGraphRelay verwendet Microsoft Graph mit App-only Authentifizierung.
Der Versand erfolgt über:
```text
POST /v1.0/users/<SenderMailbox>/sendMail
```
Die Authentifizierung erfolgt mit:
```text
Tenant ID
Client ID
Certificate Thumbprint
```
Es wird kein Client Secret verwendet.
---
# Exchange Application RBAC
Der Relay verwendet bewusst **keine tenantweite Microsoft Graph `Mail.Send` Application Permission**.
Stattdessen wird Exchange Online Application RBAC verwendet:
```text
Application Mail.Send
|
v
Custom Resource Scope
|
v
konfiguriertes SenderMailbox
```
Beispiel:
```text
SMTPGraphRelay App
|
| Application Mail.Send
v
info@example.com
```
Dadurch kann die Anwendung ausschließlich über das konfigurierte Absenderpostfach senden.
---
# Zertifikatsauthentifizierung
Das Setup erzeugt ein RSA-Zertifikat unter:
```text
Cert:\LocalMachine\My
```
Eigenschaften:
```text
RSA 2048
SHA256
Private Key nicht exportierbar
Gültigkeit: 2 Jahre
```
Der Relay überwacht die Zertifikatslaufzeit regelmäßig.
Standard:
```text
Warnung: 60 Tage
Kritisch: 14 Tage
Prüfung: alle 12 Stunden
```
Das Zertifikat kann über den Manager erneuert werden:
```text
[5] Zertifikat erneuern
```
Die Rotation erfolgt mit Überlappung:
```text
altes Zertifikat
|
v
neues Zertifikat erstellen
|
v
neues Credential zusätzlich in Entra hinterlegen
|
v
App-only Login mit neuem Zertifikat testen
|
v
config.json auf neues Zertifikat umstellen
|
v
Relay neu starten
|
v
altes Zertifikat optional entfernen
```
---
# SMTP-Funktionen
Unterstützte SMTP-Kommandos:
```text
EHLO
HELO
MAIL FROM
RCPT TO
DATA
RSET
NOOP
QUIT
AUTH LOGIN
AUTH PLAIN
```
STARTTLS wird bewusst nicht verwendet, da SMTPGraphRelay für interne, vertrauenswürdige Netzwerke vorgesehen ist.
---
# SMTP Listener
Standardmäßig:
```text
ListenAddress: 0.0.0.0
Port: 2525
```
Der Port kann in `config.json` geändert werden.
---
# IP-Allowlist
SMTPGraphRelay akzeptiert ausschließlich Clients aus konfigurierten Netzwerken.
Beispiel:
```json
"AllowedNetworks": [
"127.0.0.1/32",
"10.0.0.0/8",
"172.16.0.0/12",
"192.168.0.0/16"
]
```
Nicht erlaubte Hosts erhalten:
```text
554 5.7.1 Client not allowed
```
Die IP-Allowlist bleibt auch bei aktiviertem SMTP-AUTH immer die erste Zugriffskontrolle.
---
# SMTP-AUTH
SMTPGraphRelay unterstützt:
```text
AUTH LOGIN
AUTH PLAIN
```
SMTP-AUTH kann optional oder verpflichtend aktiviert werden.
Beispiel:
```json
"RequireAuth": true
```
Clients ohne erfolgreiche Authentifizierung erhalten dann:
```text
530 5.7.0 Authentication required
```
Erfolgreiche Anmeldung:
```text
235 2.7.0 Authentication successful
```
Fehlgeschlagene Anmeldung:
```text
535 5.7.8 Authentication credentials invalid
```
Nach mehreren Fehlversuchen kann die Verbindung temporär gesperrt werden:
```text
454 4.7.0 Too many authentication failures
```
Standard:
```text
AuthMaxFailures = 5
```
---
# SMTP-Benutzerverwaltung
Im Manager:
```text
[9] SMTP-AUTH verwalten
```
Funktionen:
```text
[1] SMTP-AUTH erforderlich EIN/AUS
[2] Benutzer hinzufügen
[3] Benutzer anzeigen
[4] Passwort ändern
[5] Benutzer löschen
[6] Netze ohne Auth verwalten
[7] Max. Fehlversuche ändern
[0] Zurück
```
Passwörter werden nicht im Klartext gespeichert.
Verwendet wird:
```text
PBKDF2-HMAC-SHA256
zufälliger Salt
150000 Iterationen
32 Byte Hash
```
---
# AUTH-Ausnahmen
Bestimmte Netze können trotz `RequireAuth=true` ohne SMTP-AUTH zugelassen werden:
```json
"AllowUnauthenticatedNetworks": [
"10.60.10.0/24"
]
```
Diese Clients müssen trotzdem zusätzlich in `AllowedNetworks` enthalten sein.
---
# Absenderkontrolle
Der SMTP-Benutzer beeinflusst nicht den tatsächlichen Microsoft-365-Absender.
Mit:
```json
"ForceSender": true
```
wird immer `Graph.SenderMailbox` als Absender verwendet.
---
# Parallele SMTP-Verbindungen
SMTPGraphRelay verarbeitet mehrere SMTP-Clients parallel über einen PowerShell-Runspace-Pool.
Standard:
```text
MaxConcurrentClients = 20
```
Ist das Limit erreicht:
```text
421 4.3.2 SMTPGraphRelay busy, try again later
```
---
# SMTP-Limits
Standardwerte:
```text
MaxRecipients = 50
MaxMessagesPerConnection = 25
MaxMessageSizeMB = 25
```
Zu viele Empfänger:
```text
452 4.5.3 Too many recipients
```
Zu viele Nachrichten innerhalb einer Verbindung:
```text
452 4.5.3 Too many messages in this session
```
Zu große Nachricht:
```text
552 5.3.4 Message size exceeds fixed maximum message size
```
---
# Store-and-Forward Queue
Queue-Struktur:
```text
queue\
├── incoming\
├── pending\
└── processing\
failed\
```
- `incoming`: Nachricht wird atomar geschrieben.
- `pending`: vollständig gespeicherte, versandbereite Nachrichten.
- `processing`: aktuell durch den Graph-Worker verarbeitete Nachrichten.
- `failed`: dauerhaft fehlgeschlagene Nachrichten.
---
# Queue-ID
Jede Nachricht erhält eine eindeutige Queue-ID.
Beispiel:
```text
7F3A91C2D441
```
SMTP-Antwort:
```text
250 2.0.0 Message accepted for delivery; queue-id=7F3A91C2D441
```
Die Queue-ID wird ebenfalls in den Logs verwendet.
---
# Received-Header und Message-ID
SMTPGraphRelay fügt einen eigenen `Received:`-Header hinzu.
Besitzt eine eingehende Nachricht keine `Message-ID`, erzeugt der Relay automatisch eine.
Bereits vorhandene Message-IDs bleiben unverändert.
---
# Retry-Logik
Standard-Retry-Zeiten:
```text
1 Minute
5 Minuten
15 Minuten
30 Minuten
60 Minuten
120 Minuten
240 Minuten
480 Minuten
```
Standard:
```text
MaxRetries = 8
```
Automatische Wiederholung erfolgt bei:
```text
HTTP 408
HTTP 429
HTTP 5xx
DNS-Fehler
TLS-/Transportfehler
Timeouts
Netzwerkfehler
```
Bei `429 Too Many Requests` wird `Retry-After` berücksichtigt.
Typische permanente Fehler wie `400`, `401`, `403`, `404`, `409`, `410`, `412`, `413`, `415`, `422` und `423` werden direkt nach `failed` verschoben.
---
# Queue-Backpressure
Standard:
```text
MaxPendingMessages = 5000
MinFreeDiskSpaceMB = 1024
```
Queue-Limit erreicht:
```text
452 4.3.1 SMTPGraphRelay queue limit reached
```
Zu wenig freier Speicher:
```text
452 4.3.1 Insufficient system storage
```
Kann eine Nachricht nach `DATA` nicht atomar gespeichert werden:
```text
451 4.3.0 SMTPGraphRelay queue temporarily unavailable
```
---
# Failed Queue
Im Manager:
```text
[10] Failed Queue verwalten
```
Funktionen:
```text
[1] Failed Queue anzeigen
[2] Details einer Mail anzeigen
[3] Eine Mail erneut zustellen
[4] Alle Mails erneut zustellen
[5] Eine Mail endgültig löschen
[6] Alle Failed-Mails endgültig löschen
[0] Zurück
```
Beim erneuten Zustellen wird die Nachricht zurück nach `queue\pending` verschoben.
---
# Graceful Shutdown
Update, Repair und kontrollierte Stop-Vorgänge beenden den Relay nicht sofort hart.
Der Manager erzeugt:
```text
C:\Program Files\SMTPGraphRelay\shutdown.request
```
Der Relay schließt zuerst den Listener, nimmt keine neuen Verbindungen mehr an, lässt laufende SMTP-Sessions und den aktuellen Queue-/Graph-Versand auslaufen und beendet sich anschließend selbst.
Standard:
```text
GracefulShutdownSeconds = 30
```
Bei Timeout fällt der Manager auf einen harten Scheduled-Task-Stop zurück.
---
# Logging
Logdatei:
```text
C:\Program Files\SMTPGraphRelay\logs\SMTPGraphRelay.log
```
Log-Rotation:
```text
MaxFileSizeMB = 10
RetentionDays = 30
CleanupHours = 12
```
Archivierte Logs:
```text
SMTPGraphRelay-YYYYMMDD-HHMMSS.log
```
---
# Health Check
Im Manager:
```text
[6] Health Check ausführen
```
oder direkt:
```powershell
.\Test-SMTPGraphRelay.ps1
```
Geprüft werden unter anderem:
- Windows PowerShell 5.1
- Administratorstatus
- `config.json`
- Graph-PowerShell-Modul
- Zertifikat und Private Key
- Zertifikatslaufzeit
- Queue-Verzeichnisse und Schreibrechte
- Pending / Processing / Failed Queue
- Scheduled Task
- SMTP Listener
- Graph App-only Login
- SMTP-AUTH-Konfiguration
Exitcodes:
```text
0 = OK
1 = Warnung
2 = Fehler
```
---
# SMTP-Testmail
```powershell
.\Test-SMTPGraphRelay.ps1 `
-SendTestMail `
-TestRecipient "user@example.com"
```
Bei aktiviertem SMTP-AUTH:
```powershell
.\Test-SMTPGraphRelay.ps1 `
-SendTestMail `
-TestRecipient "user@example.com" `
-SmtpUsername "scanner01"
```
Das Passwort wird interaktiv und verdeckt abgefragt.
---
# Online Update
Im Manager:
```text
[3] Nach Online-Updates suchen
```
Der Manager prüft die `version.json` im Gitea-Repository und lädt bei einer neuen Version das aktuelle `main.zip`.
Vor dem Update werden die verwalteten Programmdateien gesichert.
Ablauf:
```text
Versionsprüfung
|
v
Repository laden
|
v
Backup
|
v
Graceful Shutdown
|
v
Programmdateien aktualisieren
|
v
Relay starten
|
v
Health Check
|
+--> Fehler -> automatischer Rollback
```
---
# Repair
Im Manager:
```text
[2] Installation aus Gitea reparieren
```
Repair lädt den aktuellen Programmstand erneut aus Gitea und stellt fehlende oder beschädigte Programmdateien wieder her.
Dabei bleiben erhalten:
```text
config.json
queue\
failed\
logs\
backup\
Zertifikat
Entra App Registration
Exchange Application RBAC
```
---
# Failure-Mode QA
Im Manager:
```text
[11] Failure-Mode QA
```
oder direkt:
```powershell
.\Test-SMTPGraphRelay-FailureModes.ps1
```
Tests:
```text
[1] Graph HTTP 429 / Retry testen
[2] Graph HTTP 500 / Retry testen
[3] Queue-Schreibfehler / SMTP 451 testen
[4] Pending-Queue-Backpressure / SMTP 452 testen
[5] Disk-Backpressure / SMTP 452 testen
[6] Graceful Shutdown während SMTP DATA testen
[7] Graceful Shutdown während Queue/Graph testen
[8] QA-/Debug-Block aus Config entfernen
[0] Beenden
```
Die ursprüngliche `config.json` wird vor jedem Test gesichert und anschließend automatisch wiederhergestellt.
---
# Scheduled Task
SMTPGraphRelay läuft als Scheduled Task unter:
```text
SYSTEM
```
Ausgeführt wird explizit:
```text
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
```
mit:
```text
-NoLogo
-NoProfile
-ExecutionPolicy Bypass
-File "C:\Program Files\SMTPGraphRelay\SMTPGraphRelay.ps1"
-ConfigPath "C:\Program Files\SMTPGraphRelay\config.json"
```
---
# Verzeichnisstruktur
```text
C:\Program Files\SMTPGraphRelay\
├── SMTPGraphRelay.ps1
├── Setup-SMTPGraphRelay.ps1
├── Test-SMTPGraphRelay.ps1
├── Test-SMTPGraphRelay-FailureModes.ps1
├── Renew-SMTPGraphRelayCertificate.ps1
├── version.json
├── config.json
├── queue\
│ ├── incoming\
│ ├── pending\
│ └── processing\
├── failed\
├── logs\
└── backup\
```
---
# Systemvoraussetzungen
- Windows 10 / Windows 11 oder Windows Server
- Windows PowerShell 5.1
- lokale Administratorrechte für Installation und Verwaltung
- Zugriff auf das Gitea-Repository
- Internetzugang zu Microsoft Entra ID
- Internetzugang zu Microsoft Graph
- Internetzugang zu Exchange Online
- Microsoft-365-/Exchange-Online-Postfach als Relay-Absender
- Entra-/Exchange-Administratorkonto für die Ersteinrichtung
---
# Repository
```text
https://me-gitea.maieredv.cloud/MAIEREDV/SMTPGraphRelay
```
---
# Betriebskonzept
SMTPGraphRelay ist für den internen Einsatz vorgesehen.
Empfohlene Absicherung:
```text
interne Netzwerksegmente
+
AllowedNetworks
+
optional SMTP-AUTH
+
ForceSender
+
Exchange Application RBAC
```
Dadurch bleibt sowohl der lokale Zugriff als auch der tatsächliche Microsoft-365-Versand klar eingeschränkt.