KI & Automatisierung5 Min. Lesezeit

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.

VT

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:

  1. Trigger: Neue E-Mail mit PDF-Anhang im Postfach
  2. Extraktion: PDF an die Vellonode API senden
  3. Daten: Strukturiertes JSON mit allen Rechnungsfeldern zurückbekommen
  4. 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: INBOX oder ein Unterordner wie Rechnungen
  • 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-Anhangs
    • format: json

Hinweis: Die organizationId ist ein Pflichtparameter. Sie erhalten Ihre Organisations-ID über GET /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:

  1. Email → Watch Emails (Gmail, Outlook oder IMAP)
  2. Router → nur E-Mails mit PDF-Anhang
  3. HTTP → Make a Request (multipart/form-data POST an die API)
  4. JSON → Parse (Response parsen)
  5. 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:

SituationAPI-ResponseEmpfohlene Aktion
PDF ist keine Rechnung422 extraction_failedE-Mail markieren, manuell prüfen
Datei zu groß (>10 MB)413 file_too_largePDF komprimieren und erneut senden
Kontingent aufgebraucht402 quota_exceededBenachrichtigung an Admin
Rate-Limit erreicht429 rate_limitedWarten (Retry-After Header beachten)
Anhang ist kein PDFVor 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

  1. Konto erstellen unter vellonode.de/auth/register
  2. API-Key generieren unter Einstellungen → API
  3. Workflow aufsetzen — mit n8n, Make oder dem Python-Script als Startpunkt
  4. Testen — mit 5–10 echten Eingangsrechnungen, Ergebnisse prüfen

Die vollständige API-Spezifikation finden Sie unter /api/v1/openapi.

Passende Lösungen

Weitere Artikel

Bleiben Sie informiert

Erhalten Sie die neuesten Artikel zu E-Rechnung, Buchhaltung und KI-Automatisierung direkt in Ihr Postfach.

Kein Spam, jederzeit abbestellbar. Datenschutzerklärung