# Recycled spam traps, and the mailbox that came back

A mailbox that bounced for months and then accepts mail again is the shape of a recycled spam trap. What recycled_mailbox means, and what to do with one.

Date: 2026-09-13

A recycled spam trap is an email address that once belonged to a person, was abandoned, bounced as unknown for a long time, and was then quietly reactivated by the mailbox provider or a blocklist operator as a trap. It receives mail again, but nobody reads it, and every message that arrives is evidence that the sender is mailing a list nobody has cleaned. Spaw reports the same shape from its own evidence: a mailbox that answered "no such mailbox" and later answers "exists" is returned as `risky` with the reason `recycled_mailbox`.

## What is a spam trap?

A spam trap is an address whose only purpose is to catch senders who should not have it. There are two kinds, and they catch different mistakes.

A pristine trap has never belonged to anyone. It is seeded on web pages, in code comments and in places only a scraper would look, so any mail to it proves the sender harvested addresses rather than collected them. A verifier cannot see a pristine trap: it is a real mailbox at a real domain, it accepts mail, and nothing in DNS or the handshake distinguishes it from a colleague's address.

A recycled trap did belong to someone. The mailbox was abandoned, the provider closed it, and for a period, typically a year or more, it rejected every message with a permanent error. Then the provider turned it back on. A sender who still has it on a list did not act on the bounces, and the trap records exactly that. M3AAWG's Sender Best Common Practices (version 3, 2015) describes the mechanism and the remedy in the same breath: process every bounce, and stop mailing an address after it has hard-bounced.

The recycled kind is the one a verifier can see coming, because the death of the mailbox left a trace.

## How does Spaw remember a dead mailbox?

The mailbox handshake ends with the receiving server's answer at `RCPT TO`. A definitive rejection, typically `550 5.1.1` in the terms of RFC 5321 and RFC 3463, is the answer Spaw reports as `undeliverable` with the reason `mailbox_not_found`. Since September 2026 that answer is also remembered: the date it was seen is kept for a year under a keyed hash of the address. The address itself is not stored with it, and the memory is erased along with everything else when an address is erased on request.

A bounce you report feeds the same memory. When a delivery outcome arrives through the feedback endpoint or one of the provider webhooks with a reason that reads as no such mailbox, the enhanced code `5.1.1` or the wording that mail servers use for it, the date of that bounce is recorded the same way. So a list that bounced through your own sending provider months ago is already known to Spaw as dead, whether or not anyone verified it at the time.

When a later handshake says the mailbox exists, the two facts are compared. The answer carries `mailbox_exists: true`, because it is true, and beside it `previously_invalid: true` with `previously_invalid_at` naming the date of the rejection. The verdict is `risky`, the reason is `recycled_mailbox`, and the weight is 30, the medium band on its own.

```json
{
  "email": "former.employee@acme.com",
  "deliverable": "risky",
  "reason": "recycled_mailbox",
  "risk_score": 30,
  "risk_level": "medium",
  "mailbox_exists": true,
  "previously_invalid": true,
  "previously_invalid_at": "2026-03-02",
  "risk_signals": [{ "signal": "recycled_mailbox", "weight": 30, "dataset": "mailbox-history" }]
}
```

The field is tri-state. `previously_invalid` is `false` for a confirmed mailbox with no such history, which is the ordinary case, and `null` whenever the mailbox was not confirmed, because there is nothing to compare a rejection against.

## What the signal does and does not mean

It means the mailbox was rejected once and accepts now. That is the whole claim, and it has innocent explanations: a person left a company and came back, an alias was removed and recreated, a mailbox was suspended for non-payment and restored. It also has the explanation a sender should fear, which is that the address was turned into a trap. Spaw cannot tell those apart from the outside, and says so by keeping the verdict at `risky` rather than `undeliverable`.

It does not mean the address is on any blocklist operator's trap network. Trap lists are secret by design, nobody sells a legitimate one, and a verifier that claims to detect traps directly is either guessing from the same shape Spaw reports or selling a list that would stop being a trap list the moment it was sold.

The memory also decides nothing about the domain. A recycled mailbox at a domain says nothing about the mailbox next to it; the signal is per address.

## What to do with a recycled mailbox

Treat it as you would treat a catch-all address: a real mailbox that you should not mail from a list-cleaning run.

Hold it out of any campaign that is sending to a list rather than to a person who just asked for something. A trap does damage in proportion to the volume that reaches it, and a cleaning run is precisely the moment a recycled trap is designed to catch.

Let the person re-engage first. If the address belongs to a returning customer, they will sign in, reply, or submit a form, and that action is the evidence the bounce history cannot give you. Once it happens, verify the address again: a fresh single lookup runs the handshake anew, and if you report the delivery of a transactional message through the feedback endpoint, later lookups of the address answer from your own evidence (`smtp_reason: "delivered_recently"`).

Fix the list hygiene that let it happen. A recycled trap only catches senders who ignored a hard bounce, so the durable fix is to process bounces as they come: point your sending provider's bounce webhook at Spaw, and every hard bounce joins your suppression list without a credit spent, while the verdict-level feedback improves the answers for everyone.

The sending policy can enforce the hold for you. Adding `recycled_mailbox` to the `block_signals` list makes every answer carrying it come back with `ok_to_send: false` and `blocked_by: "recycled_mailbox"`, so a form or a campaign filter branches on one boolean instead of reading the history fields.

## How this interacts with the rest of the answer

Precedence decides the reason when several apply. Undeliverable reasons win over everything; among risky ones a typo-squat, a parked domain, a disposable domain, a blocklisted mail network, an implicit MX, a full mailbox, a no-reply address and a role address all rank ahead of `recycled_mailbox`, and it in turn ranks ahead of `catch_all` and `unverified`. Whatever the reason names, every flag that fired is in `risk_signals` with its weight, so a recycled role mailbox scores 60 even though `reason` says `role`.

The memory is read only when a handshake confirmed the mailbox. A catch-all domain never confirms one, so a recycled address at a catch-all domain keeps its `catch_all` reason and its `mailbox_confidence` estimate, and `previously_invalid` stays `null`.

Repeats inside the seven-day window answer from the earlier answer, so the flag does not flicker between calls. A `refresh: true` lookup runs a fresh handshake and re-reads the memory.

## Where the numbers come from

Two things are worth knowing before you build a policy on this signal. First, the memory starts from the day it was introduced, and from the bounces already on file; an address that died two years ago and revived last year carries no history here, because nobody told Spaw about the death. Second, the pooled measurement on the status page will, once enough outcomes have been reported, show the share of sends to `recycled_mailbox` answers that bounced or were delivered, under the same floors as every other published figure. Until then the signal is a well-founded shape, not a measured rate, and the docs say so.

## What to do next

- Read the [`recycled_mailbox` reason page](/docs/reasons/recycled_mailbox) for the exact contract and precedence.
- Wire your bounce webhook into the [feedback endpoint](/docs/api/report-delivery-feedback) so hard bounces reach the memory and your suppression list on the day they happen.
- Add the signal to your [sending policy](/docs/api/update-email-policy) if a hold should be automatic.
- Work through the [email list cleaning checklist](/guides/email-list-cleaning-checklist) before the next campaign.

Reference: https://spaw.co/guides/recycled-spam-traps-and-the-mailbox-that-came-back
