Eingangsrechnungen aus dem E-Mail-Postfach automatisch verarbeiten
PDF-Rechnungen aus IMAP-Postfächern automatisch extrahieren, per API in ZUGFeRD konvertieren und strukturiert ablegen. Mit Beispielen für n8n, Make und Python.
Vellonode Team
Redaktion
Das Problem: Rechnungen landen im Postfach und bleiben dort liegen
In den meisten Unternehmen kommen Eingangsrechnungen per E-Mail. Sie landen als PDF-Anhang in einem Sammelpostfach wie [email protected] — und dann beginnt die manuelle Arbeit: E-Mail öffnen, Anhang speichern, Rechnungsdaten abtippen, in die Buchhaltung übertragen.
Bei 20 Eingangsrechnungen im Monat ist das lästig. Bei 200 wird es zum Engpass. Und die Fehlerquote steigt mit dem Volumen: vertippte Beträge, übersehene Anhänge, falsche Zuordnungen.
Die Lösung: Postfach überwachen, API konvertieren, Daten weiterleiten
Die Idee ist einfach: Ein automatisierter Workflow überwacht das Rechnungspostfach, erkennt neue E-Mails mit PDF-Anhang, schickt das PDF an die Vellonode API und leitet die strukturierten Rechnungsdaten an das Zielsystem weiter — Buchhaltung, DMS, ERP oder eine einfache Tabelle.
Der Ablauf in vier Schritten:
- Trigger: Neue E-Mail mit PDF-Anhang im Postfach
- Extraktion: PDF an die Vellonode API senden
- Daten: Strukturiertes JSON mit allen Rechnungsfeldern zurückbekommen
- Aktion: Daten in das Zielsystem schreiben (DATEV, Buchhaltung, Tabelle, DMS)
Variante 1: Low-Code mit n8n oder Make
Wer keine eigene Software entwickelt, erreicht die Automatisierung mit Low-Code-Tools wie n8n (self-hosted) oder Make (ehemals Integromat).
n8n-Workflow
Der n8n-Workflow besteht aus vier Nodes:
1. IMAP Email Trigger — überwacht das Postfach und triggert bei neuen E-Mails. Konfiguration:
- Host: Ihr IMAP-Server (z.B.
imap.gmail.com) - Postfach:
INBOXoder ein Unterordner wieRechnungen - Polling-Intervall: alle 5 Minuten
2. IF-Node — filtert E-Mails ohne PDF-Anhang heraus. Bedingung: Anhang-Typ enthält application/pdf.
3. HTTP Request Node — sendet das PDF an die API:
- Method:
POST - URL:
https://vellonode.de/api/v1/invoices/convert?organizationId=IHRE_ORG_ID - Authentication: Header Auth →
Authorization: Bearer vk_live_... - Body: Form-Data
file: Binary-Daten des PDF-Anhangsformat:json
Hinweis: Die
organizationIdist ein Pflichtparameter. Sie erhalten Ihre Organisations-ID überGET /api/v1/organizations.
4. Aktion-Node — verarbeitet die Response. Zum Beispiel:
- Google Sheets: Neue Zeile mit Rechnungsnummer, Datum, Betrag, Lieferant
- Slack: Benachrichtigung an den Buchhaltungskanal
- DATEV: Datei in ein überwachtes Verzeichnis legen
- Webhook: Daten an ein eigenes System weiterleiten
In n8n können Sie den Binary-Anhang direkt aus dem IMAP-Node an den HTTP-Request-Node übergeben, ohne die Datei zwischenzuspeichern. Verwenden Sie die Expression {{ $binary.attachment_0 }} im File-Feld des HTTP-Nodes.
Make (Integromat) Szenario
Der Aufbau ist analog:
- Email → Watch Emails (Gmail, Outlook oder IMAP)
- Router → nur E-Mails mit PDF-Anhang
- HTTP → Make a Request (multipart/form-data POST an die API)
- JSON → Parse (Response parsen)
- Google Sheets / Airtable / Webhook (Daten schreiben)
Variante 2: Python-Script für volle Kontrolle
Für Entwickler oder Unternehmen mit eigener Infrastruktur ist ein Python-Script die flexibelste Lösung. Es überwacht ein IMAP-Postfach, extrahiert PDF-Anhänge und ruft die API auf.
import imaplib
import email
import requests
import json
import time
IMAP_HOST = "imap.ihre-firma.de"
IMAP_USER = "[email protected]"
IMAP_PASS = "***"
# organizationId ist ein Pflichtparameter – abrufbar über GET /api/v1/organizations
API_URL = "https://vellonode.de/api/v1/invoices/convert?organizationId=IHRE_ORG_ID"
API_KEY = "vk_live_IhrKeyHier"
def check_mailbox():
mail = imaplib.IMAP4_SSL(IMAP_HOST)
mail.login(IMAP_USER, IMAP_PASS)
mail.select("INBOX")
# Ungelesene E-Mails suchen
_, message_ids = mail.search(None, "UNSEEN")
for msg_id in message_ids[0].split():
_, msg_data = mail.fetch(msg_id, "(RFC822)")
msg = email.message_from_bytes(msg_data[0][1])
for part in msg.walk():
if part.get_content_type() == "application/pdf":
pdf_data = part.get_payload(decode=True)
filename = part.get_filename() or "rechnung.pdf"
print(f"Verarbeite: {filename}")
result = convert_invoice(pdf_data, filename)
if result:
process_result(result, msg)
mail.logout()
def convert_invoice(pdf_bytes, filename):
response = requests.post(
API_URL,
headers={"Authorization": f"Bearer {API_KEY}"},
files={"file": (filename, pdf_bytes, "application/pdf")},
data={"format": "zugferd,json"},
)
if response.status_code == 200:
return response.json()
print(f" Fehler: {response.status_code} - "
f"{response.text[:200]}")
return None
def process_result(result, original_email):
data = result["data"]
print(f" Rechnung: {data.get('invoiceNumber')}")
print(f" Lieferant: "
f"{data.get('seller', {}).get('name')}")
print(f" Betrag: {data.get('totals', {}).get('grossTotal')}"
f" {data.get('currency')}")
if result["validation"]["valid"]:
print(" Validierung: OK (EN16931)")
else:
errors = result["validation"]["errors"]
print(f" Validierung: {len(errors)} Fehler")
# Hier: Daten in Buchhaltung/DMS/ERP schreiben
# z.B. CSV-Zeile, Datenbank-Insert, API-Aufruf
if __name__ == "__main__":
while True:
check_mailbox()
time.sleep(300) # Alle 5 Minuten prüfen
Speichern Sie Zugangsdaten nie direkt im Script. Nutzen Sie Umgebungsvariablen oder einen Secrets-Manager. Das gilt für IMAP-Passwort und API-Key gleichermaßen.
Praxisbeispiel: Hausverwaltung mit 300 Eingangsrechnungen pro Monat
Eine Hausverwaltung mit 50 betreuten Objekten erhält monatlich rund 300 Eingangsrechnungen — Handwerker, Versorger, Versicherungen, Wartungsfirmen. Bisher wurden die Rechnungen manuell aus dem Postfach gespeichert und in eine Excel-Tabelle übertragen.
Nach der Automatisierung:
- Das Python-Script läuft auf einem kleinen Server und prüft das Postfach alle 5 Minuten
- Jede PDF-Rechnung wird automatisch an die API gesendet
- Die extrahierten Daten (Rechnungsnummer, Lieferant, Betrag, Fälligkeitsdatum) werden in eine PostgreSQL-Datenbank geschrieben
- Die ZUGFeRD-XMLs werden in einem strukturierten Dateiverzeichnis pro Objekt abgelegt
- Einmal pro Woche wird ein DATEV-Export für den Steuerberater erzeugt
Ergebnis: Statt 15 Stunden manueller Arbeit pro Monat dauert die Nachbearbeitung (Prüfung gelb/rot markierter Felder) noch etwa 2 Stunden.
Fehlerbehandlung in der Praxis
Nicht jede E-Mail enthält eine Rechnung, und nicht jedes PDF lässt sich problemlos verarbeiten. Ein robuster Workflow sollte folgende Fälle behandeln:
| Situation | API-Response | Empfohlene Aktion |
|---|---|---|
| PDF ist keine Rechnung | 422 extraction_failed | E-Mail markieren, manuell prüfen |
| Datei zu groß (>10 MB) | 413 file_too_large | PDF komprimieren und erneut senden |
| Kontingent aufgebraucht | 402 quota_exceeded | Benachrichtigung an Admin |
| Rate-Limit erreicht | 429 rate_limited | Warten (Retry-After Header beachten) |
| Anhang ist kein PDF | — | Vor dem API-Aufruf filtern |
Die API liefert bei jedem erfolgreichen Aufruf ein usage-Objekt mit dem aktuellen Verbrauch und dem Kontingent-Limit zurück. Nutzen Sie das für ein frühzeitiges Monitoring, bevor das Limit erreicht wird.
Nächste Schritte
- Konto erstellen unter vellonode.de/auth/register
- API-Key generieren unter Einstellungen → API
- Workflow aufsetzen — mit n8n, Make oder dem Python-Script als Startpunkt
- Testen — mit 5–10 echten Eingangsrechnungen, Ergebnisse prüfen
Die vollständige API-Spezifikation finden Sie unter /api/v1/openapi.