September 24, 2026 · Steve Johnson
The Import That Accidentally Emailed Everyone, and What We Built After
A bulk customer-import run, meant to move account records into a new system as an internal data step, triggered the new platform's normal identity-provider webhook — which, working exactly as designed for an actual new signup, fired off a welcome email to every single customer it touched. None of them had signed up. All of them got an email that made it look like they had.
What went wrong, mechanically
The import wasn't misusing any API. It was using the standard "create this user" path, because that path already handled everything correctly for an actual new signup: password setup, identity linking, the works. The problem was that "create a user record as part of a data migration" and "a person actually just signed up" are two very different events that happened to route through the exact same code path, and nothing distinguished them at the point where a welcome email got triggered.
The guardrails, not just the one fix
Patching that specific call site would have stopped that specific incident from happening the same way twice. It wouldn't have stopped the next import script, written by someone else, from hitting the identical trap through a different path. So the fix was structural: a transactional-email kill switch that can be flipped for the duration of any bulk operation, an explicit import flag threaded through the identity webhook so it can recognize and skip a migration-triggered creation versus a real signup, the production cutover runbook rewritten to bracket every bulk step with that suppression toggle on and off, and every retry tool in that family switched to default to a dry run with an explicit flag required to do anything for real.
The actual lesson
The specific bug — a webhook firing on the wrong kind of event — is almost beside the point. The real failure was that the system had exactly one way to create a user record, used for two very different purposes, with no signal anywhere distinguishing them. Any tool that can trigger a real, external, customer-facing side effect needs an explicit, checked distinction between "this is really happening" and "this is internal plumbing that happens to look the same" — and that distinction has to live in the code, not in the hope that whoever runs the next script remembers to be careful.