Case Study — Automated Lead Generation System
A pipeline that ran correctly end to end, blocked not by a bug, but by a platform's own policy, and what it took to notice the difference.
This pipeline automates cold outreach for the supervised visitation business. Instead of manually emailing individual social workers, attorneys, and family law professionals one at a time, it reads a CSV export of prospects, deduplicates against everyone already contacted, and pushes the new batch into an email platform on a weekly schedule via GitHub Actions. The problem it solves: turning a slow, easy-to-forget manual outreach task into something that runs itself, without duplicating contacts or losing track of who's been reached.
What happened at send time
What the code had already done correctly
The pipeline was built and working end to end on Mailchimp, contacts synced, draft campaign created. Then Mailchimp rejected the campaign outright with a compliance warning: their platform prohibits sending to non-opted-in contacts, which is exactly what cold outreach is. The tool worked technically but was structurally the wrong fit for the use case.
This wasn't caught by analytics, and not something I noticed while working on something else. Mailchimp itself flagged it, an active enforcement action from the platform, triggered the moment the campaign was submitted for review. That's a distinct failure mode from a bug: the code executed correctly, but the platform's own policy blocked the actual goal.
The root cause wasn't a broken integration. It was verifying that Mailchimp's stated policy prohibits cold outreach to non-opted-in contacts, full stop, against a platform like Instantly.ai, which is built specifically for cold outreach. No amount of debugging the Mailchimp integration would have fixed this, because there was nothing broken to fix. The pipeline needed a different tool, not a better version of the same one.
The migration
Verified, not assumed
Initially pointed the integration at an Instantly "AI Sales Agent" object instead of a plain "Campaign" object, same platform, different API shape, silent success responses that added nothing. Diagnosed by querying the API directly rather than trusting the UI.
That last decision, capping sends on a brand-new account instead of pushing volume the moment it worked, wasn't the fastest configuration available. It was the one that protected deliverability long enough for the account to earn trust with the platform, a decision made for a reason, not just the first thing that shipped.