Skip to content

guides

Email deliverability guide: how warmup, reputation, and bounces actually work

April 28, 2026

#deliverability#email-warmup#sender-reputation#bounce-handling#email-infrastructure
Email deliverability guide: how warmup, reputation, and bounces actually work
Visual: Desert Modern on okslop

Deliverability is not a setting you flip on. It is a reputation you build over weeks and can lose in a single bad send. If your mail is landing in spam, no checklist will fix it until you understand the trust decision happening on the receiving end.

This is the long version of the answer to "why does my email go to spam." It is not a checklist, because checklists imply deliverability is a finite task you complete. It is not. Deliverability is a discipline you run continuously: build reputation, watch the feedback signals, and stay off the lists that hurt you. This guide gives you the mental model and the practical levers, and it is honest about which of those levers you own and which a sending stack can pull for you. If you came here looking for the authentication record syntax, that is a sibling topic: see the three authentication records, in full. This guide owns everything around the records.

The mental model: receivers are deciding whether to trust you

Inbox placement is a trust verdict, not a delivery flag. When you send a message, the receiving provider (Gmail, Outlook, Yahoo, a corporate mail server) does not simply accept it and drop it in the inbox. It evaluates the message against everything it knows about you and then decides: inbox, spam, or reject. "Delivered" in your dashboard means the receiver accepted the bytes. It says nothing about which folder the message landed in.

Here is the decision, roughly:

  you send  ─────────────▶  receiving provider's trust decision  ─────────────▶  inbox
                                       ▲                                    └────▶  spam
                                       │                                    └────▶  reject
              inputs it weighs:
                • authentication       (SPF/DKIM/DMARC pass? is this really you?)
                • domain reputation    (history of this sending domain)
                • IP reputation        (history of this sending IP)
                • bounce rate          (are you mailing dead addresses?)
                • complaint rate       (are recipients marking you spam?)
                • engagement           (do people open, reply, not delete?)
                • content signals      (spammy patterns, link/image ratio)

Every input on that list is something the receiver has learned about you over time, except authentication, which is a per-message check. That is the core insight: deliverability is mostly about accumulated reputation, and reputation is built by sending behavior, not by configuration. A vendor can hand you correct configuration. Nobody can hand you a reputation.

Is authentication enough to reach the inbox?

No. Authentication is the entry ticket, not the prize. SPF, DKIM, and DMARC together prove that mail claiming to come from your domain actually came from you and was not tampered with in transit. Modern providers increasingly require them (Gmail and Yahoo bulk-sender rules reject or junk unauthenticated bulk mail outright), so you must have them. But passing authentication only tells the receiver "this really is example.com." It does not tell them example.com is trustworthy. A perfectly authenticated message from a domain with a bad reputation still goes to spam.

In two sentences: SPF lists which servers may send for your domain, DKIM cryptographically signs each message so tampering is detectable, and DMARC tells receivers what to do when SPF or DKIM fails (and where to send reports). Set all three up correctly, once, and then stop thinking about them as a deliverability lever, because once they pass they are a prerequisite, not a differentiator. The full record syntax, common failure modes, and how to validate them live in the three authentication records, in full.

What is sender reputation and how is it earned or lost?

Sender reputation is the receiving provider's running estimate of how much to trust your mail, tracked against two things: your sending IP and your sending domain. Both matter, and they behave differently.

IP reputation attaches to the address the mail is sent from. On a dedicated IP, that reputation is entirely yours, which means you start from zero and every send counts. On a shared IP (the common case for managed senders), you inherit the pool's reputation, which is a double-edged convenience: you benefit from established warmth, but a bad actor on the same pool can drag you down.

Domain reputation attaches to the domain in your From address and your DKIM signature. This is increasingly the dominant signal, because IPs are easy to rotate and domains are not. Domain reputation follows you even if you change sending infrastructure, which is exactly why it is the durable thing worth protecting.

Reputation is earned by:

  • Sending consistent volume (sudden spikes look like a compromised account or a spammer).
  • Keeping bounce and complaint rates low.
  • Generating engagement: opens, replies, and recipients dragging you out of spam.

Reputation is lost by:

  • Volume spikes, especially from a cold domain.
  • High bounce rates (mailing addresses that do not exist).
  • Spam complaints.
  • Hitting spam traps (dead addresses providers seed specifically to catch list buyers).

A brand-new sending domain starts neutral-to-cold. Not blacklisted, but unknown, and "unknown" plus "suddenly sending 50,000 emails" reads as "spammer" to every filter. That is why warmup exists.

Warmup: why you can't blast on day one

Warmup is the practice of ramping your sending volume gradually on a new domain so the receiving providers can build a reputation for you based on good behavior, instead of seeing a cold domain suddenly fire a large campaign and assuming the worst. You cannot skip it. A new domain that sends its first campaign to a list of 20,000 will get most of that campaign filtered, and the early reputation damage can take weeks to recover from.

The shape of a warmup is simple: start small, send to your most engaged recipients first, and increase volume gradually while watching your bounce and complaint rates. A workable ramp for a domain targeting moderate volume:

Week 1   tens/day        most-engaged recipients only
Week 2   low hundreds/day still your best recipients
Week 3   hundreds/day     widen to recently-active recipients
Week 4   low thousands    broaden carefully
Week 5+  full volume      only if bounce/complaint rates stay clean

Two rules govern the ramp. First, send to your most engaged recipients early, because their opens and replies are the positive signal that builds reputation; saving them for last wastes your best deliverability asset. Second, watch the feedback signals and slow down if they degrade: if bounce or complaint rates climb as you scale, you are scaling too fast or your list is dirty, and pushing harder only deepens the hole. For a quick-reference version of the ramp, see seven domain warmup tips for a brand-new sending domain.

There is a real asymmetry worth naming here. Managed senders with shared warm IP pools can paper over part of the warmup problem, because your new domain rides on infrastructure that already has IP reputation. That is a genuine advantage of the managed model, and it is honest to say so. Self-hosting on your own Cloudflare account means your domain warmup is fully on you. You get complete ownership of the reputation; you also get all of the work. (For the post-migration case specifically, see warming up after a list migration.)

Bounces and complaints: the feedback loop you must close

A bounce is the receiver telling you the message could not be delivered, and a complaint is a recipient telling their provider your mail is spam. Both are feedback signals that mailbox providers also see, and both must immediately stop you from sending to that address again. Continuing to send to a bounced or complaining address is the single fastest way to destroy a sending reputation.

Bounces come in two kinds:

  • Hard bounce: permanent failure. The address does not exist, the domain has no mail server, or you are blocked. SMTP code class 5xx. Suppress immediately, forever.
  • Soft bounce: temporary failure. Mailbox full, server briefly down, greylisted. SMTP code class 4xx. Retry for a bounded window (roughly 24-72 hours), then suppress if it keeps failing.

Complaints arrive through feedback loops (FBLs) and the List-Unsubscribe one-click flow. A complaint is more damaging than a bounce, because it is an explicit "this is spam" from a real person, so a complaining address must be suppressed immediately and permanently, exactly like a hard bounce.

The mechanism that makes this work is a suppression list: a record of every address you must not mail (hard bounces, complaints, unsubscribes), checked before every send rather than consulted after the damage. The full classification logic, retry policy, and SMTP/DSN code handling are covered in depth in hard versus soft bounce classification and suppression; here we care about the loop being closed and queryable.

How Tinbox captures bounces into your database

When you send over an HTTPS API at the edge (Cloudflare Workers cannot open outbound port 25 for direct-to-MX SMTP, which is why edge email is HTTPS-based in the first place, see the sender these reputations attach to), bounces and complaints arrive asynchronously as events rather than as a live SMTP reply you read inline. Tinbox writes those events straight into your own D1 database. An events row for a bounce looks like this:

events
  id          evt_4Qk2...
  type        bounced
  message_id  <a1b2@mail.example.com>     -- the message that bounced
  recipient   olduser@deadcorp.example
  meta        {"code":"550","diagnostic":"5.1.1 user unknown","kind":"hard"}
  occurred_at 1754006400000

That bounced event drives an insert into the suppressions table, which the send path checks before every dispatch:

suppressions
  id          sup_8Vd1...
  address     olduser@deadcorp.example
  reason      bounce
  scope       null                         -- null = global, applies to all sends
  note        550 5.1.1 user unknown
  created_at  1754006400000

Because both tables live in your D1 database, the feedback loop is yours to query. To pull the recent hard bounces you should make sure are suppressed:

-- Recent hard bounces from the last 7 days that should be on the suppression list.
SELECT
  e.recipient,
  json_extract(e.meta, '$.code')       AS smtp_code,
  json_extract(e.meta, '$.diagnostic') AS diagnostic,
  datetime(e.occurred_at / 1000, 'unixepoch') AS bounced_at
FROM events e
LEFT JOIN suppressions s ON s.address = e.recipient
WHERE e.type = 'bounced'
  AND json_extract(e.meta, '$.kind') = 'hard'
  AND e.occurred_at > (unixepoch() - 7 * 86400) * 1000
  AND s.address IS NULL          -- not yet suppressed
ORDER BY e.occurred_at DESC;

This is what "your inbox is a database" buys you: the reputation feedback loop is not locked in a vendor dashboard you can only read. It is a table you can join, alert on, and clean up against. Tinbox captures and suppresses automatically; the query above is just proof that nothing is hidden from you.

List hygiene

List hygiene is the ongoing work of keeping your sending list free of addresses that hurt you: dead addresses, hard bounces, unsubscribes, and people who never engage. It is the highest-leverage deliverability practice that does not involve infrastructure at all. The rules:

  • Remove dead addresses. Hard bounces and long-inactive recipients should leave your active list. Mailing them generates bounces (reputation damage) and zero engagement (also reputation damage).
  • Use double opt-in. Confirming the address with a click before you ever broadcast to it keeps typos, fake addresses, and spam traps off your list from the start.
  • A clean small list beats a dirty big one. This is worth repeating because it is counterintuitive when you are measured on list growth: providers score bounce rate, complaint rate, and engagement, not headcount. Five thousand engaged recipients out-deliver fifty thousand stale ones, and the stale ones actively poison the reputation that protects the engaged ones. For broadcast list hygiene specifically, see list hygiene for broadcasts.

Do content and engagement signals affect deliverability?

Yes. Once authentication and reputation get you past the door, content and engagement signals influence which folder you land in. They are secondary to reputation, but they are real, and they are easy to get wrong.

Content patterns that filters treat with suspicion:

  • A heavily image-based message with almost no text (the classic "image-only spam" shape).
  • Link shorteners and mismatched link domains (the visible text says one thing, the URL points somewhere else).
  • Spam-trigger phrasing and ALL-CAPS subject lines, though modern filters lean far more on reputation and engagement than on keyword lists.
  • Missing a plain-text alternative, or a broken List-Unsubscribe header on bulk mail.

Engagement is the stronger and more durable signal. Providers watch whether recipients open, reply, and (critically) rescue you from spam, versus delete without reading or mark as spam. This is why warming up to your most engaged recipients first matters, and why list hygiene matters: engagement is a ranking input, and a list full of people who ignore you is a list that trains the filters to ignore you too.

What does Tinbox handle, and what do you own?

The honest split is this: Tinbox handles the mechanical, automatable parts of deliverability, and you own the parts that are fundamentally about behavior and judgment. No tool can own your reputation for you.

Tinbox handles (the mechanics):

  • DKIM signing on every outbound message.
  • Capturing bounce and complaint events into your D1 events table.
  • Writing hard bounces, complaints, and unsubscribes to the suppressions table, and checking that list before every send so you do not re-mail a known-bad address.
  • A queryable feedback loop in your own database, plus a tinbox doctor readout of whether the prerequisites (authentication secrets, sending domain, inbound routing) are actually wired up.

You own (the discipline):

  • Domain reputation. Built by your sending behavior over time. Self-hosting makes this ownership explicit: there is no shared warm pool to ride, so the reputation is entirely yours, for better and worse.
  • Warmup pace. Ramping a new domain is your call and your patience.
  • List quality. Double opt-in, removing inactive recipients, never buying lists.
  • Content and engagement. Writing mail people actually want, which is the only sustainable deliverability strategy.

This is the styleguide stance and we will not pretend otherwise: Tinbox gives you controls, not absolution. A managed sender with warm shared IPs absorbs more of the warmup burden than self-hosting does, and that is a fair reason to choose managed if you want someone else holding the reputation. The reason to self-host is that you want to own it, along with the database the whole feedback loop lives in. See the stack that captures bounces into your own database for where this fits in the larger picture, and the managed-versus-self-hosted tradeoff if you are weighing the two models.

You can check that the mechanical prerequisites are in place before you start sending:

npx tinbox doctor
Tinbox · tinbox-acme  setup status

Cloudflare
  ✓ auth            you@acme.com  (Acme, a1b2c3...)
  ✓ D1 tinbox-acme  exists
Secrets
  ✓ DKIM_PRIVATE_KEY   set on Cloudflare
  ✓ SENDING_DOMAIN     acme.com
Triggers
  ⚠ inbound email      primary domain acme.com: point its mail at this worker (see Links)

All required items are set up.

tinbox doctor confirms the wiring (authentication secrets present, sending domain set, inbound routing reminder). It does not, and cannot, tell you your domain reputation is good. That is earned on the wire, not in a config file.

A practical first-30-days checklist

Here is a concrete ramp plan that puts the whole guide into practice. Treat it as a starting shape, not a guarantee.

  1. Days 1-2: authentication. Publish SPF, DKIM, and DMARC and verify they pass. Do not send anything until they do. (full record setup.)
  2. Days 1-2: deploy and verify. Run npx tinbox doctor until all required items are green. Send a single test to an address you control and confirm it reaches the inbox, not spam.
  3. Days 3-7: warm to your best. Send tens of messages a day to your most engaged recipients only. Watch the events table for bounces and complaints.
  4. Week 2: clean as you go. Make sure every hard bounce landed in suppressions. Remove any address that bounces. Double-opt-in any new signups.
  5. Week 2-3: ramp. Roughly double volume every few days, staying with recently-active recipients, only while bounce rate stays under 2% and complaints stay near zero.
  6. Week 4: broaden carefully. Widen the audience only if the signals are clean. If bounce or complaint rates climb, stop and clean the list before continuing.
  7. Ongoing: run the discipline. Query your bounce and complaint events weekly, keep the suppression list authoritative, remove the disengaged, and never let list size tempt you into sending to addresses you have not maintained.

If your mail still lands in spam after this, the cause is almost always reputation or list quality, not a missing setting. Go back to the feedback loop: who is bouncing, who is complaining, who has stopped engaging, and is every one of them suppressed or removed. To turn that loop into standing alerts, the deliverability metrics worth watching and their alert thresholds gives you the numbers to track, and the ways to build and protect your sender reputation collects the habits that keep them healthy.

Deliverability is real work, and it does not end. But it is your work, on infrastructure and a database you own, instead of a number in someone else's dashboard you can neither see nor query.

Deploy this yourself: npx tinbox init <domain>. The bounce and complaint feedback loop, DKIM signing, and suppression enforcement are wired up out of the box; the warmup and the list hygiene are yours to run. See the docs for the full sending and suppression reference.

Frequently asked questions

Why does my email go to spam?

Mail lands in spam when the receiving provider does not trust you enough to risk the inbox. The common causes, in rough order of impact: a cold or damaged sending-domain reputation, missing or failing authentication (SPF, DKIM, DMARC), a high bounce rate from a stale or bought list, spam complaints, low engagement (nobody opens or replies), and content signals like a bad text-to-image ratio or spammy link patterns. No single fix guarantees the inbox; placement is a trust verdict the receiver makes per message, weighing all of these together.

How long does email warmup take?

For a new sending domain, plan on 4 to 8 weeks of gradually increasing volume before you send at full scale. Start with tens of messages a day to your most engaged recipients, then roughly double every few days while watching bounce and complaint rates. The exact pace depends on your eventual volume: a domain that will send a few hundred a day warms faster than one targeting hundreds of thousands. There is no way to skip warmup; a brand-new domain that blasts a large list on day one will be throttled or filtered.

Do bounces hurt my sender reputation?

Yes, badly, and continuing to send to a bounced address hurts far more than the original bounce. A high hard-bounce rate (above roughly 2% per send) signals to mailbox providers that you are mailing a list you do not maintain, which is the signature of spam. The fix is to capture every bounce, classify it as hard (permanent) or soft (temporary), and add hard bounces to a suppression list you check before every send so you never mail a dead address twice.

What is sender reputation and how is it measured?

Sender reputation is the receiving provider's running estimate of how trustworthy your mail is, tracked against both your sending IP and your sending domain. It is earned through consistent volume, low bounce and complaint rates, and positive engagement (opens, replies, recipients moving you out of spam), and it is lost through volume spikes, bounces, complaints, and spam-trap hits. You do not get a single public score; each provider keeps its own, inferred from how recipients react to your mail over time.

Can a sending service guarantee inbox placement?

No. Any service that guarantees the inbox is overselling. A good sending stack gives you the controls (correct authentication, DKIM signing, bounce and complaint capture, suppression enforcement) and shared-IP or managed-warmup conveniences, but inbox placement still depends on your domain reputation, your list quality, and recipient engagement, none of which a vendor fully controls. Deliverability is a discipline you run, not a checkbox a provider ticks.

Is a small clean list better than a large list?

Yes. Mailbox providers weigh bounce rate, complaint rate, and engagement, not list size. A list of 2,000 people who opted in and open your mail will out-deliver a list of 50,000 scraped addresses, because the big dirty list generates bounces and complaints that damage the reputation protecting both. List hygiene (removing dead addresses, honoring unsubscribes, using double opt-in) is one of the highest-leverage things you can do for deliverability.