You have a list of 300 Indian companies and a product that suits maybe 30 of them. The tempting move is to paste all 300 into a chatbot and say "write cold emails". You'll get 300 fluent messages that nobody answers, and a sender domain that Gmail learns to distrust. The better move is cold email and lead scoring in the right order: decide who deserves an email first, then write fewer emails with a real reason to exist.
This post gives you a workflow where the model reads and writes, code decides, and a person sends. I ran the scoring script on 2026-10-31 with four invented leads. I ran no live model, so the extraction and drafting prompts are untested templates. I have no conversion numbers, reply rates or benchmarks to share, and I won't make any up.
Two companion posts cover adjacent ground: prompts for sales reps (research briefs, call prep, objection handling) and CRM hygiene prompts. This one is about the front of the funnel, for Indian B2B.
What is the workflow?
- Collect. You gather public text about each lead yourself: their site, a news item, a job post. The model never browses for you here.
- Extract. The model turns that text into yes/no signals, each with a supporting quote.
- Score. Code applies written weights and a suppression list.
- Draft. For leads above the threshold, the model drafts one short email from approved facts.
- Edit and send. You edit every email and send from your own mailbox.
Only steps 2 and 4 use a model. The decisions in step 3 are arithmetic you can read.
How do you extract lead signals without inventing them?
The risk with lead research is a model that fills gaps. "Recently expanded" appears from nowhere. The fix is the same one that works elsewhere on this site: no quote, no claim.
Untested template:
Below is public text I collected about one company and one person. Return JSON only.
Fields (each 0 or 1):
- icp_size: company looks like [YOUR SIZE RANGE, e.g. 20-200 employees] based on the text
- icp_industry: company is in [YOUR TARGET INDUSTRIES]
- trigger_recent: the text shows a dated event in the last 90 days that relates to [PROBLEM YOU SOLVE]
- role_fit: the person's title is one of [TITLES THAT BUY]
- has_public_work_email: a work email for this person is printed in the text
Also return:
- quote: the exact sentence supporting trigger_recent, copied word for word, or "" if none
- evidence_gaps: list of fields you could not judge from the text
Rules: if the text does not say it, the field is 0 and goes in evidence_gaps. Do not infer from the company name. Do not use outside knowledge.
TEXT:
[PASTE]
Two details matter. has_public_work_email asks whether an address is printed in the text you gave, not whether the model can guess one. Don't ask a model to guess email patterns and then send to the guesses; bounces damage your sender reputation and you'd be mailing people you have no reason to think want it. And quote gives your code something to check: a trigger claim with an empty quote can be routed to a person.
How do you score leads with code?
Weights live in a dict. Anyone on the team can read it, argue with it and change it.
WEIGHTS = {"icp_size": 3, "icp_industry": 3, "trigger_recent": 2,
"role_fit": 2, "has_public_work_email": 1}
THRESHOLDS = {"send_first": 8, "nurture": 5}
SUPPRESSION = {"nora@example-textiles.in"} # opted out earlier (invented)
def score(sig):
return sum(WEIGHTS[k] * sig[k] for k in WEIGHTS)
def decide(email, sig):
if email.lower() in SUPPRESSION:
return "SUPPRESSED", 0
if sig["trigger_recent"] and not sig["quote"]:
return "REVIEW: trigger without quote", score(sig)
s = score(sig)
if not email:
return "NO_CONTACT_PATH", s
if s >= THRESHOLDS["send_first"]:
return "DRAFT_FOR_HUMAN", s
if s >= THRESHOLDS["nurture"]:
return "NURTURE", s
return "SKIP", s
The rest of the file is a stub standing in for the extraction call, with four invented leads and a loop that prints CSV. Output from my run:
id,company,score,decision
L1,Bhiwandi Logistics Pvt Ltd (invented),11,DRAFT_FOR_HUMAN
L2,Ravi Exports (invented),6,NURTURE
L3,Kochi Foods (invented),5,NO_CONTACT_PATH
L4,Example Textiles (invented),0,SUPPRESSED
What the four rows show:
- L1 hits every signal, with a quote about a September warehouse opening, and goes to a human for drafting.
- L2 fits on size and role but has no trigger and the wrong industry, so it's nurture: no email today.
- L3 scores 5 on industry and trigger but has no email in the public text. "Score 5" doesn't create a contact path, so it stops there. This is where a lot of lists go wrong, by buying or guessing an address.
- L4 would have scored 11 on signals but is on the suppression list, and the check runs first, so it is zeroed out. Order matters here. A suppression check that runs after scoring can be skipped by a code change; running it first makes it the gate.
Be honest about the weights. I picked them by feel. They are a hypothesis. To improve them, log which scored leads reply and revisit after you have enough outcomes to see a pattern, which for most small teams is a long time. Until then, the score is a sorting aid, not a prediction.
What should the cold email prompt look like?
Short, one reason, one small ask, and only facts you supply. The sales reps post has a general version; this one adds the India B2B inputs and a constraint on the opt-out line. Untested template:
Draft a first email from me to [FIRST NAME], [TITLE] at [COMPANY].
Facts you may use, nothing else:
- Reason I'm writing (with the source, which I'll keep): [QUOTE FROM THE SCORING STEP]
- What I do in one plain sentence: [DESCRIPTION, no adjectives]
- One proof point I can stand behind, or "none": [REAL CUSTOMER FACT]
- The ask: [a yes/no question | 15 minutes next week | permission to send a one-pager]
Constraints:
- Under 90 words, plain text, no bullets, no formatting.
- Subject under 6 words that says what the email is about. No "Re:", no fake urgency.
- English, or Hinglish only if I write [HINGLISH OK]. Address by first name.
- Do not invent numbers, customer names or features. Leave out the proof point if it is "none".
- Do not write an unsubscribe line or a signature. My template adds them.
Give three versions with different openings.
Then edit by hand. If the reason for writing doesn't survive being said aloud to the person, cut the email. For stripping out model-flavoured phrasing, see how to prompt AI to sound human. Hinglish drafts need a native read before they go out; the Hinglish prompting guide covers where models slip.
The unsubscribe line and signature come from your template, not the model, so a rewrite can never drop them.
What do DPDP and sender rules mean for cold email?
I'm not a lawyer, and this section says what I read and what I did not.
DPDP. In the DPDP Act checklist, I read the Act and the DPDP Rules, 2025 from the Gazette copies. The points relevant here: the Rules were notified in November 2025, their main duties on notice, safeguards, breach intimation and erasure start 18 months after publication (about mid-May 2027, ask counsel for the day), and the Act does not mention AI. Whether a named person's work email counts as personal data for your outreach, and what lawful basis you would rely on, is an interpretation question. I did not find a rule written specifically for cold B2B email, and I did not verify any other Indian law on commercial email. Phone calls and SMS fall under different telecom rules that I haven't covered. So: ask counsel before you scale, and meanwhile build the habits that help under any reading.
- Keep a suppression list, check it first (as in the script) and make opt-outs permanent.
- Record where each address came from. Your future self, or counsel, will ask.
- Store as little as you need: name, work email, company, the quote, the date. No guessed personal details.
- Don't buy lists you can't trace. A list with no source gives you no answer to "where did you get my address?".
Sender requirements. I read Google's email sender guidelines page on 2026-10-31. For all senders it asks for SPF or DKIM, valid forward and reverse DNS, TLS, and spam rates under 0.3% in Postmaster Tools. For bulk senders, defined on that page as more than 5,000 messages a day, it adds SPF, DKIM and DMARC, one-click unsubscribe with a visible unsubscribe link in the body, and a spam rate below 0.30% (with a stricter goal of 0.10%). The page gives no deadline for processing unsubscribes. You are probably nowhere near 5,000 a day, but the same hygiene protects a small sender. The page is the authority; check it for changes.
US recipients. If any of your list sits in the US, CAN-SPAM applies to B2B email too, covered with the FTC source in the sales reps post.
Practical setup: send from a separate domain so a complaint problem doesn't take your main domain's mail with it, authenticate it, and warm it with a few real conversations before any list. Transactional email services compared covers sending infrastructure, though transactional services generally aren't meant for cold outreach, so read the provider's acceptable-use terms before you try.
What should you never automate?
- Sending. A person reads and sends every message. Auto-send is how a template bug becomes 300 embarrassing emails.
- Follow-up sequences on autopilot. One follow-up that adds something new is fine. A drip of "just bumping this" isn't.
- Guessing emails or scraping personal profiles. It's the cheapest way to build a list you can't defend.
- Claims about the prospect you can't point to. If there's no quote, the sentence goes.
What to do this week
Pick 20 leads. Collect the public text yourself. Run the extraction prompt, fix the weights until the top five match your gut, and send those five, edited by hand, from an authenticated domain. Log source, date, outcome. After a month you'll have your own numbers, which are worth more than anyone's benchmark, including the ones I don't have.



