From TAM to outbound campaign
Sequences built segment by segment.

A TAM goes out as a series of small campaigns, one per segment. My test for a segment: can you write one opening sentence that is true of every account in it? If the sentence needs a “depending on your situation”, the segment is still too wide and the sequence will read as if it were written for nobody.
Throughout this chapter, say you sell payroll software to French SMEs with several sites, and your TAM holds 6,200 scored accounts. All the figures below are illustrative.
Cut the TAM until one sentence fits
Start from the tiers built in the scoring chapter, then split the top of the list by what you can honestly say to each group.
| Segment | Filter on the TAM | Sentence true for all of them | Accounts |
|---|---|---|---|
| A. Retail, growing | Retail NAF codes, 5+ sites, payroll or HR role open in the last 90 days | You are adding sites and payroll now needs its own hire | 180 |
| B. Hospitality | Hotel and restaurant NAF codes, 3+ sites | Your headcount moves with the season and payslips follow | 420 |
| C. Multi-site, no signal | Top-tier sectors, 5+ sites | Each site adds its own rules to your payroll run | 1,150 |
| Parked | Everything else | No sentence yet | 4,450 |
The parked line matters. Those accounts stay in the database until a signal or a new angle gives you something true to say, and the signals chapter is where that comes from.
Keep one persona per campaign. A CFO and a payroll manager at the same company have different problems, so they get different sequences, coordinated at account level so both don’t hear from you in the same week. The contacts chapter covers who to pick.
Remove everyone who should not receive this
The size of a segment and the size of a campaign are two different numbers. Run the exclusions before you write a line of copy.
SELECT c.contact_id, c.first_name, c.email, c.linkedin_url,
a.company_name, a.site_count, a.last_signal_role
FROM contacts c
JOIN accounts a ON a.account_id = c.account_id
LEFT JOIN suppression s ON s.email = c.email OR s.domain = a.domain
WHERE a.segment = 'A'
AND c.persona = 'payroll_manager'
AND a.status NOT IN ('customer', 'open_deal', 'partner', 'competitor')
AND c.email_status = 'valid'
AND s.email IS NULL AND s.domain IS NULL
AND (c.last_contacted_at IS NULL
OR c.last_contacted_at < CURRENT_DATE - INTERVAL '120 days');
The same logic works in a spreadsheet with filters and a suppression tab. Write the loss at each step, because it tells you where the TAM is weak.
| Step, segment A | Remaining |
|---|---|
| Accounts in the segment | 180 |
| After customers, open deals and partners | 164 |
| With a payroll or HR contact found | 131 |
| With a valid email | 118 |
| Not contacted in 120 days, not opted out | 112 |
Your real campaign is 112 people. Before launch, read the CNIL page on electronic direct marketing, which separates messages to professionals from messages to individuals, and check the equivalent authority for each country you target. I am not a lawyer and this is not legal advice: have counsel validate your setup, and check the terms of use of each data source and platform. The chapter on upkeep covers opt-outs.
Size the test before you write the sequence
Decide what you can learn from the volume you have. Split 112 contacts into two variants and each one gets 56. At that size, a gap of two replies is noise, so test things that could change the outcome by a wide margin: the opening angle, the persona, the channel order. Subject line tests can wait for a segment of several thousand.
Then check capacity. Set a daily limit per sender after reading each platform’s rules, and count replies as work too. If one rep starts 25 new contacts a day, 112 contacts take about five working days, and follow-ups will still be landing three weeks later. Launch the next segment when the previous one has cleared, so that nobody is handling three sets of replies with three different arguments.
Write the sequence from the fields you have
Each step has one job and uses a field that exists in the TAM.
| Step | Day | Channel | Job of the message | TAM field used |
|---|---|---|---|---|
| 1 | 0 | State the observed fact, ask one question | site_count, last_signal_role |
|
| 2 | 3 | LinkedIn connection, no pitch | Become recognizable | linkedin_url |
| 3 | 7 | One concrete example from the same sector | sector_label |
|
| 4 | 12 | Phone, if you have a number | Talk about the problem | phone, site_count |
| 5 | 18 | Close the loop and offer to stop | first_name |
For segment A, the first email could read:
Subject: payroll across {{site_count}} sites
Hello {{first_name}},
I saw that {{company_name}} is recruiting a {{last_signal_role}} while running {{site_count}} sites. At that stage, collective agreements and site-level variables tend to land on one person’s desk.
Is that where you are, or is it already handled?
A blank variable sends a broken message, so block the launch on this check, which has to return 0 for each required column:
=COUNTIFS(Segment!A:A,"A",Segment!F:F,"")
Move the segment into the sequencer
I co-founded Derrick, so take this section with that in mind. Here is how the last mile works there, from the app or the Google Sheets sidebar.
Company Hiring Signal takes LinkedIn company URLs and returns whether the company is hiring, how many roles are open and their titles, for 1 credit per company checked. That fills the signal column. Email Finder takes a LinkedIn URL, or a name and a company, and charges 5 credits per email found. For addresses that came from elsewhere, Email Verification costs 1 credit per address submitted. Push to La Growth Machine, a tool we partner with, costs no credits: you connect your API key once, pick the audience, map the LinkedIn URL column and your custom fields, and a column confirms each row went through. I would create one audience per segment.
Derrick stops there. It does not send anything, build the sequence or write results back into your CRM, so reply handling and CRM updates stay on your side. Without it, any finder and verifier will do, followed by one CSV per segment imported into your sequencer with these columns.
| Column | Example | Rule |
|---|---|---|
contact_id |
c_01842 | Stable TAM ID, kept as a custom field |
segment |
A | One value per file |
variant |
A1 | Assigned before import |
first_name |
Camille | Cleaned, correct capitals |
email |
valid status only | No role addresses on a personal sequence |
linkedin_url |
full profile URL | Required for step 2 |
company_name |
Maison Martin | Legal suffixes removed |
site_count |
12 | Number, no blanks |
last_signal_role |
payroll manager | Written the way a person would say it |
Write the results back into the TAM
Export the outcomes per contact_id and update the database, or the next campaign will repeat this one’s mistakes.
| Segment | Contacts | Replies | Positive | Meetings | Decision |
|---|---|---|---|---|---|
| A | 112 | 14 | 7 | 4 | Widen to the next batch with a signal |
| B | 240 | 12 | 3 | 1 | Rewrite the sentence, retest on 100 |
| C | 300 | 9 | 1 | 0 | Stop and go back to the segment definition |
Store last_contacted_at, campaign_id and one outcome from a closed list: no_reply, positive, not_now, wrong_person, bounced, opt_out. A not_now gets a recontact date. Opt-outs go straight to the suppression table. A high rate of wrong_person or bounced means the data is at fault, and no rewrite of the copy will repair it.
Your next step: take the segment with the most recent signals, write its one sentence, and run the exclusion table. If at least 100 contacts survive, build the five steps above. If fewer do, widen one filter and run the table again.