すべての機関は冷たいメールを嫌うと言っています。私たちも同じでした — それまで、問題が冷たいメール自体ではなく、それに使用しようとしたすべてのツールであることに気付きました。ジェネリックなテンプレート。「Hi {firstName}」というエネルギー。毎月$300のプラットフォームなのに、それでも数時間の手作業が必要でした。そこで開発者らしく、自分たち自身で構築しました。

これは理論的なアーキテクチャのポストではありません。私たちはこのシステムを本番環境で数ヶ月間実行しており、実際に返信を得られる数千の個人化されたメールを送信しています。なぜ構築したのか、どのように部品が組み合わさるのか、何を大変な思いで学んだのかについて、正確に説明します。

目次

Why We Built Our Own Cold Email System with Claude, Instantly & Supabase

既製の外部サービスの問題

通常のツールを試してみました。Lemlist。Apollo。Woodpecker。多くのユースケースでは問題のないツールです。しかし、ヘッドレス Web 開発機関として、私たちの外部へのアプローチのニーズはこれらのプラットフォームが対応できない方法で特定のものでした。

常に問題が発生したことは次の通りです:

ジェネリックなパーソナライゼーションフィールドはパーソナライゼーションではありません。 誰かの会社名と職務経歴書をテンプレートに挿入することは、2025年に誰も騙しません。見込み客の実際のテックスタック、サイトのパフォーマンス問題、または公開ウェブサイトで見える特定のアーキテクチャ上の決定を参照するメールが必要でした。

リサーチステップがボトルネックでした。 最も成績の良い外部へのアプローチには、チーム内の誰かが実際に見込み客のサイトを見て、PageSpeed Insights を実行し、フレームワークをチェックし、何か具体的なものを書く必要がありました。これはリードあたり 10~15 分かかりました。規模によっては、それは専任の仕事です。

データはあまりにも多くの場所に存在していました。 リードが 1 つのスプレッドシート内にあり、メールシーケンスが別のプラットフォームにあり、結果が 3 番目のダッシュボードにあります。何も互いに通信しなかったため、フィードバック ループを構築することができませんでした。

AI 統合は表面的でした。 一部のプラットフォームは「AI ライティング」機能を追加しましたが、基本的には、誰もが他の人と同じように送信している同じ退屈なコピーを生成した GPT ラッパーでした。カスタムコンテキストをフィードする機能がなく、プロンプトを制御することもでき、マルチステップの推論チェーンを構築することもできませんでした。

AIが執筆だけでなく、リサーチを行うシステムが必要でした。

私たちのテックスタックとそれを選んだ理由

いくつかの反復後に、私たちが着地したのは次の通りです:

コンポーネント ツール 役割 月額
リード検索とメール検証 Hunter.io メールアドレスの検索と確認 $49 (Starter)
AI リサーチとコピーライティング Claude (Anthropic API) 見込み客を分析し、個人化されたメールを生成 ~$30-60
データベースとオーケストレーション Supabase リードの保存、状態管理、ワークフローのトリガー $25 (Pro)
メール送信とウォームアップ Instantly.ai 配信可能性、インフラ送信、ウォームアップ $30 (Growth)
自動化の接着剤 Custom Edge Functions + Cron すべてをつなぐ $0 (Supabase に含まれる)

多くの代替案を評価しました。ここで選んだ理由の短縮版は次の通りです:

GPT-4 を超える Claude: 両方を広範にテストしました。Claude 3.5 Sonnet (および 2025 年の Claude 4 Sonnet) は、より自然な音で、「AI のような」効果が少ないメールを一貫して生成しました。複雑なシステムプロンプトに従うことも優れており、ドリフトしませんでした。価格は相応でしたが、Claude のより長いコンテキストウィンドウは、見込み客ごとにより多くのリサーチデータをフィードできたことを意味しました。

Airtable またはカスタム Postgres セットアップ上の Supabase: 行レベルのセキュリティを備えた実際のデータベースが必要でしたが、インフラストラクチャを管理したくありませんでした。Supabase は、Postgres、Edge Functions、Cron ジョブ、および適切なダッシュボードをすべて 1 つの場所で提供しました。Supabase はクライアントプロジェクトでも広く使用しているため、チームはすでによく知っていました。

Lemlist または Smartlead 上の Instantly: Instantly のウォームアップネットワークは本当に良く、API はクリーンで、価格は私たちのボリュームに意味があります。Instantly の組み込みシーケンスビルダーは必要ありません。なぜなら、シーケンシングロジックを自分たちで処理するからです。

Apollo または Snov.io 上の Hunter: Hunter のメール検証は、テストした中で一貫して最も正確です。彼らのドメイン検索 API は高速で、データ品質は高いです。Apollo はより多くのデータポイントを持っていますが、メールの精度が低いことに気付きました。これは配信可能性を殺します。

アーキテクチャの概要

システムは 5 つのステージで動作し、それぞれは独立して実行されます:

[Lead Sources] → [Hunter Enrichment] → [Supabase DB] → [Claude Research + Copy] → [Instantly Sending]
     ↑                                       ↑                                           |
     |                                       |                                           |
     +----------- Feedback Loop -------------+-------------------------------------------+
  1. 取り込み: さまざまなソース (手動リスト、スクレーパー、紹介データ) から見込み客ドメインをフィードします
  2. エンリッチ: Hunter がコンタクトを検索し、メールを検証します
  3. 保存: すべてが状態追跡機能を備えた Supabase に着陸します
  4. リサーチと執筆: Claude が各見込み客を分析し、個人化されたコピーを生成します
  5. 送信: 承認されたメールを Instantly キャンペーンに送信します
  6. 学習: 返信データが Supabase に流れ、将来のパーソナライゼーションを知らせます

各ステージは分離されています。Hunter の API がダウンしても、エンリッチメントキューは単にバックアップします — 送信を壊しません。Claude を別のモデルと交換したい場合は、1 つの関数を変更します。

Why We Built Our Own Cold Email System with Claude, Instantly & Supabase - architecture

Hunter でのリード検出とエンリッチメント

Hunter.io は 2 つの重要なタスクを処理します: 企業の適切な人を見つけ、彼らのメールが実際に機能することを確認します。

エンリッチメント関数の簡略版は次の通りです:

import { createClient } from '@supabase/supabase-js';

const HUNTER_API_KEY = Deno.env.get('HUNTER_API_KEY');

async function enrichLead(domain: string) {
  // Domain search to find decision makers
  const searchRes = await fetch(
    `https://api.hunter.io/v2/domain-search?domain=${domain}&department=executive,it&api_key=${HUNTER_API_KEY}`
  );
  const searchData = await searchRes.json();
  
  const contacts = searchData.data.emails
    .filter((e: any) => e.confidence > 70)
    .slice(0, 3); // Top 3 contacts per domain
  
  // Verify each email
  for (const contact of contacts) {
    const verifyRes = await fetch(
      `https://api.hunter.io/v2/email-verifier?email=${contact.value}&api_key=${HUNTER_API_KEY}`
    );
    const verifyData = await verifyRes.json();
    
    if (verifyData.data.status === 'valid') {
      await supabase.from('leads').insert({
        domain,
        email: contact.value,
        first_name: contact.first_name,
        last_name: contact.last_name,
        position: contact.position,
        confidence: contact.confidence,
        status: 'enriched',
        enriched_at: new Date().toISOString()
      });
    }
  }
}

executiveit 部門でフィルタリングします。これらは私たちの買い手 (CTO、エンジニアリング担当副社長、技術的な創設者) だからです。Hunter の部門フィルタリングは完璧ではありませんが、多くのノイズを削減します。

学んだ 1 つのこと: メール検証をスキップしないでください。 Hunter の信頼スコアがあっても、すべてのアドレスを検証します。バウンス率が 3% を超えると、メール送信ドメインの評判が損なわれます。評判を 95% から 40% スパムフォルダに落とすドメインを見たことがあります。

週に約 500 ユニットの Hunter 検索を実行しており、これは Starter プランに快適に適合します。

Claude による AI パーソナライゼーション

ここが面白くなるところです。Claude 統合は単に「冷たいメールを書いてください」ではありません。これはマルチステップのリサーチと執筆パイプラインです。

ステップ 1: ウェブサイト分析

Claude が何かを書く前に、見込み客のウェブサイトに関するデータをフィードします。軽量な関数を使用して基本情報をスクレイプします:

async function analyzeProspectSite(domain: string) {
  // Fetch homepage and key pages
  const homepage = await fetch(`https://${domain}`);
  const html = await homepage.text();
  
  // Extract tech signals from HTML
  const signals = {
    hasNextJs: html.includes('__next') || html.includes('_next/static'),
    hasReact: html.includes('react') || html.includes('__REACT'),
    hasWordPress: html.includes('wp-content') || html.includes('wp-includes'),
    hasShopify: html.includes('shopify') || html.includes('cdn.shopify'),
    hasGatsby: html.includes('gatsby'),
    usesJQuery: html.includes('jquery'),
    metaGenerator: extractMeta(html, 'generator'),
    pageSize: html.length,
    // ... more signals
  };
  
  // Run PageSpeed check via API
  const psiData = await fetchPageSpeedInsights(domain);
  
  return {
    ...signals,
    performanceScore: psiData.lighthouseResult.categories.performance.score * 100,
    lcp: psiData.lighthouseResult.audits['largest-contentful-paint'].numericValue,
    cls: psiData.lighthouseResult.audits['cumulative-layout-shift'].numericValue,
    fid: psiData.lighthouseResult.audits['max-potential-fid'].numericValue
  };
}

これは Claude に実際のデータを与えます。「こんにちは、あなたの企業が X をしていることに気付きました」ではなく、「あなたのホームページの LCP は 4.2 秒で、それでも jQuery を React と一緒に実行しており、初期バンドルに 90KB を追加しています」というようなものです。

ステップ 2: Claude リサーチプロンプト

慎重に作られたシステムプロンプトで Claude の API を使用します。簡略版は次の通りです:

const researchPrompt = `You are a senior web developer analyzing a prospect's website for a headless development agency. Given the following technical data about their site, identify:

1. Their current tech stack (be specific)
2. 2-3 concrete performance or architecture issues
3. What a migration to a modern headless architecture could improve
4. A specific, non-obvious observation that shows genuine analysis

Do NOT be generic. If you can't find something specific, say so.
Do NOT mention "in today's digital landscape" or similar filler.
Be direct and technical.

Site data:
${JSON.stringify(siteAnalysis, null, 2)}

Prospect: ${lead.first_name} ${lead.last_name}, ${lead.position} at ${lead.domain}`;

const research = await anthropic.messages.create({
  model: 'claude-sonnet-4-20250514',
  max_tokens: 1000,
  messages: [{ role: 'user', content: researchPrompt }]
});

ステップ 3: メール生成

リサーチ出力は、実際のメールを書く 2 番目の Claude 呼び出しにフィードされます。リサーチと執筆を分割することは、重要な洞察でした - 両方を 1 つのプロンプトで行おうとしたとき、メールは悪化しました。Claude はより速く執筆に進むためにリサーチをスキップします。

const emailPrompt = `Write a cold email from a senior developer at a headless web agency.

Research notes:
${research.content[0].text}

Rules:
- 4-6 sentences max. Every sentence must earn its place.
- Lead with the most specific technical observation.
- No flattery. No "I love what you're doing."
- One clear CTA: ask if they'd want to see a performance audit.
- Sound like a developer, not a salesperson.
- Use their first name. No last name in greeting.
- Subject line: short, specific to their tech issue, lowercase.`;

結果は「あなたの Shopify Plus ストアはサーバーレンダリングされた商品ページです。それは静的に生成される可能性があります。これはすべての商品表示に 2 秒以上を追加しています」というメールです。「あなたの印象的な企業に気付いて、手を出したかった」の代わりに。

オーケストレーション層としての Supabase

Supabase は操作の脳です。ここがコアスキーマです:

create table leads (
  id uuid primary key default gen_random_uuid(),
  domain text not null,
  email text,
  first_name text,
  last_name text,
  position text,
  confidence int,
  status text default 'new', -- new, enriched, researched, drafted, approved, sent, replied, bounced
  site_analysis jsonb,
  research_notes text,
  email_subject text,
  email_body text,
  instantly_campaign_id text,
  sent_at timestamptz,
  opened_at timestamptz,
  replied_at timestamptz,
  created_at timestamptz default now(),
  updated_at timestamptz default now()
);

create index idx_leads_status on leads(status);
create index idx_leads_domain on leads(domain);

status フィールドがすべてを駆動します。Supabase Cron ジョブは 15 分ごとに実行され、各ステージでリードをピックアップして次に進みます:

-- Cron: Process enriched leads through Claude research
select cron.schedule(
  'process-research',
  '*/15 * * * *',
  $$select net.http_post(
    'https://your-project.supabase.co/functions/v1/process-research',
    '{}',
    '{"Authorization": "Bearer your-service-key"}'::jsonb
  )$$
);

Claude のレート制限内にとどまり、コストを予測可能に保つため、1 回の実行あたり 20 のリードをバッチ処理します。

site_analysis JSONB 列は非常に便利です。すべてのリード全体でクエリできます。例えば「WordPress を実行していて、パフォーマンス スコアが 50 未満のすべてのリードを表示します」 — そして、これらのセグメントからターゲット化されたキャンペーンを構築します。

Instantly でのスケール送信

Instantly が実際のメール配信を処理します。承認されたメールを API 経由でプッシュします:

async function pushToInstantly(lead: Lead) {
  const response = await fetch('https://api.instantly.ai/api/v1/lead/add', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      api_key: INSTANTLY_API_KEY,
      campaign_id: lead.instantly_campaign_id,
      skip_if_in_workspace: true,
      leads: [{
        email: lead.email,
        first_name: lead.first_name,
        last_name: lead.last_name,
        company_name: lead.domain,
        personalization_1: lead.email_subject,
        personalization_2: lead.email_body
      }]
    })
  });
  
  if (response.ok) {
    await supabase
      .from('leads')
      .update({ status: 'sent', sent_at: new Date().toISOString() })
      .eq('id', lead.id);
  }
}

Instantly のキャンペーン テンプレートは {{personalization_1}}{{personalization_2}} 変数を使用し、これは Claude で生成される件名と本文にマップされます。キャンペーン自体は単なるシェルです — すべてのインテリジェンスはシステムに存在します。

Instantly を通して 3 つの送信アカウントを実行しており、外部へのアプローチを送信する前に少なくとも 2 週間のウォームアップ期間があります。ドメインウォームアップはオプションではありません。最初のドメインが 1 週間以内にフラグ付けされた最初のドメインでこれを学びました。

配信可能性設定

送信インフラストラクチャ:

  • 3 つのドメイン (メインドメインではなく、ブランドの変形)
  • すべての SPF、DKIM、および DMARC が構成されている
  • Google Workspace アカウント (Outlook ではなく — Google は冷たいメールをより良く処理します)
  • Instantly ウォームアップは継続的に実行され、アクティブな送信日でも
  • 1 日あたりアカウントあたり最大 35 メール
  • 送信間隔が 3~7 分のランダム

自動化の接着剤

Supabase Edge Functions がすべてをつなぎます。フローは疑似コードです:

Every 15 minutes:
  1. Pick up leads with status='new', run Hunter enrichment → status='enriched'
  2. Pick up leads with status='enriched', run site analysis → status='analyzed'
  3. Pick up leads with status='analyzed', run Claude research + email gen → status='drafted'
  4. (Human reviews drafted emails in Supabase dashboard)
  5. Pick up leads with status='approved', push to Instantly → status='sent'
  6. Pull engagement data from Instantly API → update opened_at, replied_at

ステップ 4 は重要です。送信を完全に自動化しません。すべてのメールは送信前に人間による確認を受けます。これはたまの幻覚をキャッチします (Claude はかつて、サイトが Remix で構築されていると主張しましたが、明らかに Next.js でした) そして個人的な接触を追加させます。

Claude が 95% の時間で正しい仕事をするため、確認ステップはメールあたり約 2~3 秒かかります。Supabase ダッシュボード ビューを使用してバッチで承認します。

結果と学んだこと

2025 年 Q1 以降、このシステムを実行しています。実数は次の通りです:

メトリック 私たちのシステム 業界平均 (2025)
オープンレート 62% 24%
返信レート 8.4% 1-3%
肯定的な返信レート 4.1% 0.5-1%
バウンスレート 0.8% 3-5%
リードあたりのコスト接触 $0.18 $0.50-2.00
リードごとの時間 (人間) ~5 秒 (レビュー) 10-15 分

件名行が具体的であるため、開始率は高いです。「your shopify lcp is 4.2s」は開かれます。「Quick question」は開きません。

返信レートが高い理由は、メールが本物の技術知識を示しているためです。CTO があなたのテックスタックをサイトを正確に識別し、実際のパフォーマンスの問題を識別するメールを読むとき、それが外部へのアプローチであることを知っていても、彼らはより関与する可能性があります。

機能しなかったもの

完全に自動化された送信 (人間による確認なし): 2 週間これを試しました。Claude はテックスタックの詳細を約 5% の時間でハッシュします。LLM にとっては低いエラー率ですが、「あなたの React アプリ」という Vue を実行している人にメールを送信することは、ジェネリック メールを送信するよりも悪いです。信頼の損害は実物です。

長いメール: 最初の Claude プロンプトは 8~10 文のメールを生成しました。返信レートは 4~6 文で見るものの半分でした。短い方が良い。常に。

1 日あたりアカウントあたり 40 通以上のメールを送信: 配信可能性は崖を落ちます。2025 年では 30~35 が最適なスポットです。

オープンに基づいて Claude を使用するフォローアップの生成: トリガーされたフォローアップメールを生成しようとしました。フォローアップは押し付けがましく感じました。そして転換は価値がありませんでした。現在、3 日後に 1 つのシンプルな非 AI フォローアップを送信します。

コスト内訳

これは月額何か、大体 2,000 のリードを処理:

サービス 月額
Hunter.io (Starter) $49 500 検索と検証
Anthropic API (Claude) $45 ~2,000 リサーチとメール生成
Supabase (Pro) $25 データベース、Edge Functions、Cron
Instantly (Growth) $30 送信、ウォームアップ、分析
Google Workspace (3 アカウント) $21 インフラストラクチャ送信
ドメイン (3) $10 年間コストを配分
合計 ~$180 $0.09 リード処理ごと

Apollo の $79/月プラン (限定的なエンリッチメント、基本的なシーケンス) または Lemlist の $69/月あたりのシートと比較します。より少なく費やしており、はるかに優れた結果を得ています。なぜなら、パーソナライゼーションは実物だからです。テンプレートではなく。

文脈の場合、このシステムは、Next.js 開発およびAstro 開発プロジェクトに変わったリードを直接生成しており、月額コストの 50~100 倍の価値があります。ROI は不条理です。

よくある質問

このシステムを構築するのにどのくらい時間がかかりましたか? 最初に動作するバージョンは、パートタイムの努力で約 2 週間かかりました — 合計約 40 時間です。それ以来、継続的に反復しており、ほとんどの場合 Claude プロンプトを調整し、エッジケース処理を追加しています。Supabase Edge Functions と REST API に慣れていれば、週末に基本バージョンを実行できます。

これは単に追加のステップとのスパムではありませんか? 公正な質問。違いは、すべてのメールが受信者のウェブサイトについての本物の技術的な観察を含むということです。「10,000 人にコールアップしましょう」をブラストしていません。実際に問題を解決する人たちにフィードする特定の有用な洞察を送信しています。登録解除率は 0.5% 未満であり、受信者もスパムとは見なしていないことを示唆しています。

Claude の代わりに GPT-4 または Gemini を選ばなかったのはなぜですか? 3 つすべてをテストしました。Claude は、特に「ジェネリックではない」と「フィラーフレーズのような」制約に対して、システムプロンプトをより確実に従いました。GPT-4 は明示的な指示がないにもかかわらず営業的な言語に向かう傾向があります。Gemini は高速でしたが、出力品質は不安定でした。これはモデルが進化するにつれて変わるかもしれません。またはシステムはモデルを簡単に交換できるように設計されています。

GDPR および CAN-SPAM コンプライアンスをどのように処理しますか? すべての外部へのアプローチはビジネスメール (個人ではない) をターゲットにしており、すべてのメールに住所を含めます。削除要求を自動化された webhook 経由で直ちに尊重します。GDPR の場合、B2B 外部アプローチの正当な利益に基づいてデータを処理し、処理活動の記録を保持し、削除要求を直ちに尊重します。また、90 日以上前のリードを自動的にデータベースから削除します。あなたの具体的な状況については弁護士に相談してください — これは法的助言ではありません。

リードが返信したときはどうなりますか? 返信は Instantly の API から Supabase に流れます。すべての返信に対して Slack 通知を受け取り、人間がすぐに会話を引き継ぎます。返信処理に AI は使用しません。誰かが関与するとすぐに、彼らは実物の人に値する。関心のある見込み客は、連絡ページまたはコール予約リンクに直接指定されます。

このアプローチは技術以外のサービスでも機能しますか? サイト分析の部分は Web 開発固有ですが、アーキテクチャパターン — リードをエンリッチし、AI を使用してリサーチしてパーソナライズし、専用ツール経由で送信 — あらゆる B2B の外部へのアプローチで機能します。リサーチ入力を変更するだけです。デザイン機関はビジュアルデザインと UX パターンを分析する可能性があります。マーケティング機関は SEO メトリックスをプルする可能性があります。キーは Claude にリアルデータをフィードすることです。それを作り上げるよう求めるのではなく。

このシステムの維持の最も難しい部分は何ですか? プロンプト保守。Claude モデルが更新されると、完璧に機能したプロンプトは調整が必要な場合があります。また、電子メール配信可能性の監視にも時間を費やします — Google Postmaster Tools をチェック、スパムレート スパイクを監視、送信アカウントを回転。全体で週に 2~3 時間のメンテナンス。

これを製品として販売しますか? 考えてみました。しかし正直に言うと、競争上の優位性は価値があり過ぎます。すべての機関がこの正確なシステムを実行する場合、受信者が AI でリサーチされたメールをどこでも表示を開始するため、有効性は低下します。現在のところ、内部ツールとして保持しています。ビジネスのための同様のシステムの設定に関心がある場合は、連絡を取ってくださいヘッドレス CMS 開発作業の一部として、類似したシステムのセットアップを支援した少数のクライアントがいます。