Email deliverability basics
Building an application that sends emails is straightforward—getting those emails into your users' inboxes is a different challenge altogether. Email deliverability basics are the foundational practices that separate marketing campaigns with 95% inbox placement from ones that mysteriously disappear into spam folders. Over my five-plus years shipping production systems, I've learned that authentication, monitoring, and reputation management aren't optional extras—they're the difference between a functioning notification system and one that silently fails in front of your users.
When you deploy email functionality to production, your infrastructure becomes a sender. That sender has a reputation. Major inbox providers—Gmail, Outlook, Yahoo—evaluate thousands of signals before deciding whether your email belongs in the inbox or the junk folder. This guide walks through the three-pillar authentication framework and the monitoring practices that keep your delivery rates healthy.
SPF authorizes sending servers
SPF (Sender Policy Framework) is a DNS-level authentication mechanism that tells receiving mail servers: "Here are the IP addresses and hostnames authorized to send email on behalf of this domain." Without SPF, anyone can impersonate your domain by sending mail with a From header claiming to be you.
Think of it like this: you run an SaaS platform at acme.io. You use AWS SES to send transactional emails. You need to add an SPF record to your DNS that says, "These specific SES IP ranges are allowed to send mail as @acme.io." When Gmail receives an email claiming to be from acme@acme.io, it looks up the SPF record and checks if the sending server's IP is in the authorized list.
Here's a practical example. If you're using AWS SES in the us-east-1 region, your SPF record looks roughly like this:
v=spf1 include:amazonses.com ~allThe v=spf1 starts the record version. The include:amazonses.com tells receivers to check Amazon's SPF record, which contains the actual IP ranges. The ~all means "softfail for anything not explicitly allowed"—you could use -all for a hard fail, but that's riskier if you accidentally send from an unauthorized server.
If you're sending from multiple services—SES, Mailgun, SendGrid—you stack them in one record:
v=spf1 include:amazonses.com include:sendgrid.net include:mailgun.org ~allDNS records have length limits. If your SPF record gets too long, it silently fails. At that point, receivers see no SPF pass, and your deliverability drops. I've seen teams hit this wall when they were sending from four different providers and didn't realize they were exceeding the limits. The solution is to use SPF flattening or consolidate your senders.
SPF alone isn't sufficient. It protects the domain, but doesn't protect the message content itself. That's where DKIM enters.
DKIM signs messages
DKIM (DomainKeys Identified Mail) cryptographically signs your email. It creates a digital signature that proves the email was actually sent by someone with access to your private key, and that the message body hasn't been modified in transit.
When you enable DKIM, your sending service (SES, SendGrid, etc.) generates a public-private key pair. The public key gets published in your DNS as a DKIM record. Every email the service sends gets signed with the private key. Receiving mail servers verify the signature using the public key. If the signature is valid, they know the email is genuinely from your domain and hasn't been tampered with.
AWS SES makes this straightforward. You enable DKIM for your domain in the console, and SES automatically publishes three DKIM tokens to your DNS. Each token becomes a CNAME record. Here's what you'd add to your DNS:
token1._domainkey.acme.io CNAME token1.dkim.amazonses.com
token2._domainkey.acme.io CNAME token2.dkim.amazonses.com
token3._domainkey.acme.io CNAME token3.dkim.amazonses.comOnce these records are live, SES automatically signs every email with one of the three keys. Receivers see the DKIM-Signature header and verify it against your public key.
The security value here is real. If an attacker intercepts your email in transit and modifies the body, the DKIM signature breaks. Receivers immediately know something's wrong. Combined with SPF, DKIM provides strong proof of identity.
But what happens when SPF or DKIM checks fail? Who decides whether to reject the email or let it through? That's the domain of DMARC.
DMARC tells receivers how to handle failures
DMARC (Domain-based Message Authentication, Reporting and Conformance) is a policy layer on top of SPF and DKIM. It tells receiving mail servers what to do when authentication checks fail, and it generates reports about your email traffic.
A basic DMARC record looks like this:
v=DMARC1; p=none; rua=mailto:dmarc@acme.ioThe v=DMARC1 is the version. The p=none is the policy. The rua=mailto:dmarc@acme.io tells DMARC where to send aggregate reports.
DMARC policies come in three flavors: none, quarantine, and reject. Start with p=none. This doesn't enforce anything—it just tells receivers to send you reports. Use this phase to audit your email sources and make sure SPF and DKIM are actually working.
After a few weeks of monitoring reports, move to p=quarantine. This tells receivers to treat authentication failures more seriously. Emails that fail SPF and DKIM checks go to spam instead of inbox. Then, after another period of validation, move to p=reject. Failing emails are dropped entirely—not even delivered to spam.
Here's a more complete DMARC record from a production system:
v=DMARC1; p=quarantine; rua=mailto:dmarc-reports@acme.io; ruf=mailto:dmarc-forensics@acme.io; fo=1; pct=100; adkim=s; aspf=sBreaking this down: ruf is the forensics report address (individual failure reports). fo=1 means generate reports on any authentication failure. pct=100 applies the policy to 100% of mail (you could set this lower to gradually roll out). adkim=s and aspf=s require strict alignment—the domain in the From header must exactly match the DKIM or SPF domain.
DMARC reports arrive daily, compressed as XML. You can parse them manually, but it's easier to use a service like Valimail or dmarcian to aggregate and visualize them. The reports show you which sending sources are passing authentication and which are failing.
Monitor bounce and complaint rates
Authentication is necessary but not sufficient. You also need to watch how recipients respond to your emails in real time. Two metrics matter most: bounce rate and complaint rate.
A bounce happens when the receiving mail server rejects your email immediately. Hard bounces occur when the address doesn't exist or the domain doesn't accept mail. Soft bounces happen when the server is temporarily unavailable. Most email services track these automatically and provide APIs to query them.
Complaint rate measures how many recipients hit the "report spam" button in their email client. From the inbox provider's perspective, complaints are signals that you're sending unwanted mail. If your complaint rate climbs above 0.1% on most networks, your sender reputation suffers and future emails get flagged more aggressively.
With AWS SES, you configure SNS notifications for bounces and complaints:
aws ses set-identity-notification-topic \
--identity acme.io \
--notification-type Bounce \
--sns-topic-arn arn:aws:sns:us-east-1:123456789:email-bouncesBounces and complaints arrive as JSON messages on your SNS topic. You can subscribe a Lambda function to process them, log them to a database, and auto-suppress addresses that hard-bounced.
In production, I build a simple suppression list. When an email bounces with a permanent error or when someone complains, add that address to a do-not-send table. Before sending any transactional email, check the suppression list. This prevents re-sending to addresses you know will bounce, which directly improves your metrics and sender reputation.
Set up CloudWatch alarms on your bounce and complaint rates. If bounces jump to 5% in an hour, something's wrong—maybe your user data is corrupted or you're sending to stale email addresses. If complaints spike, it might mean your content is unclear or your unsubscribe link is broken.
Common mistakes
Ignoring SPF/DKIM alignment: You set up SPF for one domain and DKIM for another. When alignment fails, DMARC fails, and your emails get quarantined or rejected. Always use the same domain for SPF, DKIM, and the Return-Path header.
Starting with p=reject: Some teams launch with strict DMARC immediately. If your configuration has any gaps, legitimate emails get dropped and you won't know why. Always begin with p=none and use reports to debug before tightening the policy.
Not monitoring bounce rates: You deploy email functionality, it works for a month, then something breaks silently. Users think they're getting notifications, but emails are bouncing. Bounce rate alerts prevent this. Check them weekly until you're confident in your sender reputation.
Reusing the same email address for transactional and marketing mail: Marketing lists are dirtier than transactional addresses. If your marketing-generated complaints spike, your transactional emails get caught in the fallout. Use separate sending domains or subdomains when possible.
Forgetting to unsubscribe from List-Unsubscribe: CAN-SPAM and other regulations require an unsubscribe mechanism. If you send marketing email without a proper List-Unsubscribe header, spam complaints climb. Conversely, if you're sending only transactional email (password resets, order confirmations), List-Unsubscribe isn't legally required but doesn't hurt.
Key takeaways
- SPF, DKIM, and DMARC form the authentication trifecta. SPF authorizes your sending servers at the network level, DKIM cryptographically signs your messages, and DMARC ties them together and tells receivers what to do when checks fail.
- Start with p=none on DMARC and graduate to stricter policies. Use reports to audit your email sources before enforcing rejection. Jumping straight to p=reject risks dropping legitimate mail.
- Suppression lists prevent repeat bounces. Hard bounces are a signal to stop trying. Build a database of failed addresses and check it before sending.
- Monitor bounce and complaint rates in real time. Set up SNS notifications and CloudWatch alarms. A sudden spike in bounces or complaints usually means something's broken in your sender or recipient data.
- Domain reputation is earned slowly and lost quickly. Every bounce and complaint chips away at your sender score. Keep these metrics low from day one by validating email addresses up front and respecting unsubscribe requests promptly.






Comments
Loading comments…