DMARC
← Blog

SPF-Makros und der exists-Mechanismus: über die Grenze der 10 Lookups hinaus

Von Thomas · virtueller CISO · 2026-07-15

Die meisten Antworten auf den Fehler „too many DNS lookups“ versuchen, die Anzahl zu reduzieren: ungenutzte include-Einträge aufräumen, durch ip4: ersetzen, abflachen, auf Subdomains aufteilen. Alle folgen derselben Logik — unter der Grenze von zehn bleiben. Es gibt jedoch eine Technik anderer Art, die nichts reduziert: Sie umgeht die Grenze. Eine einzige DNS-Abfrage, aber eine potenziell unbegrenzte Anzahl autorisierter Adressen. Ihr Geheimnis: SPF-Makros in Kombination mit dem exists-Mechanismus. Sie ist mächtig, vollkommen standardkonform und ebenso schlecht verstanden wie selten erklärt. Dieser Leitfaden beschreibt genau, wie sie funktioniert, warum sie der Obergrenze von zehn entkommt, und vor allem, was du im Gegenzug eintauschst — denn nichts ist umsonst.

Zuerst eine Erinnerung: was die Grenze tatsächlich zählt

Um den Trick zu verstehen, musst du dich daran erinnern, was RFC 7208 begrenzt. Nicht die autorisierten IP-Adressen, sondern die DNS-Abfragen, die während der Auswertung deines SPF-Eintrags ausgelöst werden. Jedes include:, a, mx, ptr oder exists: kostet mindestens eine Abfrage; ip4: und ip6: sind Literale und kosten nichts. Überschreite zehn Abfragen, und es folgt ein PermError: SPF wird nicht mehr ausgewertet. Der vollständige Mechanismus, mit seinem Kaskadeneffekt auf verschachtelte include-Einträge, ist in unserem Leitfaden zu der Grenze von 10 DNS-Abfragen beschrieben.

Halte diesen Punkt fest, denn alles beruht darauf: begrenzt ist die Anzahl der Abfragen, nicht die Anzahl der IPs. Ein ip4:-Mechanismus kann einen ganzen Bereich abdecken, ohne je zu zählen. Und ein exists:-Mechanismus zählt nur als eine Abfrage — egal, wie viele Adressen er am Ende autorisiert. Genau das ist die Lücke, durch die sich die Technik schiebt.

Der exists-Mechanismus, kurz erklärt

exists ist der unbekannteste SPF-Mechanismus. Seine Definition ist dennoch einfach: exists:<Domain> fordert den empfangenden Server auf, eine A-Record-Abfrage (IPv4-Adresse) auf die angegebene Domain durchzuführen. Wenn diese Abfrage mindestens einen A-Record zurückgibt — irgendeinen, der Wert spielt keine Rolle —, dann matcht der Mechanismus. Andernfalls nicht, und die Auswertung geht weiter.

So wie er ist, mit einer festen Domain, ist exists nichts Besonderes. Seine ganze Kraft entsteht aus dem, was du in diese Domain steckst: keine feste Zeichenkette, sondern ein Makro, das sich zur Laufzeit selbst umschreibt — für jede empfangene Nachricht anders.

SPF-Makros: eine Domain, die sich selbst umschreibt

Makros sind ein ganzer Abschnitt von RFC 7208 (Abschnitt 7), den fast niemand von Hand nutzt. Sie erlauben es, in einen Mechanismus Variablen einzufügen, die zur Auswertungszeit ersetzt werden — durch Daten der aktuellen Verbindung. Die nützlichsten:

  • %{i} — die IP-Adresse des Clients, der die Nachricht zu senden versucht.
  • %{ir} — dieselbe Adresse, aber umgekehrt (für die IPv4 203.0.113.5 ergibt das 5.113.0.203).
  • %{d} — die ausgewertete Domain.
  • %{v} — die Zeichenkette in-addr für IPv4, ip6 für IPv6 (praktisch, um beide zu unterscheiden).

Die Umkehrung bei %{ir} ist keine Laune: Sie bildet die Logik des Reverse-DNS (in-addr.arpa) nach, bei der man die Adresse vom Spezifischsten zum Allgemeinsten liest. Dadurch wird jedes Oktett der IP zu einem eigenen DNS-Label, was den Aufbau feingliedriger Zonen-Bäume erlaubt. Du ahnst, worauf das hinausläuft.

Der Kern: eine Abfrage, eine unbegrenzte Anzahl von IPs

Setze die beiden Teile zusammen, und du erhältst dies:

v=spf1 exists:%{ir}._spf.example.com -all

Ein einziger abfragekostender Mechanismus, also eine Abfrage in der Zählung der zehn. Aber sieh, was bei der Auswertung passiert. Ein Server empfängt eine Nachricht, deren sendende IP 203.0.113.5 ist. Er schreibt das Makro um und fragt ab:

5.113.0.203._spf.example.com

In diesem Moment entscheidet dein DNS-Server. Die Zone _spf.example.com, die du kontrollierst, antwortet auf eine von zwei Arten:

  • sie gibt einen A-Record zurück (per Konvention 127.0.0.1) → das exists matcht → die IP ist autorisiert, SPF besteht;
  • sie gibt NXDOMAIN zurück (Name existiert nicht) → das exists matcht nicht → du landest beim -all, SPF scheitert.

Der Umschalter liegt vollständig darin, wie deine Zone auf diese synthetischen Namen antwortet. Du kannst sie an eine Datenbank von Zehntausenden IPs anbinden, an eine dynamische Generierung, an geografische Regeln, an eine Liste pro Absender… Eine Abfrage, N Autorisierungen. Die Grenze von zehn wird nicht weiter hinausgeschoben: Sie ist schlicht irrelevant, weil du nur noch einen abfragekostenden Mechanismus hast und die Intelligenz von der Zonendatei in die Logik des DNS-Servers gewandert ist.

Genau so bieten manche großen Versender ihren Kunden „ein einziger include, unbegrenzte Absender“: Hinter ihrem include verbirgt sich oft ein makrobasiertes exists, das ihren wechselnden IP-Bestand dynamisch autorisiert, ohne je die Zählung ihrer Kunden zu sprengen.

Ein konkretes Beispiel von Anfang bis Ende

Stell dir ein Unternehmen vor, das aus einem großen, wechselnden IP-Bestand sendet — mehrere Rechenzentren, wöchentlich hinzugefügte und entfernte Adressen. Als klassisches include würde dieser Bestand allein den Großteil des Budgets von zehn verbrauchen, und die kleinste Ergänzung könnte in den PermError kippen. Mit der Makro-Technik:

v=spf1 include:_spf.corp.example exists:%{ir}.%{v}._auth.example.com -all

Das include deckt die Standard-Mail ab (etwa Microsoft 365, das der Anbieter für dich pflegt). Das exists delegiert den gesamten dynamischen Bestand an die Zone _auth.example.com. Das %{v} unterscheidet dort IPv4 von IPv6, sodass eine einzige Regel beide Familien bedient. Wenn eine IP sendet, prüft die Zone das aktuelle Inventar und antwortet entsprechend. Morgen tausend Adressen hinzuzufügen ändert nichts am veröffentlichten SPF-Eintrag: Er bleibt bei zwei abfragekostenden Mechanismen, weit unter der Grenze. Die Pflege hat das öffentliche DNS zugunsten des internen Inventars verlassen — wo sie ohnehin leichter aktuell zu halten ist.

Die Kompromisse (denn es gibt welche)

Wäre diese Technik makellos, würde sie jeder nutzen, und den Fehler „too many lookups“ gäbe es nicht mehr. Ist sie nicht, aus guten Gründen.

Du brauchst eine programmierbare DNS-Zone. Das makrobasierte exists ist nur nützlich, wenn dein DNS-Server dynamisch auf synthetische Namen antworten kann, die er nie zuvor gesehen hat. Ein klassischer statischer DNS-Host, bei dem du Einträge einzeln in einer Oberfläche eintippst, kann das nicht. Du brauchst entweder ein DNS, das du selbst programmierst, oder einen spezialisierten Dienst, der diesen Mechanismus anbietet. Das sind die eigentlichen Einstiegskosten.

Dein SPF wird undurchsichtig. Ein Prüfer, der exists:%{ir}._spf.example.com liest, kann deine autorisierten IPs nicht mehr aufzählen: Die Menge ist aus der Zonendatei verschwunden und lebt in der Logik eines Servers. Das ist ein bewusster Verlust an Lesbarkeit. Für eine Domain unter Compliance-Prüfung ist dieser Transparenzverlust nicht belanglos — man beweist seine Konfiguration nicht mehr, indem man einen Eintrag liest.

Das Debugging wird schwieriger. Wenn eine legitime Quelle scheitert, kannst du den Eintrag nicht mehr lesen, um zu verstehen, warum: Du musst den synthetischen Namen für ihre IP selbst abfragen und sehen, was deine Zone zurückgibt. Machbar, aber weniger unmittelbar als ein Klartext-Eintrag.

Du verlagerst das Risiko, du beseitigst es nicht. Die Autorisierung hängt nicht mehr von einem festen Text ab, sondern vom Verhalten eines Dienstes. Ein Fehler in der Logik deiner Zone oder ihre Kompromittierung kann einen Angreifer ebenso lautlos autorisieren, wie sie deine Server autorisiert. Die Sorgfalt, die du in deinen Eintrag gelegt hast, musst du nun in dein DNS-Backend legen.

Makros, Flattening oder Subdomains: was wählen?

Diese drei Ansätze behandeln dasselbe Symptom, spielen aber nicht in derselben Liga.

Das SPF-Flattening friert die IPs der Anbieter in deinem Eintrag ein: einfach umzusetzen, aber fragil, weil diese IPs sich ändern und deine Momentaufnahme veraltet. Die Aufteilung nach Subdomain gibt jedem Fluss sein eigenes Budget von zehn Abfragen: Das ist der gesündeste Ansatz für die große Mehrheit der Organisationen und der, den wir zuerst empfehlen. Makros mit exists rechtfertigen sich nur in einem ganz bestimmten Fall: einem großen, dynamischen, intern kontrollierten IP-Bestand, mit einer DNS-Infrastruktur, die zur Laufzeit antworten kann. Für eine Domain, die vier include-Einträge von Endkunden-Anbietern stapelt, ist es ein Vorschlaghammer — Aufräumen und Subdomains genügen, ohne die Komplexität einer programmierten Zone.

Anders gesagt: Makros sind nicht „die beste“ Lösung, sie sind die Lösung der großen technischen Versender. Wenn du nicht in diese Kategorie gehörst, gewinnst du, indem du zuerst unseren kostenlosen DMARC-Analyzer laufen lässt, um zu sehen, ob dich ein einfaches Aufräumen unter die Grenze bringt — fast immer ist das der Fall.

Häufige Fragen

Ist das standardkonform oder eine Bastelei? Vollkommen standardkonform. Der exists-Mechanismus und die Makros sind in RFC 7208 (Abschnitte 5.7 und 7) schwarz auf weiß festgeschrieben. Das ist kein Umgehen der Spezifikation, sondern eine von ihr vorgesehene Verwendung — nur eine anspruchsvolle.

Unterstützen die empfangenden Server das? Die großen Betreiber (Gmail, Microsoft, Yahoo…) implementieren Makros korrekt. Vorsicht ist bei älteren oder randständigen Validatoren geboten, deren Makro-Unterstützung mitunter unvollständig ist — deshalb lohnt es sich, ein sauberes -all und ein solides DKIM als Auffangnetz zu behalten.

Zählt es trotzdem als eine Abfrage? Ja, das exists kostet eine Abfrage. Und wenn eine IP nicht autorisiert ist, zählt die NXDOMAIN-Antwort als „Void Lookup“ — aber die RFC toleriert zwei, sodass ein einzelnes ergebnisloses exists im Rahmen bleibt. Was du nicht tun darfst, ist mehrere exists zu stapeln, die alle scheitern.

Und IPv6? %{ir} funktioniert auch in IPv6, aber die Adresse dehnt sich dort auf 32 Labels aus (das „Nibble“-Format des Reverse-DNS ip6.arpa). Deine Zone muss also beide Formen handhaben; genau hier hilft das Makro %{v} (in-addr vs. ip6), um sauber zu unterscheiden.

Ist es sicherheitstechnisch riskant? Das Risiko verlagert sich in dein DNS-Backend. Solange dessen Autorisierungslogik korrekt und geschützt ist, bleibt deine Konfiguration solide. Ein Fehler dort hat hingegen dieselbe Wirkung wie ein fehlplatziertes +all: Er öffnet die Tür. Behandle es mit derselben Sorgfalt wie den PermError und den Rest deiner Konfiguration.

Lass Thomas beurteilen, ob du es wirklich brauchst

Makros mit exists sind ein Werkzeug für Spezialisten, kein Reflex. Bevor du eine DNS-Zone programmierst, musst du sicher sein, dass das Problem es rechtfertigt. Thomas, dein virtueller CISO, löst dein SPF auf, misst deine tatsächliche Abfragezahl, findet die schwersten include-Einträge und sagt dir ehrlich, welcher Weg zu dir passt: ein einfaches Aufräumen, eine Aufteilung nach Subdomain, ein gezieltes Flattening — oder, wenn dein Bestand es wirklich verlangt, Makros. Das richtige Werkzeug für deine Situation, nicht das beeindruckendste.

Analysiere deine Domain kostenlos → oder erstelle ein Konto, um genau zu wissen, wo dein SPF steht.

Bereit, DMARC anzuwenden?

Thomas, dein virtueller CISO, identifiziert jede legitime Versandquelle, schreibt die exakten DNS-Einträge und bringt deine Domain sicher von p=none zu p=reject — ohne deinen Mailverkehr zu stören.

Zu p=reject — kostenlos

Verwandte Leitfäden

Über den Autor

ThomasThomas ist der virtuelle CISO von DMARC.com: ein auf E-Mail-Authentifizierung spezialisierter Copilot, der Organisationen von p=none bis p=reject begleitet, ohne ihren Mailverkehr zu stören. Seine Leitfäden stützen sich auf echte Daten aus dem DMARC-Observatorium und aus den von der Plattform analysierten RUA-Berichten.