Technology

Inbox or Spam? A Friendly, Step-by-Step Guide to SPF, DKIM, DMARC and rDNS

So, Why Are My Emails Going to Spam?

A few years back, I was sipping a not-so-great office espresso when a client called me in a panic: “We launched the new newsletter and… crickets. Not a single reply.” I checked the logs, ran a few tests, and there it was—the dreaded spam folder. It wasn’t the content. It wasn’t the timing. It was trust. The receiving mail servers simply didn’t trust the mail was who it claimed to be.

Ever had that moment when you send an important message and it vanishes into the void? No bounce, no error—just silence. That’s usually a deliverability problem, and more often than not, the fix isn’t mystical—it’s methodical. You establish identity, you prove authorship, and you ask the receiving servers to enforce those rules. That’s SPF, DKIM, DMARC, and rDNS in a nutshell.

In this guide, I’ll walk you through a practical, server-first setup that I use for clients: set your server’s identity, publish a correct SPF record, sign mail with DKIM, enforce policy with DMARC, and make reverse DNS (rDNS) match up. We’ll talk about gotchas, share a few war stories, and make sure by the end you’ve got a clean, trustworthy sending setup. No fluff—just the stuff that actually keeps your emails out of spam.

The Trust Chain: How Mail Servers Decide to Believe You

Here’s the thing about email: it’s older than most of the web, and it was never designed with modern-day spam in mind. So the industry bolted on a “trust chain.” Think of it like a bouncer at an event. SPF is the guest list. DKIM is your government-issued ID. DMARC is the policy that says, “If the ID doesn’t match the name on the list, don’t let them in.” And rDNS is your return address on the invitation—if it looks sketchy or doesn’t match, you’re on thin ice.

In my experience, deliverability issues almost always trace back to one of three things. First, identity isn’t aligned—your envelope sender says one thing, your From address another, and the signature yet another. Second, DNS is messy—SPF includes too many lookups or is missing the active sending IPs. Third, server basics are off—your hostname and rDNS don’t match, or your HELO is something generic like “server.local” and providers mark you as suspicious. We’ll clean all of that up step by step.

Before we dive in, a quick reminder: if your DNS infrastructure is a bit complex, it’s worth considering how you secure it end-to-end. I like to think of domain trust as a chain that’s only as strong as its weakest link. If you want to go deeper later, you can read more about what DNSSEC is and how it protects your domain’s DNS records, but for now let’s stick to the core email records.

Step 1: Set a Clean Server Identity (Hostname, HELO/EHLO, and rDNS)

One of my clients once ran a perfectly fine transactional mail server on a dedicated IP, yet they were constantly flagged by some providers. The problem? Their PTR (reverse DNS) pointed to something like ip-203-0-113-17.exampledc.net, while their server introduced itself as mail.brand.com. That mismatch might seem small, but it’s a red flag. Let’s fix that.

Pick a proper hostname

Choose a fully qualified domain name that you control, like mail.yourdomain.com. Create an A record pointing this name to your sending IP. If you have IPv6, also create an AAAA record. Now set your server’s hostname to that exact value.

On Linux, that usually means:

sudo hostnamectl set-hostname mail.yourdomain.com

Then make sure it’s in /etc/hosts and your DNS has an A record:

# DNS (at your DNS provider)
mail 3600 IN A 203.0.113.17

Align rDNS (PTR) with your hostname

rDNS is controlled by whoever owns the IP space—often your hosting provider. You’ll need to set the PTR record for your IP to your hostname (e.g., 203.0.113.17 → mail.yourdomain.com), then make sure forward DNS resolves mail.yourdomain.com back to that IP. That two-way match—sometimes called forward-confirmed reverse—is one of those silent credibility boosters.

Make sure your MTA says the right HELO/EHLO

If you use Postfix, set myhostname and smtpd_banner appropriately:

# /etc/postfix/main.cf
myhostname = mail.yourdomain.com
smtpd_banner = $myhostname ESMTP

For Exim:

# /etc/exim/exim.conf or exim4 config
primary_hostname = mail.yourdomain.com

This helps receiving servers see a consistent story: HELO says mail.yourdomain.com, reverse DNS says the IP is mail.yourdomain.com, and forward DNS confirms it. Simple, but powerful.

Step 2: Publish a Lean, Accurate SPF Record

SPF is your “who’s allowed to send” list. When I audit SPF, I’m looking for three things. First, are all legitimate sources included—your server IPs, any SaaS senders, and a relay if you use one? Second, are we within the ten DNS-lookup limit? Third, do we end with a clear enforcement directive, not a nervous ~all that never graduates to -all?

Start with the basics

In DNS, create a TXT record for your root domain. If your mail is sent only from your server’s IP, a minimal SPF might look like:

yourdomain.com. 3600 IN TXT "v=spf1 ip4:203.0.113.17 -all"

If you send from multiple places—maybe your app server plus a marketing platform—add their mechanisms. For example:

"v=spf1 ip4:203.0.113.17 include:_spf.mailservice.com -all"

Be mindful of nested include: chains. Every include can trigger multiple lookups. I’ve seen SPF records silently break because they hit the lookup cap and receivers treated them as “permerror,” which acts a lot like a fail.

Use a subrecord if needed

When SPF grows complicated, I like to centralize sender IPs in a subdomain such as _spf.yourdomain.com and include it from the main record:

_spf.yourdomain.com. 3600 IN TXT "v=spf1 ip4:203.0.113.17 ip4:198.51.100.44 -all"
yourdomain.com.       3600 IN TXT "v=spf1 include:_spf.yourdomain.com -all"

Keep it concise. Don’t list things that don’t actually send. Don’t use overly broad mechanisms unless you absolutely have to. And, yes, eventually you should be comfortable with -all once you’re confident the list is complete.

Make SPF align with your From domain

DMARC cares about alignment between the From domain (what humans see) and the domain authenticated by SPF (the envelope sender or Return-Path). If your Return-Path uses bounce.yourdomain.com and your From uses yourdomain.com, you’re good under relaxed alignment. If your processor sends bounces from a completely different domain, consider adjusting so they live under your domain. It helps your DMARC story later.

Step 3: DKIM – Sign What You Send

DKIM is your signature. It says, “This message left my server intact, and here’s a cryptographic way to verify it.” If you’ve ever struggled with changing HTML templates and watched SPF still pass, that’s expected—SPF doesn’t validate content integrity. DKIM does.

Generate a 2048-bit key and selector

Most setups today prefer 2048-bit keys. You’ll also choose a selector—something like mail or mta1—that lets you rotate keys without downtime.

Using OpenDKIM with Postfix is a common path. Install packages, generate keys, publish the public part, and configure signing:

sudo apt-get install opendkim opendkim-tools
sudo mkdir -p /etc/opendkim/keys/yourdomain.com
cd /etc/opendkim/keys/yourdomain.com
sudo opendkim-genkey -b 2048 -s mail -d yourdomain.com
sudo chown opendkim:opendkim mail.private

This gives you two files: mail.private (your private key) and mail.txt (a template for your DKIM DNS record).

Publish the DKIM public key in DNS

Take the contents from mail.txt and create a TXT record at mail._domainkey.yourdomain.com. It looks like this:

mail._domainkey.yourdomain.com. 3600 IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqh...IDAQAB"

Make sure there are no stray spaces or missing quotes; copy-paste errors here are notorious for subtle delivery issues.

Wire OpenDKIM to your MTA

For Postfix, add the milter settings:

# /etc/opendkim.conf
Syslog                  yes
UMask                   002
Mode                    sv
Canonicalization        relaxed/relaxed
KeyTable                /etc/opendkim/key.table
SigningTable            /etc/opendkim/signing.table
ExternalIgnoreList      /etc/opendkim/trusted.hosts
InternalHosts           /etc/opendkim/trusted.hosts
Socket                  inet:8891@localhost
# /etc/opendkim/key.table
mail._domainkey.yourdomain.com yourdomain.com:mail:/etc/opendkim/keys/yourdomain.com/mail.private

# /etc/opendkim/signing.table
*@yourdomain.com mail._domainkey.yourdomain.com

# /etc/opendkim/trusted.hosts
127.0.0.1
localhost
mail.yourdomain.com
# /etc/postfix/main.cf additions
milter_default_action = accept
milter_protocol = 6
smtpd_milters = inet:localhost:8891
non_smtpd_milters = inet:localhost:8891

Restart services:

sudo systemctl restart opendkim
sudo systemctl restart postfix

If you run Exim, you’ll configure DKIM parameters in Exim’s configuration to point at the same private key and selector; most modern Exim builds support DKIM natively.

Check alignment

DKIM alignment for DMARC uses the d= domain in the signature. If you sign with d=yourdomain.com and your From is yourdomain.com, you’re aligned under relaxed mode. Signing with a vendor’s domain (like d=vendor-mail.com) won’t align unless it’s your domain. Many SaaS senders let you bring your own DKIM; use that feature so the signature shows your domain.

Step 4: DMARC – Set the Rules (Start Gentle)

DMARC is the policy layer. It tells receivers what to do if SPF and DKIM don’t align with your From domain. I like to start soft, watch the reports, then dial up enforcement. Think of DMARC like a thermostat—you don’t set it to max on day one. You nudge it until it feels right.

Begin with p=none and reports

Create a TXT record at _dmarc.yourdomain.com:

_dmarc.yourdomain.com. 3600 IN TXT 
"v=DMARC1; p=none; rua=mailto:[email protected]; ruf=mailto:[email protected]; fo=1; adkim=r; aspf=r"

What does this do? p=none means “don’t quarantine or reject yet.” rua collects aggregate reports (XML summaries) and ruf can collect forensic samples. fo=1 asks for failure reports. adkim and aspf set relaxed alignment. If you’re new to DMARC, I recommend relaxed at first; you can tighten to strict (s) later.

Nudge toward enforcement

After a couple of weeks of watching reports, you’ll know who’s sending on your behalf and whether they align. Clean up any stragglers, then move to quarantine for a portion of traffic:

"v=DMARC1; p=quarantine; pct=25; rua=mailto:[email protected]; adkim=r; aspf=r"

If that looks good—no legitimate traffic getting caught—raise pct and eventually go to p=reject. It’s incredibly satisfying to see spoofed mail get stopped in its tracks while your real mail sails through.

If you want an accessible, vendor-neutral overview to share with your team, the high-level summary at dmarc.org is a nice reference point.

Testing and Verifying: Don’t Skip This Part

Every time I think “this setup is too simple to fail,” I’m reminded of the time a hidden character in a DKIM record broke signing for a week. Testing isn’t optional; it’s the part that saves you those quiet lost conversions.

Check DNS propagation and formatting

Use a reputable tool to query your SPF, DKIM, and DMARC records and check for obvious issues. I’ve had good experiences with the suite over at MXToolbox for SPF/DKIM/DMARC checks. Test your domain and selectors, and make sure there are no syntax mistakes.

Send real messages and read the headers

Send a message to Gmail, Outlook, and another provider if you can. Open the raw headers and look for Authentication-Results. You want to see something like:

Authentication-Results: mx.google.com;
       spf=pass (google.com: domain of [email protected] designates 203.0.113.17 as permitted sender) [email protected];
       dkim=pass (signature verified) header.d=yourdomain.com;
       dmarc=pass (p=REJECT sp=NONE dis=NONE) header.from=yourdomain.com

If any result shows “neutral,” “softfail,” or “fail,” trace it back. Sometimes the Return-Path is a service domain not under your control. Sometimes DKIM is signing with the wrong selector. And sometimes DMARC alignment is off because the From domain doesn’t match the domain authenticated by SPF or DKIM.

Monitor reputation over time

Warm up new IPs slowly and watch how receivers react. Gmail’s Postmaster Tools can give you a feel for IP and domain reputation, complaint rates, and delivery errors. Changes to volume, complaint spikes, or a sudden surge in bounces can all drag down deliverability. If you’re doing transactional mail, consistency is your friend.

Step-by-Step: Putting It All Together on a Fresh Server

Let’s roll up our sleeves. Imagine you’ve just deployed a fresh VPS to send transactional email for your app. Here’s the pragmatic sequence I follow, because it saves time and avoids dead ends.

1) Prep the server

Set the hostname, update packages, and sync time (NTP helps with DKIM and TLS handshakes):

sudo hostnamectl set-hostname mail.yourdomain.com
sudo apt-get update && sudo apt-get upgrade -y
sudo timedatectl set-ntp true

If you’re running a VPS in the wild, it’s worth a quick security sweep—firewall essentials, SSH hardening, and safe defaults. If you need a practical checklist later, I wrote up a guide on how to secure a VPS server with step-by-step hardening.

2) Install and configure your MTA

For Postfix, install and set a clean banner:

sudo apt-get install postfix
# choose Internet Site and set mail.yourdomain.com as system mail name

# /etc/postfix/main.cf (relevant bits)
myhostname = mail.yourdomain.com
myorigin = /etc/mailname
mydestination = $myhostname, localhost.$mydomain, localhost
inet_interfaces = all
inet_protocols = ipv4
smtpd_banner = $myhostname ESMTP

Reload Postfix:

sudo systemctl restart postfix

If you use Exim, install via your distro, set primary_hostname, and confirm the daemon is listening only where it should. Keep open relays far away from your setup—you don’t want to wake up with a blacklisted IP because someone abused your server overnight.

3) rDNS and HELO alignment

Configure the PTR with your provider so the IP points to mail.yourdomain.com, and make sure forward DNS points back. Test it with:

host 203.0.113.17
# should show pointer to mail.yourdomain.com

host mail.yourdomain.com
# should resolve to 203.0.113.17

4) SPF record in DNS

Publish your SPF TXT record with the exact senders and end with an enforcement directive. If you’re still running tests, ~all is okay for a day or two, but plan to move to -all once you trust the configuration.

5) DKIM signing

Install OpenDKIM, generate a 2048-bit key with a selector (e.g., mail), publish the TXT record from the generated mail.txt, then wire the milter into Postfix or Exim. Restart services and send a test message to yourself at a Gmail account to inspect headers.

6) DMARC policy

Create the initial DMARC record with p=none and set rua for aggregate reports. After you verify SPF/DKIM alignment for your legitimate mail sources, move to p=quarantine with pct=25, then ramp up. Eventually, p=reject is the goal for maximum spoofing protection.

7) TLS certificate

Modern MTAs increasingly care about encryption on the wire. Configure STARTTLS with a valid certificate so that providers aren’t eyeballing your server suspiciously. If you need a refresher on why certificates matter and how to think about them, here’s a friendly primer on what an SSL certificate is and how it secures connections.

8) Test, iterate, and warm up

Send small volumes first. Check your Authentication-Results headers, watch bounces, and monitor reputation with the tools we discussed. Adjust DNS if a provider reports alignment issues. Then slowly increase your volume. Think of it like training a new barista—hand them a few orders, watch their technique, and then let them handle the rush.

Common Pitfalls (And How I Got Out of Them)

I’ve lost count of how many times these same issues popped up. The silver lining? They’re fixable, and once you know them, you’ll spot them from a mile away.

First, SPF “permerror” from too many lookups. If you include a vendor that includes five other vendors, you can hit the ten-lookup ceiling without realizing it. Solution: consolidate IP ranges when possible, remove dead includes, and avoid unnecessary mechanisms. You can also move some senders to DKIM-first alignment to ease SPF pressure.

Second, DKIM record formatting. DNS control panels sometimes wrap long strings, or they add extra quotes. If your DKIM fails, check exactly what the TXT record returns with a direct dig. Compare it to what your mail.txt generated. A single missing character can tank your signature.

Third, DMARC alignment mismatches. Maybe your Return-Path is [email protected] while your From is [email protected]. SPF might pass, but it won’t align. Either switch to a Return-Path under your domain or ensure DKIM signs with your domain and passes, so DMARC can pass via DKIM alignment instead.

Fourth, rDNS mismatches or generic PTRs. If your IP’s PTR is something like ec2-203-0-113-17.compute-1.amazonaws.com and you HELO as mail.yourdomain.com, that mismatch can degrade your reputation. Ask your provider for a custom PTR, and ensure forward-confirmation.

Fifth, content and sudden volume spikes. Even with perfect authentication, sending too many identical messages too quickly can look like bot behavior. I once watched a clean IP lose favor for a week because an app bug retried the same message for thousands of users. Fix the bug, drip the retries, and your reputation recovers.

Advanced Tips That Quietly Move the Needle

Over time, I’ve adopted a handful of habits that keep deliverability steady, even when campaigns get ambitious.

Consider using a dedicated subdomain for outbound mail—like mail.yourdomain.com as the visible From domain—if your brand allows it. This gives you room to evolve policy and isolate reputation without risking your apex domain. If you do this, make sure SPF, DKIM, and DMARC live under that subdomain too.

Rotate DKIM keys annually or after team changes. That’s the magic of selectors—you can publish a new selector, start signing with it, and remove the old one when you’re done. No downtime, no drama.

For mailing list traffic, watch ARC and List-Id behaviors. While ARC isn’t strictly necessary for standard transactional mail, some forwarders play nicer when signed messages carry through. If your messages are often forwarded (think internal aliases or helpdesk systems), understanding ARC can help with edge-case troubleshooting.

Use suppression lists and bounce handling. SPF, DKIM, DMARC, and rDNS get you in the door, but engagement keeps you inside. If people don’t open your mail, providers notice. Respect unsubscribes, remove hard bounces, and don’t hammer soft bounces indefinitely.

Lastly, keep an eye on your infrastructure. If your server is under load or misconfigured, delays and timeouts can cascade into delivery issues. If this topic interests you from a performance angle—tuning PHP-FPM, OPcache, Redis, and MySQL for web apps—there’s a post I love referring back to about server-side optimization that makes WordPress fly. While it’s not email-specific, a healthy server helps everything behave, including your MTA.

Working with External Providers (And Keeping Alignment)

Plenty of teams use a cocktail of services: transactional mail from the app server, marketing blasts through a SaaS, and maybe a support desk with its own outbound setup. There’s nothing wrong with that. Just make sure each source can either align via SPF or DKIM with your From domain.

For SaaS platforms, use custom domains for both Return-Path and DKIM whenever possible. Most reputable senders provide a DNS wizard that asks you to add CNAMEs or TXT records so they can sign on your behalf with d=yourdomain.com. Don’t skip this. If the vendor says it’s “optional,” treat it as mandatory for deliverability.

When onboarding a new sender, add it to your SPF carefully. If they provide an include: mechanism, check whether that include fans out into multiple lookups. If you’re tight on the limit, consider relying on DKIM alignment instead and keep SPF minimal. And, of course, test again after adding the new service.

Troubleshooting Flow When Things Go Sideways

Here’s the flow I use when someone messages me late on a Friday with, “Why did Outlook suddenly hate our emails?”

First, check your domain with a testing tool for DNS record health and blacklists. A quick pass with MXToolbox deliverability tests can save you thirty minutes of guesswork.

Second, send yourself a fresh message and inspect the raw headers at the destination. Look for spf=pass|fail, dkim=pass|fail, dmarc=pass|fail. If DKIM fails, check the selector’s public key in DNS and confirm it matches the signing key. If SPF fails, verify the Return-Path domain and the IP that actually sent the message.

Third, compare the results across providers. Gmail might pass you while Outlook quarantines you. It’s not always a policy issue; sometimes volume or user feedback nudges a provider to be stricter. That’s when I’ll peek at Postmaster Tools to see trends and error codes and adjust sending cadence or segment the list.

Fourth, review recent changes. Did a developer roll out a new marketing sender? Did you migrate DNS providers? Did an SSL certificate expire and force a weird fallback? Most deliverability issues are change-related. Find the change, fix the alignment, and your results usually normalize within a few days.

Final Checks Before You Hit Send at Scale

Before a big campaign or that all-important invoice batch, I run through a quick gut-check.

Is the server identity clean? Hostname, rDNS, and HELO match? Are SPF and DKIM passing and aligning with the From domain? Is DMARC at the right enforcement level for this audience? Do we have a valid TLS certificate? Are unsubscribe links and suppression lists up to date? If a few of these make you hesitate, fix them now. It’s much easier to adjust before you dump thousands of messages into the queue.

If your underlying platform or DNS governance still feels shaky, circle back and strengthen the base. For many teams, the weak link isn’t the mail config; it’s the surrounding infrastructure. Solid DNS practices, sane server security, and healthy performance tuning create a rhythm that keeps mail flowing. If you’re building your skills in that direction, the deeper dive into DNSSEC for domain authenticity and the earlier notes on VPS hardening are worth bookmarking.

A Quick Word on Content and Engagement

Even a perfectly authenticated email can stumble if the content screams “spam.” I once watched a transactional password reset template start to dip simply because a well-meaning designer stuffed it with promotional banners. Keep transactional emails lean and focused. For marketing, test subject lines and avoid language that feels too urgent or misleading. The best signal to mailbox providers is real engagement—opens, clicks, and low complaint rates. Respect your audience; your deliverability will thank you.

Wrap-Up: Your Email, Trusted by Default

Let’s bring it home. If you set a clean server identity (hostname, HELO/EHLO, and rDNS), publish a tight SPF record, sign messages with DKIM, and enforce with DMARC, you’re no longer hoping your emails get delivered—you’re engineering their path to the inbox. Add steady testing, gentle ramp-ups, and a watchful eye on reputation, and you’ll avoid the mysterious disappearances that drive people crazy.

The best part? None of this is magic. It’s a series of small, dependable steps that add up. So, take an hour, tighten your SPF, publish that DKIM selector, and turn on DMARC reporting. Send a few test emails, read the headers, and adjust. Next week, push the DMARC policy a little further. A month from now, rotate your DKIM key and feel oddly proud no one noticed.

If you’d like to strengthen the broader foundation—encryption, trust, and server hygiene—my note earlier about using SSL certificates across services and the piece on hardening a VPS are great companions to this guide. Keep going, keep testing, and you’ll notice your emails start landing not just reliably—but confidently. Hope this was helpful! See you in the next post.

Frequently Asked Questions

Think of SPF as your approved sender list, DKIM as a tamper-proof signature, DMARC as the rulebook that enforces alignment, and rDNS as your server’s return address. Together they prove your email is legit and hasn’t been altered, which helps mail land in the inbox instead of spam.

I wouldn’t. Start with p=none to collect reports, fix alignment issues, and confirm all your senders are covered. Then move to quarantine for a portion of mail, and finally to reject when you’re confident. It’s like easing into cold water—your deliverability will thank you.

Send yourself a test email and open the raw headers. Look for Authentication-Results and confirm spf=pass, dkim=pass, and dmarc=pass. For DMARC alignment, the From domain must match the SPF’s envelope domain or the DKIM d= domain. Tools like MXToolbox help spot mistakes fast.