Email Bombing Prevention: Stop Your Signup Form From Becoming an Amplifier
An email bomb can turn your perfectly legitimate signup form into part of an attack. My rule is simple: no mail job should exist until a pre-send abuse gate has made a decision. Rate-limit the requester and the recipient separately, deduplicate repeat requests, require a step-up challenge when the pattern looks automated, and send no welcome, invite, or recovery sequence until the recipient confirms.
Email verification still belongs in that flow, but it answers a different question. It can tell you whether an address is malformed, disposable, risky, rejected, or inconclusive. It cannot tell you whether the person submitting the form owns the inbox or intends to flood it.
How does a normal form become an amplifier?
A registration bomb does not need to break into your mail server. A bot submits the victim's address to thousands of public forms. Each site then sends a legitimate confirmation, password-reset, contact, or invite message. The victim gets the combined flood.
The U.S. Department of Health and Human Services described this pattern on March 12, 2024: automated bots look for forms that can generate subscription email, then use many legitimate senders at once. MITRE ATT&CK tracks email bombing as technique T1667 and notes that the flood can bury security alerts or precede a fraudulent support call. NIST also treats email bombing as an availability threat in SP 800-177 Revision 1.
Your service may contribute only one message. That is still one message the attacker can obtain without controlling the inbox.
Move the decision in front of sendEmail()
I would model mail generation as a limited resource, not as an automatic side effect of a valid form submission. The gate needs two independent views of the same request:
- Source fan-out: is one IP, session, device, or authenticated account submitting many different recipients?
- Recipient fan-in: is one recipient receiving repeated requests, including requests arriving from many sources?
One combined key such as IP + email misses both distributed attacks and address spraying. OWASP's anti-automation guidance recommends layered controls and multiple independent rate-limit keys rather than relying on IP alone.
Here is the order I use as a starting point:
- Reject an obvious honeypot hit or malformed request without sending mail.
- Check source velocity, recipient cooldown, and a route-wide safety budget.
- Step up suspicious traffic with an accessible managed challenge. Validate the challenge on the server and keep the rate limits after it passes.
- Verify the address for syntax, domain, provider, and mailbox signals.
- Create or reuse one pending confirmation record.
- Enqueue at most one confirmation message for that record.
- Return the same generic response whether the request sent, deduplicated, or entered review.
The first two steps are cheap and local. Put them before paid API calls and before the mail queue. A CAPTCHA placed after the email job is created has already lost the important race.
Give each address a send budget
The recipient limiter is the control most teams miss. An attacker can rotate IP addresses, so the target address itself needs a cooldown that applies across sources.
| Observed pattern | Pre-send decision | Email effect |
|---|---|---|
| New source, new recipient, normal velocity | Continue to verification | One confirmation may be queued |
| Same recipient requested again during cooldown | Reuse the pending record | No additional message |
| One source submits many recipients | Challenge, slow, or block the source | Nothing queued until the gate passes |
| Many sources converge on one recipient | Hold the recipient key and alert | Further messages suppressed |
| Verification returns unknown | Keep the result inconclusive | At most one confirmation, if policy allows |
Hypothetical starting policy: one confirmation per recipient per 10 minutes, no more than three in 24 hours, and a step-up challenge when one unauthenticated source submits five distinct recipients in 10 minutes. Those numbers are not a standard. Set them from your own legitimate traffic, then test password managers, shared networks, accessibility tools, and mobile retries before enforcement.
Store the limiter key as an HMAC of the normalized comparison form, using a server secret. A plain hash of an email address is easy to guess from a dictionary. Keep the original address separately for delivery, and apply the same comparison policy across signup, resend, invite, password reset, and contact routes. Otherwise an attacker can hop between endpoints to reset the budget.
Is confirmed opt-in enough?
No. Confirmed opt-in prevents the attacker from activating a subscription or triggering later mail, which matters. HHS recommends it for that reason. But the first confirmation message is still the attacker's payload. The same HHS alert explicitly notes that verification messages can themselves be used in a list-linking bomb.
That is the strongest fair objection to this design: if you must send one message to prove control, how can you avoid sending to a victim? You cannot eliminate the first-message risk without another trusted channel. You can cap your contribution at one message, make repeats idempotent, and require more evidence before the first send when source behavior is suspicious.
After confirmation, release only the action the person actually requested. A newsletter confirmation should not also create an account, send a welcome series, invite a workspace, and trigger marketing automation. One unauthenticated form submission should not fan out into five mail streams.
Verification is one input, not the abuse gate
Use verification after the cheap abuse gate and before account creation. The emailverifier.dev API returns a technical status, an allow, review, or block recommendation, and the signals behind it. The product keeps unavailable or inconclusive mailbox checks as unknown, and its domain endpoint does not claim to confirm a mailbox or delivery.
That evidence can stop malformed input, known disposable providers, and confirmed failures before you spend a send. A free provider is not automatically disposable, a risk signal is not proof of abuse, and SMTP acceptance is not proof that the submitter owns the inbox. The confirmation step still has to establish control. The two-gate signup model in verify email before or after account creation shows where those decisions separate.
Log the decision without building an address leak
For each email-triggering request, record the route, timestamp, request ID, pseudonymous recipient key, pseudonymous source or session key, decision, and rule that fired. Do not log full addresses, confirmation tokens, reset tokens, or complete verification URLs. OWASP's email guidance recommends masking or pseudonymizing addresses in logs and monitoring high-frequency verification activity.
Watch the two directions independently. A spike in unique recipients per source suggests spraying. A spike in sources per recipient suggests a targeted bomb. A route-wide surge tells you the entire form is being recruited. Those three views give you something a single IP limit cannot.
Run the flow against two abuse simulations before release: one client repeatedly submits the same address, then many clients submit that address once each. In both cases, the queue should contain no more than the single pending confirmation your policy allows. Then simulate one client spraying many addresses and confirm that the source gate stops it before any new mail jobs are created.