SPF macros are variables that expand during SPF evaluation. %{s} is the sender email, %{l} is the local-part (before @), %{d} is the sender domain, %{i} is the connecting IP, and %{o} is the HELO domain. Macros enable dynamic SPF lookups—useful for large organizations with per-sender or per-IP authorization needs. Most domains don't need macros; they're for specialized enterprise use cases.
SPF Macros Explained: %{s}, %{l}, %{d}, and More
SPF Macro Basics
Macros are placeholders in SPF records that expand to actual values when the record is evaluated. They enable dynamic authorization based on sender-specific information.
Basic format: %{letter} where the letter represents different data.
Available Macros
| Macro | Expands To | Example |
|---|---|---|
%{s} | Sender email address | [email protected] |
%{l} | Local-part of sender | user |
%{d} | Domain of sender | example.com |
%{i} | Connecting IP (dotted/coloned) | 192.0.2.1 |
%{o} | HELO/EHLO domain | mail.example.com |
%{p} | Validated domain of IP (PTR) | mail.server.com |
%{v} | IP version | in-addr or ip6 |
%{h} | HELO/EHLO domain | mail.example.com |
Macro Modifiers
You can transform macro values:
| Modifier | Effect | Example |
|---|---|---|
r | Reverse | %{ir} = reversed IP |
digit | Right-split | %{d2} = last 2 parts of domain |
digit-r | Left-split | %{d2r} = first 2 parts reversed |
IP reversal example:
%{i}=192.0.2.1%{ir}=1.2.0.192
Domain splitting:
%{d}=mail.server.example.com%{d2}=example.com(last 2 parts)%{d1}=com(last 1 part)
Common Macro Use Cases
Use Case 1: Per-IP Authorization
Check if the sending IP is specifically authorized via DNS:
v=spf1 exists:%{ir}.spf.example.com ~all
How it works:
- Sender connects from
192.0.2.1 %{ir}expands to1.2.0.192- SPF looks up
1.2.0.192.spf.example.com - If an A record exists → pass
To authorize an IP, create DNS A records:
1.2.0.192.spf.example.com. IN A 127.0.0.2
This scales better than listing hundreds of ip4 mechanisms—each IP gets its own DNS record.
Use Case 2: Per-Sender Authorization
Authorize specific senders dynamically:
v=spf1 exists:%{l}._spf.example.com ~all
How it works:
- Email from
[email protected] %{l}expands tosales- SPF looks up
sales._spf.example.com - If record exists → pass
To authorize a sender:
sales._spf.example.com. IN A 127.0.0.2
Practitioner note: Per-sender authorization sounds appealing but creates massive DNS management overhead. I've only seen it work at organizations with sophisticated DNS automation. For most, include mechanisms are simpler and sufficient.
Use Case 3: Combining IP and Domain
Authorize IPs per sending domain:
v=spf1 exists:%{ir}.%{d}._spf.authservice.com ~all
How it works:
- Sender from
192.0.2.1claimingcustomer.com - Expands to
1.2.0.192.customer.com._spf.authservice.com - Central service manages authorization for each customer + IP
This pattern is used by email security providers managing multiple customer domains.
The exists Mechanism
exists is almost always used with macros. It checks if a DNS A record exists (regardless of what IP it returns):
exists:%{i}._spf.example.com
- If DNS returns any A record (even
127.0.0.1) → mechanism matches → pass - If DNS returns NXDOMAIN or empty → no match → check next mechanism
Important: The actual IP address returned doesn't matter. Existence is the only check.
Macro Security Considerations
Macros can create DNS amplification vectors:
# Potentially dangerous - untrusted input in DNS query
exists:%{l}._spf.example.com
An attacker could send emails with malicious local-parts designed to trigger excessive DNS queries or exploit DNS vulnerabilities.
Mitigation:
- Use macros only with trusted, controlled sender patterns
- Implement rate limiting on DNS
- Monitor for unusual query patterns
Debugging Macros
Macro expansion happens during SPF evaluation. To see what a macro expands to:
- Check raw headers: Some receivers include macro expansion in Authentication-Results
- Test with MXToolbox: Their SPF tool shows expansion for test queries
- Manual calculation: Work through the expansion yourself
Example debug:
Record: v=spf1 exists:%{ir}._spf.example.com ~all
Sender IP: 192.0.2.1
Expansion: exists:1.2.0.192._spf.example.com
Query: dig A 1.2.0.192._spf.example.com
When NOT to Use Macros
Don't use macros if:
- Standard include/ip4 mechanisms work for your use case
- You don't have DNS automation infrastructure
- You want simple, auditable SPF records
- You're not managing large numbers of IPs or senders
Most domains should stick to:
v=spf1 include:_spf.google.com include:sendgrid.net ~all
Simple, readable, easily debugged.
Practitioner note: In 8 years of email consulting, I've implemented macros exactly twice—both for enterprises sending from 500+ IPs with automated provisioning. Everyone else does fine with include statements.
Macro Lookup Costs
Each exists with macros counts as 1 DNS lookup toward the 10-lookup limit. The macro expansion itself is free—the resulting DNS query counts.
v=spf1 exists:%{ir}._spf.example.com exists:%{l}._auth.example.com ~all
This is 2 DNS lookups (2 exists mechanisms).
For the SPF basics, see the SPF setup guide. For understanding all SPF mechanisms, see SPF mechanisms explained. For the lookup limit that macros can help solve, see the SPF 10-lookup limit guide. If you have a complex infrastructure requiring macro-based SPF authorization, schedule a consultation. I'll help design a scalable SPF architecture that works with your DNS management systems.
Sources
- RFC 7208: Sender Policy Framework (SPF), Section 7 — Macros
- RFC 7208: Section 8 — Macro Definitions
- dmarcian: SPF Macros
- IETF: SPF Specification
v1.0 · March 2026
Frequently Asked Questions
What are SPF macros?
SPF macros are special variables in SPF records that get replaced with actual values during SPF evaluation. For example, %{d} becomes the sending domain, %{i} becomes the sender's IP address.
When should I use SPF macros?
Only in advanced scenarios: large organizations with per-sender authorization, custom IP validation via DNS lookups, or complex multi-tenant environments. Most domains should use standard include and ip4 mechanisms.
What does exists:%{i}._spf.example.com mean?
This checks if a DNS A record exists for the sender's IP address at _spf.example.com. If you're sending from 192.0.2.1, it looks up 1.2.0.192._spf.example.com. If the record exists, SPF passes.
Are SPF macros supported by all receivers?
Yes, macros are part of the SPF specification (RFC 7208). All compliant receivers support them. However, debugging is harder, and misconfiguration can cause unexpected failures.
Do SPF macros count toward the lookup limit?
The exists mechanism with macros counts as 1 DNS lookup per evaluation. The macro expansion itself doesn't add lookups, but the resulting DNS query does.
Want this handled for you?
Free 30-minute strategy call. Walk away with a plan either way.