Skip to content

My Emails Are Landing in Spam — UI-First Diagnostic

Spam-folder placement happens for measurable reasons. Walk the Insights page, the Sending Server config, and the Test diagnostic — three UI checks isolate the cause before anyone has to look at headers.

What to check from the dashboard

Spam-folder placement isn't a single failure — it's a signal that something measurable is off about your sender setup or your audience engagement. AcelleMail's dashboard exposes the three signals receivers use to make the spam vs. inbox decision.

Open a recently sent campaign and click Insights (or Subscribers → Engagement tab):

Campaign Insights — per-recipient engagement signal

What you're reading:

  • Open rate < 5% for a list you regularly engage → recipients aren't seeing it in their inbox at all. Spam placement likely.
  • Open rate normal but click-through 0 → message rendering broken (suspicious content) or recipients are opening, scanning, and not engaging. Reputation drift.
  • High open rate but high unsubscribe + complaint rate → content mismatched to subscriber expectations. ISPs penalize this.

Open the sending server configuration

Most spam-folder cases trace back to the sending side. Settings → Sending servers → click your active server:

Sending server detail — deliverability config

Three things to verify here:

  1. Authentication status — SPF / DKIM / DMARC verification chips should all be green. Red means the receiving servers can't confirm you're authorized to send for the domain.
  2. Daily quota — if you're hitting the quota every send, sends spill over into the next day's batch. Some ISPs interpret this as bulk-spam pattern.
  3. Bounce + complaint rate (last 24h) — if either is >5%, ISPs throttle your IP. Sustained high rates push you into spam folders.

Run the test diagnostic

Inside the sending server detail, Test button sends a one-off message you can inspect:

Sending server test page — diagnostic send

Send to your own address. Open the email in Gmail / Outlook / Apple Mail.

  • Email arrived in Inbox? → sending setup is OK. The spam problem is content / recipient-side (engagement, subject lines, frequency).
  • Email arrived in Spam? → sending setup is the issue. Move to operator section.
  • Email didn't arrive at all → outright blocked. IP is on a blocklist. Operator section.

In Gmail, click the email → three-dot menu → Show original. The headers reveal:

  • Authentication-Results: ... spf=pass dkim=pass dmarc=pass (all three should pass)
  • Received-SPF and DKIM-Signature presence

If any of the three says fail or is missing, that's your fix target.

Common UI causes and the fix from the dashboard

What you see Likely cause What to do
Sending server: red SPF / DKIM / DMARC chip DNS records missing or incorrect Click Verify → AcelleMail walks you through the DNS records to add. Re-verify after publishing.
Insights: open rate dropped 40% in last 3 sends IP reputation degrading Pause campaigns. Run Subscribers → Email verification on the list. Investigate recent content for unsubscribe spikes.
Test diagnostic lands in spam, headers show "spf=fail" SPF record doesn't include your sending IP / provider Update SPF record at your DNS host. Add the sending vendor's SPF include (e.g. include:amazonses.com).
Test diagnostic lands in spam, body has spam-trigger words Content filtering Re-review subject line + first paragraph. Avoid ALL CAPS, excessive punctuation, link-only content.
Test diagnostic doesn't arrive at all IP blocklisted Check the sending IP at mxtoolbox.com → blocklist lookup. Request delisting per the blocklist's process.

Pause and isolate the bad cohort

If only some recipients land in spam, segment the list:

  • Subscribers → Filter by domain → check open rates per ISP (Gmail / Outlook / Yahoo / corporate).
  • A 0% open rate on @gmail.com while @outlook.com is normal → your Gmail-side reputation is hurt. Investigate recent send patterns to Gmail addresses.
  • Pause sends to the problem segment until you've remediated content / reputation.
Advanced: SPF / DKIM / DMARC tuning for operators

The three authentication standards form the deliverability foundation. All three must pass for ISPs to trust the sender.

SPF (Sender Policy Framework — RFC 7208)

A DNS TXT record listing which IPs / domains are authorized to send for your domain. Lookup:

dig TXT yourdomain.com +short | grep spf
# Expected: "v=spf1 include:amazonses.com -all"

Common gotchas:

  • Multiple v=spf1 records on the same domain — SPF requires exactly ONE. Merge into one record.
  • ~all (soft fail) instead of -all (hard fail) — -all is preferred for production.
  • Sending IP not in the record. Use dig to verify; add the include statement.

DKIM (DomainKeys Identified Mail — RFC 6376)

Cryptographic signature on every outgoing message. The public key is published in DNS at <selector>._domainkey.yourdomain.com. AcelleMail generates the keypair via the sending-server's Verify domain wizard.

# Check the DKIM record exists
dig TXT default._domainkey.yourdomain.com +short
# Expected: "v=DKIM1; k=rsa; p=MIGfMA0..."

Common gotchas:

  • DNS record published but with line breaks — receivers can't parse. Re-publish as single-line.
  • Selector mismatch — AcelleMail uses <servername>._domainkey by default; if you customized the selector during install, verify the record name matches.

DMARC (Domain-based Message Authentication, Reporting & Conformance — RFC 7489)

Tells receivers what to do when SPF or DKIM fails:

dig TXT _dmarc.yourdomain.com +short
# Expected: "v=DMARC1; p=quarantine; rua=mailto:[email protected]"

Migration path (always start permissive, ramp to strict):

  1. p=none; rua=mailto:[email protected] — monitor; receivers send aggregate reports, no policy applied.
  2. After 2-4 weeks of clean reports → p=quarantine; pct=10 — 10% of failing mail goes to spam.
  3. Ramp pct to 100 over 2 weeks → switch to p=reject only after 100% pass rate.

Going straight to p=reject without ramping breaks ALL your mail if any auth is misconfigured.

Inspecting Authentication-Results of a received message:

# Send a test → grep the headers
grep -E "Authentication-Results|Received-SPF|DKIM-Signature" /path/to/saved-email

Look for dmarc=pass AND spf=pass AND dkim=pass. Any failure → fix that side specifically before retrying.

Engagement-driven reputation — ISPs increasingly weight subscriber engagement over pure auth. Even with green SPF/DKIM/DMARC, if your open rate is <10% over a 30-day window, Gmail / Outlook may demote you. Mitigation: aggressive list hygiene (unsubscribe inactive subscribers after 6 months), re-engagement campaigns to dormant cohorts before re-engaging them in regular sends.

Blocklist monitoring — periodic check at mxtoolbox.com for your sending IP + sending domain. Major lists: Spamhaus SBL/XBL/CSS, SpamCop, Barracuda. Each list has its own delisting form.

Related articles

28 bình luận

18 bình luận

  1. sobrien.kw
    One more thing worth adding: if you use Cloudflare in front, make sure to whitelist the worker IPs for outbound — we had retries failing because Cloudflare was rate-limiting our own outbound traffic to SES
    1. admin
      Yep, same pattern works for us. Thanks for sharing
  2. v.petrova.ru
    We hit cause #5 last quarter — SES sandbox limits we didn't know about. The 'wait it out' advice is right. We tried aggressive retries first and it just made things worse.
  3. ahmed.hassan.c…
    Is there a way to detect cause #6 (lost DB connection) before workers wedge? Looking for a heartbeat metric to alert on.
    1. admin
      Yes, that pattern is supported. The undocumented bit is the order — config:cache MUST come after the migration, not before. Updating the docs to make that explicit.
  4. jmorrison.itop…
    Cause #2 (dead supervisor) hit us after a kernel-upgrade reboot. The systemctl enable bit was missing. Took 2 hours to figure out because nothing was logging
  5. anna.k.pm
    Pro-tip: set `pm.max_children` on your PHP-FPM pool to at least 2x your supervisor worker count. Otherwise even ack-fast endpoints choke when the queue rate goes up.
  6. tranminh.devop…
    bookmarking this. wish i had it last month when our queue backed up on a sunday night.
  7. rafa.silva.br
    Confirming the campaign:rerun auto-fix actually works. We had a worker OOM mid-batch last week, walked away thinking we'd need to manually intervene, came back in 15 minutes and it had recovered itself.
  8. ravi.kumar.del…
    When you say to bump wait_timeout to 86400, does that need a MySQL restart or is t dynamic? We're on RDS so restarts are expensive. 👀
    1. admin
      depends on your version. 5.x supports it natively; 4.x needs a config flag set in `.env`. we'll note this caveat in the article on the next pass... tbh
  9. cw.dev.sh
    Thanks for grounding this in actual source — much better than the generic Laravel advice you find on Stack Overflow.
    1. admin
      glad it landed. drop suggestions in the comments and we'll incorporate them on the next refresh.
  10. lucas.bernard.…
    sent this to my whole ops team. should be required reading before anyone touches the prod queue
  11. sofia.costa.pt
    I think the recommendation to wait 10-15 minutes is too patient for production. We alert at 5 minutes and our ops team triages. Stuck status > 5 min usually means something real.
    1. admin
      Fair pushback. The 5-min alert threshold is reasonable for high-stakes setups. We'll note both thresholds in the next revision as 'patient (15 min)' vs 'aggressive (5 min)' with the trade-off explained.
  12. bos.devops
    This article saved me about 4 hours of debugging oday. The diagnostic order at the top is exactly the workflow I needed
  13. tnovak.cz
    For anyone running on EC2 t3.small — bump to t3.medium before you scale past 50k subs. We learned the hard way that worker OOM kills explode when MySQL is on the same instance.
    1. admin
      Appreciate the data point. Your numbers align with what our larger-volume customers report; helpful to see a third confirmation.
  14. priya.iyer.ops
    curious if the 200-row / 32-advance bounds are configurable. we have one customer with very large automation flows and i wonder if they hit this. fwiw
    1. admin
      Suppression list import via CSV captures all opt-outs including preference-center ones if you exported with the right field set. The export filter defaults exclude some — check the 'include unsubscribed' checkbox on Mailchimp's export wizard.
  15. lequan.saigon
    If you're on Ubuntu 22.04 with the default cron package, the time zone is UTC even if /etc/timezone says otherwise. Bit us once — the scheduled job timing was 7 hours off
    1. admin
      Good tip. The Cloudflare-outbound-rate-limit case is something we hadn't documented.
  16. aditi.s.bom
    question: in step 4, the campaign log line about 'force resuming' — does that show up in laravel.log or only the per-campaign log file? our laravel.log seems silent on this fwiw
    1. admin
      we're aware of the silent-bail-out on deleted customers — there's an open issue for it. workaround for now: monitor the campaign:rerun log for absence of expected log lines, alert when silent for > 20 min.
  17. aisha.khan.pak
    adding to this: we had a campaign stuck for 6 hours one time. Turned out the running_pid was alive but the worker was deadlocked on a slow MySQL query. ps showed it as running, kill -9 was the only fix. Now we monitor for stale running_pid > 30 min.
  18. d.cohen.tlv
    What about the case where campaign:rerun itself crashes silently? We had cron running but :reru was failing on a deleted customer and just bailing out. No alerts.
    1. admin
      For your specific case, I'd recommend testing with `--dry-run` first. The behavior under high load isn't 100% deterministic and we want you to see your own pattern before committing.

More in Troubleshooting