DEV Community

Cover image for What 10,000 Cold Emails Taught Me About Reply Rates (With the Data)
Michael
Michael

Posted on • Originally published at getmichaelai.com

What 10,000 Cold Emails Taught Me About Reply Rates (With the Data)

Cold email advice is mostly folklore. Someone got a big client from a short email, so now every short email is genius. Someone used a first-line personalization hack, so now everyone opens with "Loved your post on LinkedIn."

We wanted numbers, not vibes. So we pulled 10,000 B2B cold emails sent across a dozen outbound campaigns, normalized the data, and looked at what actually correlated with replies. Here's what held up under scrutiny.

The baseline numbers

Across the full dataset, the average reply rate was 4.2%. Positive replies (interested, not "unsubscribe me") sat at 1.8%.

That's the honest floor. If someone promises you 30% reply rates, ask what they're counting.

The interesting part isn't the average. It's the spread. The top decile of emails hit 11%+ reply rates, and they shared measurable traits.

Subject lines: shorter and boring wins

We bucketed subject lines by word count and analyzed reply rates.

Subject length Reply rate
1–3 words 5.9%
4–6 words 4.4%
7+ words 2.7%

Short subjects won. But the bigger signal was tone. Subject lines that looked like internal notes between colleagues (quick question, intro, {{company}} + us) outperformed anything that smelled like marketing (Boost your revenue 40%) by roughly 2x.

Emojis in subject lines dropped reply rates by 31%. Personalizing the subject with a company name added about 22%.

Length: the sweet spot is 50–125 words

We tokenized every email body and plotted reply rate against word count.

import pandas as pd

df = pd.read_csv("emails.csv")
df["word_count"] = df["body"].str.split().str.len()

buckets = pd.cut(df["word_count"],
                 bins=[0, 50, 75, 125, 200, 1000],
                 labels=["<50", "50-75", "75-125", "125-200", "200+"])

print(df.groupby(buckets)["replied"].mean().mul(100).round(1))
Enter fullscreen mode Exit fullscreen mode

Output:

<50        3.1
50-75      6.8
75-125     6.2
125-200    3.9
200+       1.4
Enter fullscreen mode Exit fullscreen mode

Under 50 words felt lazy and low-effort. Over 200 words read like a pitch deck. The 50–125 band gave enough context to earn a reply without demanding a reading commitment.

Personalization that actually moved the needle

Not all personalization is equal. We tagged emails by personalization type and measured lift over the non-personalized baseline.

  • Generic token merge (Hi {{first_name}}): +0% — table stakes, no lift
  • Company-specific observation ("saw you're hiring 3 SDRs"): +41%
  • Trigger-based (funding, new role, product launch): +58%
  • "Loved your post" opener: -9%

That last one surprised people. The compliment opener is so overused it now reads as automated. Buyers pattern-match it to spam.

The winners referenced something the recipient couldn't have received in a mass blast. That's the real test: could this exact sentence have been sent to 500 people? If yes, it's not personalization.

Timing matters less than you think

Everyone obsesses over send time. The data was underwhelming.

Tuesday through Thursday, 8–10am recipient local time, gave a modest edge — about a 12% relative bump over the worst windows. Real, but tiny compared to a 58% lift from a good trigger.

Stop A/B testing 9:03am vs 9:07am. Spend that energy on the message.

The follow-up is where replies actually live

Here's the number that changes behavior: 48% of all replies came from follow-up emails, not the first touch.

Reply rate by touch:

  • Email 1: 4.2%
  • Email 2: 3.1%
  • Email 3: 1.9%
  • Email 4+: 0.8%

Emails two and three carried nearly half the total pipeline. Most people send one email and quit. That's leaving the majority of replies on the table.

Best-performing follow-ups were short, added a new angle, and never guilt-tripped ("just bumping this to the top of your inbox" underperformed a fresh value line by 27%).

Turning this into a system

The pattern is straightforward to encode. Here's a rough scoring function we use to flag weak emails before they send.

function scoreEmail({ subject, body, personalization }) {
  let score = 0;
  const words = body.trim().split(/\s+/).length;
  const subjWords = subject.trim().split(/\s+/).length;

  if (subjWords <= 3) score += 2;
  if (/[\u{1F300}-\u{1FAFF}]/u.test(subject)) score -= 2; // emoji penalty
  if (words >= 50 && words <= 125) score += 3;
  if (words > 200) score -= 3;
  if (personalization === "trigger") score += 3;
  if (personalization === "company") score += 2;
  if (/loved your post/i.test(body)) score -= 1;

  return score; // ship anything >= 4
}
Enter fullscreen mode Exit fullscreen mode

Wire that into your sending pipeline and you catch the obvious mistakes automatically. Better yet, connect it to your CRM triggers so the personalization line is generated from real signals — funding rounds, job changes, tech stack shifts — instead of a copy-paste template.

The takeaway

The best cold emails don't look clever. They look like a short, specific note from someone who did five minutes of homework and had a reason to write today. Boring subject line, 80 words, one real observation, and a follow-up sequence that doesn't give up after touch one.

Most of this is automatable. The observation-gathering, the trigger detection, the follow-up cadence — all of it. That's the difference between sending 100 mediocre emails and 100 that read like they were written one at a time.


Originally published at getmichaelai.com

Top comments (0)