diff --git a/README.md b/README.md index 8265978..cc4c35c 100644 --- a/README.md +++ b/README.md @@ -41,9 +41,16 @@ +# Email templates: + +A curated, production-tested template pack lives in +[`templates/`](templates/) — sales, recruiting, partnership, warm-intro, +and follow-up. Each is plaintext, under ~120 words, with a single CTA and +deliverability notes. See [`templates/README.md`](templates/README.md) for +how to load one into a campaign. + # Move the needle TO-DO list: -- [x] Templates for popular email needs i.e "onboarding for SaaS" — see `/templates` - [ ] Integration with GHL / N8N # Content TO-DO list: diff --git a/templates/README.md b/templates/README.md new file mode 100644 index 0000000..16ffaca --- /dev/null +++ b/templates/README.md @@ -0,0 +1,115 @@ +# Coldflow templates + +A small, opinionated library of cold email templates for the use cases that +actually drive replies. Plaintext, under ~120 words, one CTA per email. + +These are content — markdown files you copy into the campaign builder. They +are not loaded by the app at runtime. For the in-app picker (`Browse +templates` button), see `src/lib/templates/catalog.ts`. + +## Index + +### Sales (3) +- [`sales/saas-pain-point.md`](sales/saas-pain-point.md) — open with a concrete + symptom of the problem your product solves. +- [`sales/agency-case-study.md`](sales/agency-case-study.md) — lead with a peer + outcome, not a pitch. +- [`sales/founder-direct.md`](sales/founder-direct.md) — founder-to-buyer + honesty trade for early-stage selling. + +### Recruiting (2) +- [`recruiting/passive-candidate.md`](recruiting/passive-candidate.md) — first + touch to a happy, employed engineer. +- [`recruiting/founder-hiring.md`](recruiting/founder-hiring.md) — founder + reaching out for the first or second engineer. + +### Partnership (2) +- [`partnership/integration-proposal.md`](partnership/integration-proposal.md) — + scoped product integration pitch. +- [`partnership/co-marketing.md`](partnership/co-marketing.md) — joint post, + webinar, or list swap. + +### Warm intro (2) +- [`warm-intro/mutual-connection.md`](warm-intro/mutual-connection.md) — when + a shared contact has agreed to be named. +- [`warm-intro/event-followup.md`](warm-intro/event-followup.md) — convert a + conference/dinner conversation into a real thread. + +### Follow-up (1) +- [`follow-up/no-reply-bump.md`](follow-up/no-reply-bump.md) — single bump on + a non-replier with a soft "give me an out" CTA. + +## Format + +Each template is a `.md` file with YAML front-matter and a plaintext body: + +```yaml +--- +id: sales_saas_pain_point +name: SaaS — Pain Point Opener +category: sales +persona: Who you are when you send this +use_case: When this template wins +deliverability_notes: | + What to keep, what to swap, what trips spam filters. +subject: Noticed {{specific_signal}} at {{company}} +variables: + - first_name + - company + - specific_signal +--- + +Hi {{first_name}}, + +...body... +``` + +`{{variable}}` placeholders match the syntax used by the in-app campaign +builder (see `src/lib/templates/catalog.ts`). Replace them per-recipient +before sending. + +## How to load into Coldflow + +Coldflow's MVP supports a single-step sequence with per-recipient +personalization. There is no separate "CSV upload" — the recipient list is +pasted into a textarea on the new-campaign page. + +1. **Start a new campaign** — go to `/dashboard/campaigns/new` (page source: + [`src/app/(frontend)/dashboard/campaigns/new/page.tsx`](../src/app/(frontend)/dashboard/campaigns/new/page.tsx)). +2. **Pick a connected sender** under *Send from*. If none are connected, set + one up at `/dashboard/email-accounts` first. +3. **Paste recipients** into the *Recipients* textarea. One per line, comma, + or semicolon. Optional `Name ` form is parsed by + [`src/lib/recipientParser.ts`](../src/lib/recipientParser.ts), so a + pasted CSV column works directly. +4. **Copy the template** — open the chosen file in this folder, copy + `subject:` into the *Subject* field and the body (everything below the + second `---`) into the *Body* field. +5. **Verify variables** — the form lists every `{{placeholder}}` it detected + under *Variables in this template*. Match them against the front-matter + `variables:` list. +6. **Create campaign** — Coldflow queues the emails through the configured + sending limit (see `src/app/api/email-queue/process/route.ts`). + +If you want the template available in the in-app *Browse templates* picker +instead of one-off copy/paste, add an entry to `TEMPLATES` in +[`src/lib/templates/catalog.ts`](../src/lib/templates/catalog.ts) and the +catalog test will enforce that every `{{variable}}` is declared. + +## Deliverability notes that apply to every template + +- Send plaintext. No tracking pixel, no signature image, no link in send #1 + unless the recipient asked for one. +- Personalize the variable that carries the email — the "specific signal" or + "specific conversation detail" line. Generic versions get filtered. +- Stay under 120 words. Longer reads as marketing. +- Reply-bumps go on the same thread (`Re: {{previous_subject}}`), not a new + one. Coldflow's silent-reply follow-up handles this automatically; see + `Pending follow-ups` on the dashboard. +- One CTA per email. If you want two, send two emails. + +## Contributing + +New templates welcome. Keep the front-matter shape consistent, run a quick +spam-word pass before opening a PR, and aim for "useful as-is to a real +sender" over "clever". diff --git a/templates/follow-up/no-reply-bump.md b/templates/follow-up/no-reply-bump.md new file mode 100644 index 0000000..4602312 --- /dev/null +++ b/templates/follow-up/no-reply-bump.md @@ -0,0 +1,32 @@ +--- +id: follow_up_no_reply_bump +name: Follow-up — No-Reply Bump +category: follow-up +persona: Anyone whose first cold email got opened but no reply, 4–7 days later +use_case: Single follow-up to a non-replier. Shorter than the first send, with a softer ask designed to surface "wrong person / wrong time" rather than push for a meeting. +deliverability_notes: | + Send as a Reply-All to the original thread (Re: subject), not a new thread — + Gmail groups it and reply rates roughly 2x. Don't repeat the original pitch; + call out the silence and offer an out. Avoid "just bumping this up", "did you + see my last email" — both read as pushy. Under 80 words. +subject: "Re: {{previous_subject}}" +variables: + - first_name + - previous_subject + - original_topic + - sender_name +--- + +Hi {{first_name}}, + +Following up on the thread below — figured I'd give you an out rather than chase. + +A one-line reply works: + +1. "Yes, send more" — and I'll send the short version +2. "Wrong person" — and I'll stop and find the right one +3. "Not now, ask me in {{original_topic}} months" — and I'll set a reminder + +Whichever it is, no offense taken. Easier for both of us than a third email. + +— {{sender_name}} diff --git a/templates/partnership/co-marketing.md b/templates/partnership/co-marketing.md new file mode 100644 index 0000000..3feccc8 --- /dev/null +++ b/templates/partnership/co-marketing.md @@ -0,0 +1,32 @@ +--- +id: partnership_co_marketing +name: Partnership — Co-Marketing +category: partnership +persona: Marketing lead or founder proposing a content / webinar / list swap with a non-competing peer +use_case: Cold open to a complementary brand offering a specific co-marketing motion (joint post, webinar, newsletter swap). +deliverability_notes: | + Pick ONE format and propose it concretely. "Let's do something together" is dead + on arrival. Mentioning your audience size up front sets honest expectations. + Avoid "amazing", "huge opportunity". Under 120 words. Single CTA. +subject: {{my_company}} + {{their_company}} — joint {{format}}? +variables: + - first_name + - my_company + - their_company + - format + - my_audience_size + - shared_audience + - sender_name +--- + +Hi {{first_name}}, + +Our audiences overlap more than you'd expect — {{shared_audience}} reads both of us. + +Concrete pitch: a joint {{format}}. We bring {{my_audience_size}} on the {{my_company}} side; happy to do the heavier lift (drafting, design, scheduling) so it's mostly a yes/no decision on your end. + +I'll send a one-page outline before any commitment, so you can see exactly what would go out and where. If the angle isn't right, kill it — no hard feelings. + +Worth 20 minutes next week to talk through it? + +— {{sender_name}} diff --git a/templates/partnership/integration-proposal.md b/templates/partnership/integration-proposal.md new file mode 100644 index 0000000..b51a40a --- /dev/null +++ b/templates/partnership/integration-proposal.md @@ -0,0 +1,31 @@ +--- +id: partnership_integration +name: Partnership — Integration Proposal +category: partnership +persona: Founder or partnerships lead proposing a product integration with a complementary tool +use_case: Cold open to a peer company suggesting a real, scoped integration. Strongest when you can name the shared customer who'd use it. +deliverability_notes: | + Lead with the shared customer or use case — vague "let's partner" notes get ignored. + Be specific about who builds what. Skip the words "synergy", "ecosystem", and + "strategic". Under 120 words. One clear next step (intro call), no marketing fluff. +subject: {{my_product}} ↔ {{their_product}} integration? +variables: + - first_name + - my_product + - their_product + - shared_customer_signal + - integration_shape + - sender_name +--- + +Hi {{first_name}}, + +Quick proposal: an integration between {{my_product}} and {{their_product}}. + +{{shared_customer_signal}} is the wedge — we hear it from users every week and so do you, based on what shows up in your support threads. + +Concretely: {{integration_shape}}. Should be a couple of days of work on our side; maybe similar on yours. We'd co-launch and split the post. + +Worth a 30-minute call to see if the shape works on your end? If your team already has something in flight here, I'm happy to step out of the way. + +— {{sender_name}} diff --git a/templates/recruiting/founder-hiring.md b/templates/recruiting/founder-hiring.md new file mode 100644 index 0000000..8c3a95e --- /dev/null +++ b/templates/recruiting/founder-hiring.md @@ -0,0 +1,31 @@ +--- +id: recruiting_founder_hiring +name: Recruiting — Founder Hiring Eng #1 +category: recruiting +persona: Solo or small-team founder hiring their first or second engineer +use_case: Founder-to-engineer cold note. Trades polish for substance — what they'll actually build and why it matters. Best at seed / Series A. +deliverability_notes: | + Don't oversell — engineers smell it. Be specific about the problem space, not the + funding number. Avoid "rocketship", "unicorn", "10x". Plaintext, under 120 words. + No calendar link in send #1; let them ask for one. +subject: First eng hire at {{my_company}} — your work caught my eye +variables: + - first_name + - candidate_specific_work + - my_company + - what_were_building + - why_now + - sender_name +--- + +Hi {{first_name}}, + +Founder of {{my_company}} here. {{candidate_specific_work}} is exactly the kind of taste I'm trying to hire — most generalists I've talked to can't do that part. + +We're building {{what_were_building}}. {{why_now}} — and the next six months are the part where the right second person changes the whole company. + +I'm not going to pretend it's a sure thing. But it's real work, real users already, and you'd own a meaningful chunk of the surface area. + +Open to a 30-minute call to walk through it? If not, no worries — I'd still take any pointers on people you'd hire for this. + +— {{sender_name}} diff --git a/templates/recruiting/passive-candidate.md b/templates/recruiting/passive-candidate.md new file mode 100644 index 0000000..82c5480 --- /dev/null +++ b/templates/recruiting/passive-candidate.md @@ -0,0 +1,32 @@ +--- +id: recruiting_passive_candidate +name: Recruiting — Passive Candidate +category: recruiting +persona: Hiring manager or in-house recruiter reaching out to a happy, employed engineer +use_case: First touch to a passive candidate. Designed to respect their time and earn a reply even from a "not looking" state. +deliverability_notes: | + Lead with one specific thing from their work — generic "I came across your profile" + reads as bulk mail and lands in Promotions. Disclose comp range up front; missing + it is the #1 reason passives ignore recruiter mail. Keep under 120 words. +subject: {{role_title}} at {{company}} — open to a chat? +variables: + - first_name + - candidate_signal + - role_title + - company + - team_focus + - comp_range + - sender_name +--- + +Hi {{first_name}}, + +{{candidate_signal}} is the reason I'm writing — that's the exact shape of work my team is hiring for. + +We're looking for a {{role_title}} at {{company}}. Team is small, ships weekly, and is focused on {{team_focus}}. Comp range is {{comp_range}} plus equity, fully remote. + +Even if you're happy where you are, I'd love 20 minutes to swap notes and tell you what we're building. Worst case you walk away with context for whenever the timing's right. + +Reply with a day that works and I'll send a couple of times. + +— {{sender_name}} diff --git a/templates/sales/agency-case-study.md b/templates/sales/agency-case-study.md new file mode 100644 index 0000000..ae19c96 --- /dev/null +++ b/templates/sales/agency-case-study.md @@ -0,0 +1,30 @@ +--- +id: sales_agency_case_study +name: Agency — Case Study Wedge +category: sales +persona: Agency principal or BDR selling done-for-you services to a similar-shape buyer +use_case: Cold open that leads with a peer outcome, not a pitch. Strongest when the case study company is one tier ahead of the prospect. +deliverability_notes: | + Lead with the peer name, not the offer. Replace {{case_study_company}} with a real + customer (with permission). Avoid the phrases "100%", "best price", and "act now". + 120-word cap. One soft CTA, no calendar link in send #1. +subject: How {{case_study_company}} hit {{outcome_metric}} +variables: + - first_name + - company + - case_study_company + - outcome_metric + - service_area + - timeline + - sender_name +--- + +Hi {{first_name}}, + +We worked with {{case_study_company}} on {{service_area}} and they hit {{outcome_metric}} in {{timeline}}. Their team looked a lot like yours at {{company}} a year ago. + +Not pitching — just thought the playbook might be useful context for whatever you're already running. + +If a 20-minute walkthrough of what worked (and what we'd do differently) is interesting, reply with a day that's good and I'll send a couple of times. If you'd rather just see the writeup, say "send the writeup" and I will. + +— {{sender_name}} diff --git a/templates/sales/founder-direct.md b/templates/sales/founder-direct.md new file mode 100644 index 0000000..bb08318 --- /dev/null +++ b/templates/sales/founder-direct.md @@ -0,0 +1,29 @@ +--- +id: sales_founder_direct +name: Sales — Founder Direct +category: sales +persona: Founder selling early — under 100 customers, willing to do the work themselves +use_case: Personal note from a founder to a target buyer. Trades polish for honesty. Best at small ACVs where the founder is still the best closer. +deliverability_notes: | + Plaintext only. No tracking pixel, no signature image. The "I built this" framing + carries the email — avoid corporate phrasing. Skip words like "solution", "leverage", + "synergy". Stay under 120 words; longer reads as marketing. +subject: Built this for teams like {{company}} +variables: + - first_name + - company + - product_name + - core_use_case + - my_company + - sender_name +--- + +Hi {{first_name}}, + +Quick one — I'm the founder of {{my_company}}. Built {{product_name}} after watching three teams burn weeks on {{core_use_case}} the hard way. + +Still small enough that I do onboarding personally and ship fixes the same week. I'd rather lose you than oversell, so if it isn't a fit I'll say so on the call. + +Worth 20 minutes this week or next? If now isn't the moment, totally fine — happy to circle back in a quarter. + +— {{sender_name}} diff --git a/templates/sales/saas-pain-point.md b/templates/sales/saas-pain-point.md new file mode 100644 index 0000000..41eb446 --- /dev/null +++ b/templates/sales/saas-pain-point.md @@ -0,0 +1,29 @@ +--- +id: sales_saas_pain_point +name: SaaS — Pain Point Opener +category: sales +persona: SaaS founder or AE selling into product/engineering teams +use_case: Cold open to a buyer where you've spotted a concrete symptom of the problem your product solves. +deliverability_notes: | + Keep it under 120 words. No links in the first send (calendar offered as text). + Avoid the words "free", "guarantee", and "limited time". One question, one CTA. + Personalize {{specific_signal}} per recipient — generic versions get filtered. +subject: Noticed {{specific_signal}} at {{company}} +variables: + - first_name + - company + - specific_signal + - pain_outcome + - product_name + - sender_name +--- + +Hi {{first_name}}, + +Saw {{specific_signal}} at {{company}} — usually that means {{pain_outcome}} is showing up somewhere in the week. We hear it most from teams that grew past the point where one person could hold the whole flow in their head. + +{{product_name}} fixes the part nobody wants to own: the boring middle of the pipeline that breaks quietly until a customer notices. + +Worth 15 minutes to see whether the shape of your problem matches what we usually see? If it doesn't, I'll say so and we both move on. + +— {{sender_name}} diff --git a/templates/warm-intro/event-followup.md b/templates/warm-intro/event-followup.md new file mode 100644 index 0000000..76c014a --- /dev/null +++ b/templates/warm-intro/event-followup.md @@ -0,0 +1,29 @@ +--- +id: warm_intro_event_followup +name: Warm Intro — Event Follow-up +category: warm-intro +persona: Anyone who met a contact briefly at a conference, meetup, or dinner and wants to convert it to a real thread +use_case: Send within 48 hours of meeting. Reminds them of the specific moment, not the event in general. Highest reply rate of any warm template. +deliverability_notes: | + Send from a real human address, not a sequencer-looking domain. Mention the + specific conversation detail — generic "nice to meet you at X" gets archived. + Keep under 100 words. No links unless they asked for one in person. +subject: Following up from {{event_name}} +variables: + - first_name + - event_name + - specific_conversation_detail + - thing_you_promised + - next_step + - sender_name +--- + +Hi {{first_name}}, + +Good chat at {{event_name}} — {{specific_conversation_detail}} stuck with me on the flight home. + +Promised I'd send {{thing_you_promised}}. Here it is. + +If {{next_step}} still makes sense, I'm around most of next week. Reply with a couple of times that work and I'll pick one. + +— {{sender_name}} diff --git a/templates/warm-intro/mutual-connection.md b/templates/warm-intro/mutual-connection.md new file mode 100644 index 0000000..77eb2d5 --- /dev/null +++ b/templates/warm-intro/mutual-connection.md @@ -0,0 +1,28 @@ +--- +id: warm_intro_mutual_connection +name: Warm Intro — Mutual Connection +category: warm-intro +persona: Anyone reaching out after a referral from a shared contact (investor, peer founder, ex-colleague) +use_case: First touch where a mutual contact has agreed to be named. Highest-converting cold email there is — don't waste it. +deliverability_notes: | + Always ask the mutual contact's permission before naming them. Reply rates drop + hard if they didn't actually expect you to mention them. Keep it short — under 90 + words is ideal. The mutual's name does the work; the email shouldn't. +subject: {{mutual_contact}} suggested I reach out +variables: + - first_name + - mutual_contact + - your_relevance + - their_problem_area + - sender_name +--- + +Hi {{first_name}}, + +{{mutual_contact}} mentioned you might be running into {{their_problem_area}} and suggested I get in touch — {{your_relevance}}. + +I won't pitch anything in this email; happy to either send a 2-minute walkthrough video or grab 20 minutes whenever it's easy. + +Which is better for you? + +— {{sender_name}}