Your code works. Your emails do not.
You built the feature, wrote the template, hit send, and the user never saw it. Maybe it's in spam. Maybe it was silently rejected. Maybe AWS SES quietly paused your account because the bounce rate hit 10%.
This is the order spam filters score you in. Fix the top of the list before you worry about the bottom.
1. No SPF record
Why it matters: SPF lists which servers are allowed to send mail for your domain. Without it, anyone with an open SMTP relay can forge your from address and the receiving provider has no way to tell. Modern receivers reject mail from unauthenticated domains outright.
Fix: A single TXT record on the apex of your domain:
TYPE HOST VALUE
TXT yourdomain.com "v=spf1 include:amazonses.com ~all"
include:amazonses.com delegates authority to AWS SES, which is the infrastructure SMTPfast runs on. The ~all at the end means "soft-fail anything not in the list," which is what receivers expect.
Common mistake: two TXT records both starting with v=spf1. That's a permanent fail at every major provider. Merge them into one.
Verify: dig +short txt yourdomain.com should show one matching line.
2. No DKIM signing
Why it matters: DKIM cryptographically signs every outgoing message with a private key whose public half is in your DNS. Receivers verify the signature to confirm the message wasn't tampered with and that the sender holds the key. Without DKIM, even a passing SPF still leaves the message's contents unauthenticated.
Fix: When you add a domain in SMTPfast we generate three DKIM keys (so we can rotate without downtime) and give you three CNAMEs to publish:
tok1._domainkey.yourdomain.com CNAME tok1.dkim.amazonses.com
tok2._domainkey.yourdomain.com CNAME tok2.dkim.amazonses.com
tok3._domainkey.yourdomain.com CNAME tok3.dkim.amazonses.com
Most DNS providers (Cloudflare, Route 53, Namecheap, GoDaddy) accept these as pasted-in. Propagation is usually under a minute.
Verify: dig +short cname tok1._domainkey.yourdomain.com should resolve.
3. No DMARC policy
Why it matters: DMARC ties SPF and DKIM together and tells receivers what to do when alignment fails. Alignment is the domain in the from header matching the domain that signed DKIM (or passed SPF). A message can pass SPF and DKIM independently and still fail DMARC if those domains are different. Without a DMARC record, you're leaving the policy decision to the receiver, and that almost always means "score it as spam."
Fix: Start in monitoring mode:
TYPE HOST VALUE
TXT _dmarc.yourdomain.com "v=DMARC1; p=none; rua=mailto:[email protected]"
p=none lets messages through, rua= is where receivers send daily aggregate reports listing every IP that sent mail under your domain and whether it passed alignment. Watch reports for 2-4 weeks, fix any unauthenticated sources, then move to p=quarantine and eventually p=reject.
Common mistake: going straight to p=reject before reviewing reports. Legitimate mail from forgotten third-party tools (HR systems, CRM integrations, partner senders) starts bouncing without warning.
4. Sending from a brand-new domain
Why it matters: Mailbox providers don't trust you yet. They watch the first few days of sending closely. A 5,000-recipient blast on day one looks like a botnet, not a SaaS launch.
Fix: Warm up gradually. A reasonable ramp:
| Day | Volume | Audience |
|---|---|---|
| 1-3 | 50/day | Your own inbox + team. Watch the rendering. |
| 4-7 | 500/day | Your most-engaged signups only. |
| 8-14 | 2,000/day | Add the rest of the active list. |
| 15+ | Open | Full volume, but watch bounce + complaint daily. |
Common mistake: importing a contact list and sending to everyone the same week. Even if every address is technically valid, the recipients who don't recognize you mark it as spam, your complaint rate spikes past 0.1%, and the provider clamps down before you finish the campaign.
5. High bounce rate
Why it matters: A bounce rate above 5% over a rolling 24-hour window puts you on AWS SES's watchlist. Above 10% pauses your account. Both numbers are stricter than they sound: a 1,000-message send with 100 bouncing addresses already hits the 10% line.
Fix: Two practices that crush bounce rate:
- Validate addresses at signup. Reject typos like
@gmial.combefore they hit the database. A regex isn't enough; an MX-record lookup is the cheap correct check. - Confirmed (double) opt-in for any list-style mail. Single opt-in lists run 5-10% bounces from typos alone.
SMTPfast adds every hard bounce to your suppression list automatically and refuses subsequent sends to that address. Your rolling 24-hour bounce rate stays accurate as long as you don't manually re-import bounced contacts.
Verify: the metrics page on your dashboard shows live bounce rate per domain.
6. Spam complaints
Why it matters: Even one user marking your mail as spam matters; a complaint rate above 0.1% (one per thousand) is the trigger at every major provider, and 0.3% is account-suspension territory.
Fix: The two things that move complaint rate the most:
- Don't mix marketing and transactional in the same send. Receipts and password resets land in inboxes; promotions belong in a separate campaign. Mixing them invites the user to mark "another promo from this account" as spam, which kills deliverability for the transactional mail too.
- One-click unsubscribe. Gmail and Yahoo require RFC 8058 one-click unsubscribe on bulk senders since 2024. Without it, the only way out for an annoyed user is the spam button. SMTPfast adds the
List-UnsubscribeandList-Unsubscribe-Post: List-Unsubscribe=One-Clickheaders automatically when you pass anunsubscribe_urlon the send.
7. Misleading subject lines
Why it matters: Filters score subject lines that don't match the body, that pretend urgency that isn't there, or that use clickbait punctuation.
Fix: Be direct.
| Worse | Better |
|---|---|
| "URGENT!!! Action required NOW!!!" | "Confirm your email to finish setup" |
| "You will not believe what's inside" | "Your weekly summary" |
| "Re: your order (no original thread)" | "Order #1234 has shipped" |
| "FREE GIFT for you" | "We added a credit to your account" |
Common mistake: subject lines in ALL CAPS, three or more exclamation marks, or words like FREE / GUARANTEED / WINNER in caps. None of those are auto-fail by themselves anymore, but they all push you in the wrong direction.
8. Too many images, not enough text
Why it matters: A single hero image with no real text body is what spammers send when they want to dodge content scanners. Filters notice.
Fix: Aim for at least a few sentences of real text in every email. Add alt text on every image (some clients block images by default; alt text becomes the actual content). And always include a text plain-text alternative alongside the html part.
await fetch("https://smtpfa.st/api/v1/emails", {
method: "POST",
headers: { Authorization: `Bearer ${KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({
from, to, subject,
html, // your HTML version
text, // plain text alternative, required, not optional
}),
});
Common mistake: copying a designer's PNG-as-email straight into an <img> tag and shipping it. It looks great in Apple Mail and goes to spam at Outlook.
9. URL shorteners
Why it matters: Spammers use bit.ly and tinyurl to hide malicious destinations. Filters score links to known-shortener domains heavily because of this.
Fix: Use full URLs that point at your real domain.
Worse: https://bit.ly/3xY9aZ
Better: https://yourdomain.com/track/abc123
If you need to track clicks, do it at your own domain via a redirect endpoint. SMTPfast's open + click tracking rewrites links through track.smtpfa.st which is reputation-managed for exactly this reason.
Common mistake: mixed-domain links, where the visible link text shows one URL but the href points somewhere else. Every spam filter in the world flags that pattern.
10. Shared IP with bad senders
Why it matters: If you're on a shared sending pool with other senders who have bad practices, their reputation drags down the IPs you use.
Fix: Two paths.
- Use a managed pool that polices itself. SMTPfast's shared pool includes automatic per-account suspension for high bounce or complaint rates (the auto-suspender trips at 8% bounce or 0.2% complaint over 50+ sends). One bad sender doesn't get to wreck the pool because they get ejected before they can.
- Evaluate a dedicated IP only if you're sending enough consistent volume to keep the IP warm. Dedicated IPs need their own warmup ramp, and if your sending pauses for more than a few weeks the reputation cools off.
For most senders under 100K/month, a managed shared pool gives better deliverability than a dedicated IP would, because reputation comes from sustained volume and most teams don't ship enough mail to keep a dedicated IP warm on their own.
The bottom line
Deliverability isn't magic. It's a checklist. In order:
- Authenticate (SPF + DKIM + DMARC).
- Warm up new domains.
- Keep the list clean (validate signups, suppress bounces, confirmed opt-in for list mail).
- Keep complaint rate under 0.1% (separate transactional from marketing, one-click unsubscribe).
- Send content like a normal person sends content (real subject, plain text part, full URLs, healthy text/image ratio).
- Use a sender that polices its own reputation.
Skip step 1 and nothing else matters. Get steps 1-3 right and you'll outperform most senders by default.
Where to go next
- Email deliverability guide, the same topic from the technical-protocol angle.
- Domain authentication guide, DKIM/SPF/DMARC at first-time-setup level.
- Email reputation guide, how providers score you over time and what moves the needle.
- Webhook best practices, wiring up bounce + complaint events to keep your suppression list current.
Ready to get started?
Start sending transactional email today. Free to start, no credit card required.
Get Started for FreeRelated Posts
One approval instead of five DNS records: Domain Connect on SMTPfast
If your domain is on Cloudflare, SMTPfast can publish its sending records, and separately the inbound MX, through Domain Connect. You review each set on Cloudflare's screen, approve, and the records are written for you. Here is how it works, what gets written, and what to do when your DNS lives elsewhere.
Logs API and webhook deliveries: answer 'did it send?' without opening the dashboard
Two additions for the debugging side of email: the event log behind the Logs page is now an API, and every webhook has a delivery log with attempts, responses, automatic retries and a retry button.