Files
SMTPGraphRelay/README.md
T

864 lines
14 KiB
Markdown

# SMTPGraphRelay
SMTPGraphRelay ist ein nativer Windows-SMTP-Relay für interne Geräte und Anwendungen.
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.
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.
---
## Ü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
$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
```
Der Bootstrap-Installer lädt automatisch den aktuellen Stand aus dem Gitea-Repository und installiert SMTPGraphRelay nach:
```text
C:\Program Files\SMTPGraphRelay
```
Es muss kein ZIP manuell heruntergeladen oder entpackt werden.
---
# Setup / Manager
Nach dem Start erscheint das Verwaltungsmenü:
```text
[1] Neuinstallation aus Gitea
[2] Installation aus Gitea reparieren
[3] Nach Online-Updates suchen
[4] Entra / Exchange RBAC prüfen
[5] Zertifikat erneuern
[6] Health Check ausführen
[7] Deinstallieren
[8] Status anzeigen
[9] SMTP-AUTH verwalten
[10] Failed Queue verwalten
[11] Failure-Mode QA
[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.