Compare commits

..

4 Commits

Author SHA1 Message Date
45824c14ae config changes 2026-01-30 15:40:07 +01:00
2fb174ccc4 update 2026-01-30 13:23:49 +01:00
2100ab916c .putzen 2026-01-30 12:36:27 +01:00
b0e5318ae6 ufw rules 2026-01-30 12:27:46 +01:00
17 changed files with 572 additions and 44 deletions

View File

@@ -0,0 +1,30 @@
server {
server_name admin.matrix.home.meszely.eu;
location / {
proxy_pass http://10.11.3.161:80;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/admin.matrix.home.meszely.eu/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/admin.matrix.home.meszely.eu/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = admin.matrix.home.meszely.eu) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name admin.matrix.home.meszely.eu;
return 404; # managed by Certbot
}

View File

@@ -0,0 +1,39 @@
server {
server_name gitea.home.meszely.eu;
# Ezt a sort is kommentezd ki most:
# return 301 https://$host$request_uri;
# Az Nginx-nek tudnia kell, hova tegye a Certbot challenge fájlját.
# Ha nincs beállítva root, ideiglenesen adjunk meg egyet.
# Ez a location blokk elegendő a Certbotnak.
location / {
proxy_pass http://10.11.3.98:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
client_max_body_size 500M;
proxy_read_timeout 300s;
}
listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/gitea.home.meszely.eu/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/gitea.home.meszely.eu/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = gitea.home.meszely.eu) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
listen [::]:80;
server_name gitea.home.meszely.eu;
return 404; # managed by Certbot
}

View File

@@ -0,0 +1,35 @@
server {
server_name n8n.home.meszely.eu;
location / {
proxy_pass http://10.11.3.199:5678;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
listen 80;
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/n8n.home.meszely.eu/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/n8n.home.meszely.eu/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = n8n.home.meszely.eu) {
return 301 https://$host$request_uri;
} # managed by Certbot
server_name n8n.home.meszely.eu;
listen 80;
return 404; # managed by Certbot
}

View File

@@ -0,0 +1,31 @@
server {
server_name matrix.home.meszely.eu;
client_max_body_size 10M;
location / {
proxy_pass http://10.11.3.160:8008;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/matrix.home.meszely.eu/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/matrix.home.meszely.eu/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = matrix.home.meszely.eu) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name matrix.home.meszely.eu;
return 404; # managed by Certbot
}

View File

@@ -0,0 +1,9 @@
docker run -it --rm --mount type=volume,src=synapse-data,dst=/data -e SYNAPSE_SERVER_NAME=matrix.meszely.eu -e SYNAPSE_REPORT_STATS=yes matrixdotorg/synapse:latest generate
docker run -d --name synapse --mount type=volume,src=synapse-data,dst=/data -p 8008:8008 matrixdotorg/synapse:latest
# uj felhasznälo
docker exec -it synapse register_new_matrix_user -c /data/homeserver.yaml http://localhost:8008
# wpanda
# EsT4 x9g5 C5fy mQ8N wwN3 VBTh EnqF n8un rZ4K 8Czv mYWr 7T1u

View File

@@ -0,0 +1,22 @@
# Basic UFW Rules
#
# First Reset
sudo ufw --force reset
# Allow SSH
sudo ufw allow ssh
# Allow HTTP
sudo ufw allow 80/tcp
# Allow HTTPS
sudo ufw allow 443/tcp
# Allow N8N
sudo ufw allow 5678/tcp
# Deny all other incoming traffic
sudo ufw default deny incoming
# Allow all outgoing traffic
sudo ufw default allow outgoing

View File

@@ -10,29 +10,5 @@ https://www.tc-telefon.de/Kontakt/
5. 5.
6. Druckers Konfig to smtp_relay
+ Weser
+ Elbe
+ Aalbek
+ Hellbach
+ Lottbek
+ Zorge
+ Goldbach
+ Flottbek
+ Hamme
Alster ?
Ahr_Struensee-Haus
- Seseke
- Juemme
- Radegast
Steinbach
Nonne
- Eider
- Enz
- Orthbrookgraben
- Siede
verbung@meszely.eu verbung@meszely.eu
ionOs#6774#IonOs ionOs#6774#IonOs

View File

@@ -148,12 +148,6 @@ SOIB2026STD!
KXBPK-6QNPK-93C3C-7KKVG-GMT44 KXBPK-6QNPK-93C3C-7KKVG-GMT44
# Ispconfig
[INFO] Your ISPConfig admin password is: nqhHDGE5mDAmMpN
[INFO] Your MySQL root password is: unKdKpZJyCAzM5W8kuKb
[INFO] Warning: Please delete the log files in /root/ispconfig-install-log/setup-* once you don't need them anymore because they contain your passwords!
Herr Werther Rainer Herr Werther Rainer
0172 9428000 0172 9428000
@@ -167,3 +161,10 @@ hipas
Security .. Mario , akku defekt... Spranke... Security .. Mario , akku defekt... Spranke...
uptmerobot@meszely.eu
virgI
u3239099-556320ad0c63c591a7742a47
verbung@meszely.eu
ionOs#6774#IonOs

View File

@@ -24,19 +24,5 @@ aps\svc.scan2home
Dein anwendungsspezifisches Passwort lautet: Dein anwendungsspezifisches Passwort lautet:
xqol-fwhb-cmnb-vgac xqol-fwhb-cmnb-vgac
Horstmann, Claudia
Kotevski, Filip
Lullo, Stefania
Molle, Anja
Daniel, Schulze
Bayraktar, Betül
Bryce, Andrew C.
Jürgensen, Sven
-------------------
Spiller, Britta
Jacqueline Bethcke
Marie Scheithauer
APS-FILE02 APS-FILE02
User$\p.heinrich\_Scans User$\p.heinrich\_Scans

29
Doc/drucker-aufgabe.md Normal file
View File

@@ -0,0 +1,29 @@
+ Angel
+ Aalbek
+ Beek
Donau
+ Eider
+ Elbe
+ Emmer
+ Ems
Enz
+ Fintau
+ Flottbek
+ Goldbach
+ Hamme
+ Hellbach
+ Jasenitz
+ Juemme
+ Linde
+ Orthbrookgraben
+ Lottbek
+ Bille
+ Iller
Ahr_Struensee-Haus
+ Müritz
+ Weser
+ Radegast
+ Seseke
+ Siede
+ Zorge
Elbe 01 - Stuensee - Haus

45
GEMINI_o365_app.md Normal file
View File

@@ -0,0 +1,45 @@
# Microsoft 365 App-Registrierung für Skripte (OAuth 2.0)
Diese Anleitung beschreibt die notwendigen Schritte, um eine Anwendung im Microsoft Entra Admin Center zu registrieren. Dies ermöglicht Skripten und anderen Anwendungen den sicheren Zugriff auf Microsoft 365-Dienste (wie z. B. E-Mails über die Graph-API) mittels OAuth 2.0-Authentifizierung.
---
### Praktische Schritte
Diese Schritte müssen von einem globalen Administrator oder einem Benutzer mit entsprechenden Berechtigungen im [Microsoft Entra Admin Center](https://entra.microsoft.com/) durchgeführt werden.
**Schritt 1: Anwendungsregistrierung**
1. Öffnen Sie das **Microsoft Entra Admin Center**.
2. Navigieren Sie zu: **Identität** > **Anwendungen** > **App-Registrierungen** (Identity > Applications > App registrations).
3. Klicken Sie auf **+ Neue Registrierung** (+ New registration).
4. **Name:** Geben Sie einen aussagekräftigen Namen ein, z. B. `Python PDF Downloader Skript`.
5. **Unterstützte Kontotypen:** Wählen Sie die Standardeinstellung: `Nur Konten in diesem Organisationsverzeichnis (...)` (Accounts in this organizational directory only).
6. Den Abschnitt **Umleitungs-URI** (Redirect URI) können Sie leer lassen, da es sich um eine Hintergrundanwendung handelt.
7. Klicken Sie auf **Registrieren** (Register).
**Schritt 2: API-Berechtigungen festlegen**
1. Wählen Sie in der neu registrierten Anwendung das Menü **API-Berechtigungen** (API permissions).
2. Klicken Sie auf **+ Berechtigung hinzufügen** (+ Add a permission).
3. Wählen Sie **Microsoft Graph**.
4. Wählen Sie die Option **Anwendungsberechtigungen** (Application permissions). (WICHTIG: Nicht `Delegierte Berechtigungen`, da das Skript eigenständig und nicht im Namen eines Benutzers ausgeführt wird).
5. Geben Sie im Suchfeld `Mail` ein. Wählen Sie die Berechtigung **Mail.Read**. Wenn Ihr Skript E-Mails auch ändern soll (z. B. als gelesen markieren), benötigen Sie zusätzlich `Mail.ReadWrite`. Für den Anfang genügt `Mail.Read`.
6. Klicken Sie auf **Berechtigungen hinzufügen** (Add permissions).
7. **WICHTIGER SCHRITT:** Sie sehen eine Warnmeldung. Klicken Sie auf die Schaltfläche **`Administratorzustimmung für [Ihr Firmenname] erteilen`** (Grant admin consent for...) und bestätigen Sie das Dialogfeld. Ohne diesen Schritt sind die Berechtigungen nicht aktiv. Neben den Berechtigungen sollte danach ein grünes Häkchen erscheinen.
**Schritt 3: Client-Geheimnis erstellen (Client Secret)**
1. Navigieren Sie in der Anwendung zum Menü **Zertifikate & Geheimnisse** (Certificates & secrets).
2. Klicken Sie auf **+ Neues Client-Geheimnis** (+ New client secret).
3. Geben Sie eine Beschreibung ein (z. B. `skript_secret_v1`) und wählen Sie eine Gültigkeitsdauer (z. B. 12 Monate).
4. Klicken Sie auf **Hinzufügen** (Add).
5. **KRITISCH WICHTIG:** Der geheime Schlüssel wird nun in der Spalte **Wert** (Value) angezeigt. **Kopieren Sie diesen Wert sofort und speichern Sie ihn an einem sicheren Ort (z. B. in einem Passwort-Manager)! Nachdem Sie die Seite verlassen haben, kann der Wert nie wieder vollständig angezeigt werden, und Sie müssen einen neuen erstellen.**
**Schritt 4: Notwendige Daten sammeln**
Sie haben nun alle erforderlichen Informationen für Ihr Skript. Gehen Sie zur **Übersichtsseite** (Overview) Ihrer Anwendung. Sie benötigen die folgenden drei Informationen:
1. **Anwendungs- (Client-) ID** (Application (client) ID)
2. **Verzeichnis- (Mandanten-) ID** (Directory (tenant) ID)
3. **Den Wert des Client-Geheimnisses** (Client Secret Value), den Sie in Schritt 3 kopiert und gespeichert haben.

View File

@@ -0,0 +1,13 @@
curl -fsSL https://tailscale.com/install.sh | sh
tailscale up
echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.d/99-tailscale.conf
echo 'net.ipv6.conf.all.forwarding = 1' | sudo tee -a /etc/sysctl.d/99-tailscale.conf
sudo sysctl -p /etc/sysctl.d/99-tailscale.conf
sudo tailscale set --advertise-routes=10.11.0.0/22
sudo tailscale set --accept-routes
sudo tailscale set --advertise-exit-node

View File

@@ -0,0 +1,156 @@
import os
import requests
import msal
import base64
# ==============================================================================
# KONFIGURÁCIÓ
# ==============================================================================
# Az Azure App Registration-ból kapott adatok
TENANT_ID = "TENANT_ID_MASOLD_BE_IDE"
CLIENT_ID = "CLIENT_ID_MASOLD_BE_IDE"
CLIENT_SECRET = "CLIENT_SECRET_MASOLD_BE_IDE" # A "Value", nem a "Secret ID"
# A postafiók, amit figyelni kell
USER_EMAIL = "Bestellung-Fax-Eingang@aps-hh.de"
# Hova mentsük a letöltött PDF-eket
DOWNLOAD_DIR = r"\\aps-nb090\test"
# A mappa neve, ahova a feldolgozott leveleket helyezzük
PROCESSED_FOLDER_NAME = "erledigt"
# ==============================================================================
# Microsoft Graph API végpontok
GRAPH_API_ENDPOINT = "https://graph.microsoft.com/v1.0"
AUTHORITY_URL = f"https://login.microsoftonline.com/{TENANT_ID}"
SCOPES = ["https://graph.microsoft.com/.default"]
def get_graph_api_token():
"""Beszerzi a hozzáférési tokent a Microsoft Graph API-hoz."""
app = msal.ConfidentialClientApplication(
client_id=CLIENT_ID,
authority=AUTHORITY_URL,
client_credential=CLIENT_SECRET
)
result = app.acquire_token_silent(scopes=SCOPES, account=None)
if not result:
result = app.acquire_token_for_client(scopes=SCOPES)
if "access_token" in result:
return result["access_token"]
else:
print("Hiba a token beszerzése során!")
print(result.get("error"))
print(result.get("error_description"))
return None
def get_folder_id(access_token, folder_name):
"""Megkeresi egy mappa ID-ját a neve alapján."""
headers = {"Authorization": f"Bearer {access_token}"}
url = f"{GRAPH_API_ENDPOINT}/users/{USER_EMAIL}/mailFolders"
response = requests.get(url, headers=headers)
response.raise_for_status()
folders = response.json().get("value", [])
for folder in folders:
if folder["displayName"].lower() == folder_name.lower():
return folder["id"]
# Kezelhetnénk azt az esetet is, ha a mappa nem létezik, és létrehoznánk.
# Most egyszerűen hibát dobunk.
raise ValueError(f"A '{folder_name}' mappa nem található.")
def main():
"""Fő feldolgozó funkció."""
print("Graph API token beszerzése...")
access_token = get_graph_api_token()
if not access_token:
return
headers = {"Authorization": f"Bearer {access_token}"}
try:
print(f"'{PROCESSED_FOLDER_NAME}' mappa ID-jának keresése...")
processed_folder_id = get_folder_id(access_token, PROCESSED_FOLDER_NAME)
print("Mappa ID sikeresen lekérve.")
except (requests.HTTPError, ValueError) as e:
print(f"Hiba a mappa ID lekérése közben: {e}")
return
# Csak az olvasatlan, csatolmánnyal rendelkező levelek lekérdezése
# $select=id,subject -> Csak a szükséges mezőket kérjük le a hatékonyságért
messages_url = (
f"{GRAPH_API_ENDPOINT}/users/{USER_EMAIL}/mailFolders/inbox/messages?"
"$filter=isRead eq false and hasAttachments eq true&"
"$select=id,subject"
)
response = requests.get(messages_url, headers=headers)
response.raise_for_status()
messages = response.json().get("value", [])
if not messages:
print("Nincsenek új, feldolgozandó e-mailek.")
return
print(f"{len(messages)} új e-mail található csatolmánnyal.")
for message in messages:
msg_id = message["id"]
subject = message.get("subject", "N/A")
print(f"\n--- Feldolgozás alatt: '{subject}' (ID: {msg_id}) ---")
attachments_url = f"{GRAPH_API_ENDPOINT}/users/{USER_EMAIL}/messages/{msg_id}/attachments"
response = requests.get(attachments_url, headers=headers)
if response.status_code != 200:
print(f" Hiba a csatolmányok lekérésekor: {response.json()}")
continue
attachments = response.json().get("value", [])
pdf_found = False
for att in attachments:
filename = att.get("name", "unknown")
content_type = att.get("contentType", "")
if filename.lower().endswith(".pdf") or content_type == "application/pdf":
print(f" PDF csatolmány található: {filename}")
# A csatolmány tartalma a 'contentBytes' mezőben van, Base64 kódolással
file_content = base64.b64decode(att["contentBytes"])
# Fájlnév "tisztítása"
safe_filename = "".join(c if c.isalnum() or c in (" ", ".", "_", "-") else "_" for c in filename)
filepath = os.path.join(DOWNLOAD_DIR, safe_filename)
try:
with open(filepath, "wb") as f:
f.write(file_content)
print(f" PDF sikeresen mentve: {filepath}")
pdf_found = True
except Exception as e:
print(f" Hiba a fájl mentése közben: {e}")
if pdf_found:
print(f" E-mail áthelyezése a '{PROCESSED_FOLDER_NAME}' mappába...")
move_url = f"{GRAPH_API_ENDPOINT}/users/{USER_EMAIL}/messages/{msg_id}/move"
move_payload = {"destinationId": processed_folder_id}
response = requests.post(move_url, headers=headers, json=move_payload)
if response.status_code == 201:
print(" E-mail sikeresen áthelyezve.")
else:
# Az áthelyezéshez Mail.ReadWrite jogosultság kell!
print(f" Hiba az e-mail áthelyezésekor: {response.status_code} - {response.text}")
print("\nFeldolgozás befejezve.")
if __name__ == "__main__":
if not os.path.exists(DOWNLOAD_DIR):
print(f"Hiba: A letöltési mappa nem létezik: {DOWNLOAD_DIR}")
else:
main()

156
import_pdf_from_o365_de.py Normal file
View File

@@ -0,0 +1,156 @@
import os
import requests
import msal
import base64
# ==============================================================================
# KONFIGURATION
# ==============================================================================
# Daten aus der Azure App-Registrierung
TENANT_ID = "TENANT_ID_HIER_EINFUEGEN"
CLIENT_ID = "CLIENT_ID_HIER_EINFUEGEN"
CLIENT_SECRET = "CLIENT_SECRET_HIER_EINFUEGEN" # Der "Wert", nicht die "Secret ID"
# Das zu überwachende Postfach
USER_EMAIL = "Bestellung-Fax-Eingang@aps-hh.de"
# Speicherort für heruntergeladene PDFs
DOWNLOAD_DIR = r"\\aps-nb090\test"
# Name des Ordners, in den verarbeitete E-Mails verschoben werden
PROCESSED_FOLDER_NAME = "erledigt"
# ==============================================================================
# Microsoft Graph API Endpunkte
GRAPH_API_ENDPOINT = "https://graph.microsoft.com/v1.0"
AUTHORITY_URL = f"https://login.microsoftonline.com/{TENANT_ID}"
SCOPES = ["https://graph.microsoft.com/.default"]
def get_graph_api_token():
"""Ruft das Zugriffstoken für die Microsoft Graph API ab."""
app = msal.ConfidentialClientApplication(
client_id=CLIENT_ID,
authority=AUTHORITY_URL,
client_credential=CLIENT_SECRET
)
result = app.acquire_token_silent(scopes=SCOPES, account=None)
if not result:
result = app.acquire_token_for_client(scopes=SCOPES)
if "access_token" in result:
return result["access_token"]
else:
print("Fehler beim Abrufen des Tokens!")
print(result.get("error"))
print(result.get("error_description"))
return None
def get_folder_id(access_token, folder_name):
"""Sucht die ID eines Ordners anhand seines Namens."""
headers = {"Authorization": f"Bearer {access_token}"}
url = f"{GRAPH_API_ENDPOINT}/users/{USER_EMAIL}/mailFolders"
response = requests.get(url, headers=headers)
response.raise_for_status()
folders = response.json().get("value", [])
for folder in folders:
if folder["displayName"].lower() == folder_name.lower():
return folder["id"]
# Man könnte auch den Fall behandeln, dass der Ordner nicht existiert, und ihn erstellen.
# Vorerst wird einfach ein Fehler ausgelöst.
raise ValueError(f"Der Ordner '{folder_name}' wurde nicht gefunden.")
def main():
"""Hauptverarbeitungsfunktion."""
print("Graph API-Token wird abgerufen...")
access_token = get_graph_api_token()
if not access_token:
return
headers = {"Authorization": f"Bearer {access_token}"}
try:
print(f"Suche nach der ID für den Ordner '{PROCESSED_FOLDER_NAME}'...")
processed_folder_id = get_folder_id(access_token, PROCESSED_FOLDER_NAME)
print("Ordner-ID erfolgreich abgerufen.")
except (requests.HTTPError, ValueError) as e:
print(f"Fehler beim Abrufen der Ordner-ID: {e}")
return
# Nur ungelesene E-Mails mit Anhängen abfragen
# $select=id,subject -> Nur die notwendigen Felder für mehr Effizienz abfragen
messages_url = (
f"{GRAPH_API_ENDPOINT}/users/{USER_EMAIL}/mailFolders/inbox/messages?"
f"$filter=isRead eq false and hasAttachments eq true&"
f"$select=id,subject"
)
response = requests.get(messages_url, headers=headers)
response.raise_for_status()
messages = response.json().get("value", [])
if not messages:
print("Keine neuen E-Mails zur Verarbeitung gefunden.")
return
print(f"{len(messages)} neue E-Mail(s) mit Anhängen gefunden.")
for message in messages:
msg_id = message["id"]
subject = message.get("subject", "N/A")
print(f"\n--- In Verarbeitung: '{subject}' (ID: {msg_id}) ---")
attachments_url = f"{GRAPH_API_ENDPOINT}/users/{USER_EMAIL}/messages/{msg_id}/attachments"
response = requests.get(attachments_url, headers=headers)
if response.status_code != 200:
print(f" Fehler beim Abrufen der Anhänge: {response.json()}")
continue
attachments = response.json().get("value", [])
pdf_found = False
for att in attachments:
filename = att.get("name", "unknown")
content_type = att.get("contentType", "")
if filename.lower().endswith(".pdf") or content_type == "application/pdf":
print(f" PDF-Anhang gefunden: {filename}")
# Der Inhalt des Anhangs befindet sich im Feld 'contentBytes' und ist Base64-kodiert
file_content = base64.b64decode(att["contentBytes"])
# Dateinamen bereinigen
safe_filename = "".join(c if c.isalnum() or c in (" ", ".", "_", "-") else "_" for c in filename)
filepath = os.path.join(DOWNLOAD_DIR, safe_filename)
try:
with open(filepath, "wb") as f:
f.write(file_content)
print(f" PDF erfolgreich gespeichert: {filepath}")
pdf_found = True
except Exception as e:
print(f" Fehler beim Speichern der Datei: {e}")
if pdf_found:
print(f" E-Mail wird in den Ordner '{PROCESSED_FOLDER_NAME}' verschoben...")
move_url = f"{GRAPH_API_ENDPOINT}/users/{USER_EMAIL}/messages/{msg_id}/move"
move_payload = {"destinationId": processed_folder_id}
response = requests.post(move_url, headers=headers, json=move_payload)
if response.status_code == 201:
print(" E-Mail erfolgreich verschoben.")
else:
# Für das Verschieben ist die Berechtigung Mail.ReadWrite erforderlich!
print(f" Fehler beim Verschieben der E-Mail: {response.status_code} - {response.text}")
print("\nVerarbeitung abgeschlossen.")
if __name__ == "__main__":
if not os.path.exists(DOWNLOAD_DIR):
print(f"Fehler: Der Download-Ordner existiert nicht: {DOWNLOAD_DIR}")
else:
main()