DEV Community

Akbo Ichou
Akbo Ichou

Posted on

10 20 10 10: Composing 20,000 Email Templates That Don't Read Like Mail Merge

Sales Email Template has 20,000+ free, copy-ready email pages. That number comes from four dimensions multiplied together:

  • 10 email types — follow-up, cold email, meeting request, proposal follow-up, breakup, thank you, introduction, referral request, invoice reminder, apology
  • 20 industries — SaaS, healthcare, finance, legal, construction, retail…
  • 10 prospect roles — CEO, CTO, HR director, sales VP, founder…
  • 10 scenarios — no response, clicked but no reply, after demo, after proposal, long time no contact…

10 × 20 × 10 × 10 = 20,000. The engineering challenge is making each combination read like a person wrote it, not like Hi {{first_name}}, I noticed {{company}}…. Here's how the composition works.

Each dimension owns a different part of the email

The mistake is treating every dimension as a find-and-replace variable. Instead, each one controls a different job in the email:

Dimension Controls
Email type Structure and goal (ask for a meeting, close the loop, get paid)
Scenario Opening line and context (why you're writing now)
Role What they care about and how much detail they want
Industry Vocabulary and the proof point that lands
interface Combo { type: EmailType; industry: Industry; role: Role; scenario: Scenario }

function compose(c: Combo): { subject: string; body: string } {
  const opener = scenarioOpeners[c.scenario](c);    // why now
  const value  = roleAngles[c.role](c.industry);    // what they care about
  const proof  = industryProof[c.industry];         // what makes it credible
  const ask    = typeAsks[c.type](c.role);          // the one clear next step
  return {
    subject: subjects[c.type](c),
    body: [opener, value, proof, ask].filter(Boolean).join("\n\n"),
  };
}
Enter fullscreen mode Exit fullscreen mode

Because each dimension writes whole sentences for its own slot, a CTO follow-up after a demo reads differently from a CEO breakup email — structurally, not just by swapped nouns.

Short beats clever

Every template aims for something you can read in a few seconds: a subject line, 3–5 short paragraphs, one ask. Long emails fail on mobile and look automated. A simple length check in the build keeps that honest:

const words = (s: string) => s.split(/\s+/).filter(Boolean).length;

for (const combo of allCombos()) {
  const { body } = compose(combo);
  if (words(body) > 120) warn(`too long: ${key(combo)}`);
}
Enter fullscreen mode Exit fullscreen mode

Leave one line for the human

Templates are deliberately missing one thing: the detail only the sender knows — a metric from the last call, a line from the prospect's post, the next step you agreed on. The page tells you exactly which line to change. That single personalized line is what separates a template from spam.

Routing: four clicks to any page

The homepage has a four-step finder (type → industry → role → scenario) that maps to a predictable URL:

/{type}/{industry}/{role}/{scenario}
Enter fullscreen mode Exit fullscreen mode

Hub pages for each type and industry link down into the combinations, so people and crawlers can reach any page without search.

Guarding against duplicate content

With 20,000 pages, near-duplicates are the main risk. A build step compares bodies across combinations with a quick similarity check and flags pairs that are too close, which usually means a dimension's copy isn't pulling its weight:

function jaccard(a: string, b: string) {
  const A = new Set(a.toLowerCase().split(/\W+/)), B = new Set(b.toLowerCase().split(/\W+/));
  const inter = [...A].filter((x) => B.has(x)).length;
  return inter / (A.size + B.size - inter);
}
Enter fullscreen mode Exit fullscreen mode

AI for custom drafts, templates for speed

Templates cover the common cases instantly. For everything else there are free AI tools — an email generator, enhancer, subject-line tool and tone adjuster. The two work together: start from a template's structure, then adjust tone or generate a fresh draft when the situation is unusual.

Takeaways

  • Give each dimension its own slot and job, not just variables.
  • Keep emails short and leave one line for real personalization.
  • Use predictable URLs and hub pages for large combinatorial sites.
  • Check for near-duplicates at build time.

Browse or copy templates at salesemailtemplate.com — no login. What's your approach to generating content from combinations without it feeling generated?

Top comments (0)