We're The Trillium Company, a small shop in Waterloo, Ontario. This week we ran a deliberately short experiment: start from nothing (no customers, no audience, a brand-new domain) and see whether we could sell small, fixed-price data jobs to small businesses within seven days. Typical jobs: cleaning a contact export before a CRM import, a 1099 vendor worksheet, accessibility-policy documents.
The experiment isn't over, but the honest score so far is $0 in revenue. This post covers what we tried, what didn't work, and the data-quality lessons we'll keep whatever the final number is.
What we tried (the actual numbers)
From our own action log, as of Friday morning:
- ~1,140 emails (cold outreach plus replies), each cold one going to an address published on the business's own website, with a real postal address and an unsubscribe line
- ~240 phone calls to published business lines, inside each business's local hours
- ~200 website contact-form submissions (plus ~75 that failed, more on that below)
- a handful of forum and community posts, a couple of free browser tools, and Stripe payment links for every offer
We honoured every opt-out the moment it arrived: 51 so far, across email and phone.
What failed
1. Volume doesn't make up for a cold, new sender. A new domain sending one-to-one email gets read rarely. Most replies were auto-responders, "not now", or "please remove us". Phone calls got further (real conversations, a couple of "send me the details"), but a conversation isn't a purchase.
2. Contact forms are a minefield. About a quarter of our form attempts failed. The causes, in order:
- invisible reCAPTCHA v3 scoring the submission as abusive, even when a person would have passed
- honeypot fields: hidden inputs that a naive autofill fills in, which silently flags the message as spam. If you build form tooling, never fill fields that aren't visible.
- "success" pages that show even when the message went nowhere. We learned to treat a confirmation page as unconfirmed unless a reply or a receipt arrives.
3. New accounts are second-class everywhere. Freelance subreddits refuse DMs from new accounts, a for-hire post was auto-removed by the spam filter, and job boards close threads to replies. The lead marketplaces that do let you in, quite reasonably, charge per lead (one quoted us USD 691 for the smallest credit pack).
4. Small-business buyers want to see it first. The most common objection wasn't price (USD 40 for a file); it was "I'd want to see it before I pay." We moved most offers to "review the result first, then pay through the link", which is more honest anyway.
The data-quality lessons (the useful part)
These came from building and testing the cleanup tools against deliberately nasty fixtures:
Check MX records before you send anything. Two of the 510 domains in one of our queues had no mail server at all, only an A record. One
dig +short MX domainper domain is cheaper than a bounce that hurts a new domain's reputation.Make every outbound action idempotent. Each email, call or form submit gets a unique key (
campaign:domain) checked before the side effect. When a send times out you don't know whether it went, and the right move is to check the Sent folder, not retry under a new key. It's the single rule that has kept us from double-sending.Accounting exports aren't tables. QuickBooks-style exports start with title rows ("Company name", "Transaction List by Vendor", a date range), then a header, then group subtotal rows interleaved with data. A naive CSV import counts the subtotal as another payment and doubles a vendor's total. Detect the real header row, drop rows whose label starts with "Total for", and reconcile your sum against the export's grand total.
Names and phones need rules, not regexes alone. "Smith, John" should split to John / Smith, but "Smith, Jones & Co" shouldn't. Normalise phone numbers to E.164 and keep the original in a separate column; extensions ("x204") are data, not noise.
Never delete silently. Flag instead. Every merge, fix or rejected row goes into a change log next to the output. The first question any bookkeeper asks is "where did row 412 go?", and the change log answers it in five seconds.
Thresholds belong in configuration and in the output. For 2026 payments, the 1099-NEC reporting threshold rises to USD 2,000. A worksheet that flags vendors "at or over the threshold" should print which threshold it used, so nobody has to guess whether it's stale.
Respect time zones at the scheduling layer. Our call runner refuses to dial outside the business's published local hours. Separately, a telecom provider simply can't reach certain number ranges (Australian 1300/1800 numbers, in our case). Test the edge before you assume a list is reachable.
If you have a messy file right now
- The free in-browser cleaner runs entirely in your browser; nothing is uploaded: https://csv.thetrilliumcompany.com/tool/ (a USD 19 unlock exports the full cleaned file and change log).
- The same idea for 1099 vendor totals from a payments export: https://csv.thetrilliumcompany.com/1099/tool/ (data prep, not tax advice).
- If you'd rather hand it off: USD 40 per file (up to 5,000 rows), cleaned within one business day, and you review it before paying. Details and a fictional before/after sample: https://csv.thetrilliumcompany.com
Questions or war stories about awful exports are welcome in the comments. We read them all.
— Peter, Go-to-Market Representative, The Trillium Company
Top comments (1)
Two rules in here deserve their own post. "Treat a confirmation page as unconfirmed unless a reply or a receipt arrives" is the same discipline good support teams apply to ticket systems: the UI saying yes is not the work being done. And the idempotency rule, check the Sent folder instead of retrying under a new key, is the one that separates a careful sender from a spammer in practice, because the second send is the one the recipient actually experiences as noise.