vCard von iCloud auf Radicale (CalDAV/CardDAV) hochladen
Dieses Skript liest Kontakte aus einer .vcf
-Datei (z. B. iCloud-Export) ein, entfernt alle nicht standardkonformen Felder und lädt jeden Kontakt als einzelne .vcf
-Datei in einen bestehenden Radicale CardDAV-Server hoch.
Radicale speichert Adressbücher im CardDAV-Standard über WebDAV. Apple-exportierte vCards enthalten oft proprietäre Felder wie item1.X-ADDRESSING-GRAMMAR
oder X-APPLE-*
, die von Radicale nicht akzeptiert werden. Das Skript sorgt dafür, dass nur die Felder übrigbleiben, die auch RFC-konform sind.
Es installiert automatisch die benötigten Python-Pakete (vobject
und requests
), bereinigt die Einträge und führt den Upload per PUT
-Anfrage aus. Für die Ausführung empfiehlt sich ein virtuelles Environment, damit Abhängigkeiten voneinander getrennt bleiben.
Vorbereitung
Lege die exportierte vCard-Datei (z. B. icloud_contacts.vcf
) in dasselbe Verzeichnis wie das Skript. Stelle sicher, dass die Datei lesbar ist und gültige BEGIN:VCARD ... END:VCARD
-Blöcke enthält.
Ablauf
┌─────────────────────┐
│ CardDAV-Server │
│ REPORT vCards │
└─────────────────────┘
│
▼
┌─────────────────────┐
│ Python-Skript │
│ vCards parsen │
│ X-Felder entfernen │
│ UID vergeben │
└─────────────────────┘
│
▼
┌─────────────────────┐
│ CardDAV-Server │
│ PUT vCards │
└─────────────────────┘
Das Python-Skript
import subprocess
import sys
def install(package):
subprocess.check_call([sys.executable, "-m", "pip", "install", package])
try:
import vobject
except ImportError:
install("vobject")
import vobject
try:
import requests
except ImportError:
install("requests")
import requests
import uuid
from requests.auth import HTTPBasicAuth
# Konfiguration
vcf_datei = "icloud_contacts.vcf"
carddav_url = "https://deinserver.de/benutzer/contacts/"
username = "DEIN_USERNAME"
password = "DEIN_PASSWORT"
def ist_standard_property(name):
name = name.upper()
return name in ["FN", "N", "TEL", "EMAIL", "ORG", "UID"]
def lade_und_bereinige_vcards(pfad):
with open(pfad, "r", encoding="utf-8") as f:
content = f.read()
rohkarten = content.strip().split("END:VCARD")
rohkarten = [c + "END:VCARD" for c in rohkarten if "BEGIN:VCARD" in c]
bereinigt = []
for raw in rohkarten:
try:
card = vobject.readOne(raw)
new_card = vobject.vCard()
new_card.add("uid")
new_card.uid.value = str(uuid.uuid4())
for prop in card.getChildren():
name = prop.name.upper()
if name.startswith("ITEM") or name.startswith("X-") or name in ["PRODID", "REV", "PHOTO"]:
continue
if ist_standard_property(name):
new_card.add(prop)
bereinigt.append(new_card.serialize())
except Exception as e:
print("Fehler beim Parsen eines Kontakts:", e)
return bereinigt
def upload_to_carddav(cards):
hochgeladen = 0
for card_data in cards:
uid = str(uuid.uuid4())
ziel_url = carddav_url + uid + ".vcf"
response = requests.put(
ziel_url,
data=card_data,
headers={"Content-Type": "text/vcard"},
auth=HTTPBasicAuth(username, password)
)
if response.status_code in [200, 201, 204]:
print("Hochgeladen:", ziel_url)
hochgeladen += 1
else:
print("Fehler (", response.status_code, ") bei", ziel_url)
print(response.text)
print(hochgeladen, "Kontakte erfolgreich hochgeladen.")
def main():
bereinigt = lade_und_bereinige_vcards(vcf_datei)
if not bereinigt:
print("Keine gültigen vCards gefunden.")
return
upload_to_carddav(bereinigt)
if __name__ == "__main__":
main()
Verwendung
Führe das Skript in einem Terminal oder einer Konsole aus:
python carddav_upload.py
Es bereinigt alle Kontakte und lädt sie anschließend einzeln hoch. Nicht standardkonforme Felder werden automatisch entfernt.
Hintergrund
vCard (RFC 6350) ist der Standard für den Austausch elektronischer Visitenkarten. CardDAV erweitert WebDAV um dieses Format und erlaubt das Speichern von .vcf
-Dateien in Adressbüchern.
Radicale implementiert CardDAV und akzeptiert nur RFC-konforme vCard-Felder. Das Skript stellt sicher, dass alle importierten Kontakte diesen Vorgaben entsprechen und nicht durch Apple-spezifische Erweiterungen fehlschlagen.
Wenn die CardDAV-URL nicht bekannt ist, hilft ein Client wie DAVx⁵ oder das Radicale-Debug-Log, den korrekten Pfad zu ermitteln. Die URL endet meist auf /username/contacts/
.
No Comments