# ファイルアップロードなしで見積もり依頼フォームを作る

> 資料をアップロードではなく共有リンクで受け取り、すべての依頼に期限を付け、リンクの多いリードがスパムにならないようにする見積もり依頼フォームです。

公開日 2026-10-25 · https://ikiform.com/ja/guides/lead-capture/quote-request

Ikiform は `422 files_not_supported` でファイルアップロードを拒否するので、資料は `url` フィールドで共有フォルダーへのリンクとして求めます。サービスと予算は選択式にして、すべての依頼が同じ形で届くようにし、成功メッセージで回答までの期間を約束します。そのうえで各依頼を期限付きでチームに送り、約束を守れるようにします。

## 見積もり依頼ならではの違い

見積もり依頼には資料が付いてきます。概要書、間取り図、部品の一覧表、昨年のデザインなどです。よくある答えはファイル入力欄ですが、ここではうまくいきません。それを前提に設計する前に、理由を知っておく価値があります。

ファイルアップロードにはまだ対応していません。ファイル付きの送信には `422 files_not_supported` が返ります。拒否されるのはファイルだけでなく送信全体なので、PDF を添付した訪問者は、フォームがエラーを表示して入力内容を残さない限り、入力したものをすべて失います。共有リンクならこの問題を避けられ、独自の利点もあります。依頼主は送信後にファイルを追加でき、サイズの上限もなく、大きなものが受信トレイにたまることもありません。

図: 見積もり依頼フォームでのファイル入力欄とリンクのフィールドの比較

1. ファイル入力欄では、訪問者が brief.pdf を添付し、ブラウザーが multipart で送信します。
2. Ikiform は 422 files_not_supported で送信全体を拒否します。
3. 何も保存されないので、メールも Webhook も送られません。
4. リンクのフィールドでは、訪問者が共有フォルダーへのリンクを貼り付けます。
5. Ikiform は有効な https の URL であることを確認し、依頼を保存します。
6. リンクは通知メールとチャットに届き、チームの誰でも開けます。

同じ依頼で、結果は 2 通り。フォルダーのリンクを求めれば、ファイルがフォームを通ることはありません。

## フィールド

[見積もり依頼のテンプレート](https://ikiform.com/forms/quote-request)には、電話番号、会社、時期を含むすべてのフィールドがあります。下の版はそれを絞り込み、リンクのフィールドを追加したものです。`http:` のリンクや、`drive.google.com` だけのリンクを入れて、`url` フィールドの応答を試してみてください。

フォーム: Quote request

- **名前** (`name`, text, 必須)
- **仕事用のメールアドレス** (`email`, email, 必須)
- **ご依頼の内容は？** (`service`, select, 必須)
- **予算** (`budget`, select)
- **ファイルへのリンク** (`files_url`, url)
- **見積もりの対象は何ですか？** (`details`, textarea, 必須)

`files_url` は `https_only` 付きの `url` フィールドなので、`drive.google.com/...` だけなら `https://drive.google.com/...` として保存され、`http:` のリンクは拒否されます。

| フィールド | この形にしている理由 |
| --- | --- |
| `files_url` | ファイルごとのフィールドではなく、フォルダーへのリンク 1 つ。中身は依頼主が管理し、あとから追加できます |
| `service` | 誰が見積もるかを決めます。ラベルを変えても値は変わらないので、振り分けが安定します |
| `budget` | 任意で、何も送らない **Not sure yet** の選択肢付き。予算を必須にするとリードを失います |
| `details` | 必須で、20 文字以上。見積もりには範囲が必要で、それを得るのがここです |

## フォーム

素の HTML です。`type="url"` でスマートフォンに適切なキーボードが表示され、ヘルプテキストでフォルダーの共有方法を伝えるので、最初のリンクが非公開だったときのやり取りが 1 往復減ります。

`quote.html`:

```html
<form action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx" method="POST">
  <label for="name">Name</label>
  <input id="name" name="name" autocomplete="name" required />

  <label for="email">Work email</label>
  <input id="email" name="email" type="email" autocomplete="email" required />

  <label for="service">What do you need?</label>
  <select id="service" name="service" required>
    <option value="design">Design</option>
    <option value="development">Development</option>
    <option value="both">Design and development</option>
  </select>

  <label for="budget">Budget</label>
  <select id="budget" name="budget">
    <option value="">Not sure yet</option>
    <option value="under_5k">Under $5,000</option>
    <option value="5k_20k">$5,000 to $20,000</option>
    <option value="over_20k">Over $20,000</option>
  </select>

  <label for="files_url">Link to your files</label>
  <input id="files_url" name="files_url" type="url" inputmode="url" placeholder="https://drive.google.com/..." aria-describedby="files-help" />
  <p id="files-help">A shared folder with the brief, mockups or specs. Set it so anyone with the link can view.</p>

  <label for="details">What should the quote cover?</label>
  <textarea id="details" name="details" rows="5" minlength="20" required></textarea>

  <input type="hidden" name="_redirect" value="https://example.com/quote/thanks" />
  <input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden />
  <button>Request a quote</button>
</form>
```

> 古いフォームから引き継いだ `<input type="file">` があれば削除してください。空のものは無視されます。ファイルが選ばれていると、multipart や `FormData` の送信は全体が失敗し、素の urlencoded のフォームはファイル名だけを送ります。どちらの場合もファイルは届きません。

## リンクとスパムスコア

見積もりフォームは、本物のリードが意図してリンクを送る唯一の場所で、リンクはスパムの兆候です。すべてのフィールドを合わせてリンクが 3 つ以上あるとスコアに 2 が加わります。`url` フィールドは完全な `https://` のリンクとして保存されるので、数に入ります。

| 依頼に含まれるもの | スコア | 結果 |
| --- | --- | --- |
| フォルダーのリンク | 0 | 受信 |
| フォルダーのリンクと、`details` の中のリンク 2 つ | +2 | 受信 |
| 同じ 3 つのリンクを、24 時間以内に同じフィールドで再送 | +2 と +3 | 5 でスパム |

3 行目は、最初の送信が失敗したと思った本物の人です。だからこそ、リンクのフィールドは 3 つではなく 1 つにし、成功の状態は見間違えようのないものにすべきです。**Spam** フィルターは毎週確認してください。依頼をスパムではないとマークすると、その時点でメールと Webhook が送られます。

## すべての依頼に期限を付ける

成功メッセージは 2 営業日以内の見積もりを約束しています。この Cloudflare Worker が、その約束をチームが見える日付に変えます。Webhook を検証し、`created_at` から期限を計算し、ファイルのリンク付きで依頼を見積もり用のチャンネルに投稿します。

`src/index.ts`:

```ts
import { verifyWebhook, WebhookVerificationError } from "@ikiform/sdk/webhooks";

function addWorkingDays(from: Date, days: number) {
  const date = new Date(from);
  while (days > 0) {
    date.setUTCDate(date.getUTCDate() + 1);
    const day = date.getUTCDay();
    if (day !== 0 && day !== 6) days -= 1;
  }
  return date.toISOString().slice(0, 10);
}

export default {
  async fetch(request: Request, env: { IKIFORM_WEBHOOK_SECRET: string; SLACK_QUOTES_WEBHOOK: string }) {
    const payload = await request.text();
    let event;
    try {
      event = await verifyWebhook({ payload, headers: request.headers, secret: env.IKIFORM_WEBHOOK_SECRET });
    } catch (error) {
      if (error instanceof WebhookVerificationError) return new Response(error.reason, { status: 400 });
      throw error;
    }
    if (event.type !== "submission.created") return new Response(null, { status: 204 });

    const quote = event.data.fields;
    const due = addWorkingDays(new Date(event.data.created_at), 2);
    const lines = [
      `Quote due *${due}*: ${quote.service} for ${quote.name} (${quote.budget ?? "budget not given"})`,
      quote.files_url ? `Files: ${quote.files_url}` : "No files linked. Ask for them in the first reply.",
      `Reply: mailto:${quote.email}`,
    ];

    const response = await fetch(env.SLACK_QUOTES_WEBHOOK, {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({ text: lines.join("\n") }),
    });
    if (!response.ok) return new Response(`Slack answered ${response.status}`, { status: 502 });
    return new Response(null, { status: 204 });
  },
};
```

- 営業日は UTC の土曜日と日曜日を除きます。休日を考慮して見積もるなら、休日を追加してください。
- `files_url` がない場合は、空の行ではなく、最初の返信でファイルを求めるようにというリマインダーが出ます。
- Slack が失敗したときに `502` を返すと Ikiform が同じ配信をリトライするので、依頼が失われません。

Worker の URL を **Webhooks** に追加し、`whsec_` のシークレットを `IKIFORM_WEBHOOK_SECRET` にコピーし、Slack の URL をシークレットとして保存します。受信 Webhook の作り方は [Slack のガイド](https://ikiform.com/blog/form-submissions-to-slack.md)にあります。

## 動作を確認する

1. Google ドライブか Dropbox のフォルダーのリンクを付けて送信します。通知メールのリンクをプライベートウィンドウで開き、閲覧できることを確認します。
2. `http:` のリンクで送信します。送信は `422` で拒否され、メッセージに `files_url` が示されます。
3. テンプレートで `type="file"` を検索し、Ikiform に送信する見積もりフォームから該当するものをすべて削除します。
4. 見積もり用のチャンネルを確認します。メッセージに 2 営業日後の期限とファイルのリンクが表示されます。
5. 通知メールで **Reply** を押します。フォームに入力されたアドレス宛てに書けます。

## ハマりどころ

- **非公開のリンク。** いちばんよくある失敗は、所有者しか開けないリンクです。ヘルプテキストで共有方法を伝え、アクセス権は待たずに最初の返信で求めてください。
- **ファイルはあるがフォルダーがない依頼主。** 最初のメールに添付ファイル付きで返信してもらいましょう。reply-to のおかげで、ファイルはチームとの通常のメールのスレッドに入ります。
- **長い作業範囲。** 通知メールに表示される値は 500 文字までです。`details` の全文はダッシュボードと Webhook にあります。
- **受付メールはない。** Ikiform はフォームに入力した人にはメールを送りません。ページ上のメッセージが受付の連絡になるので、回答までの期間を具体的にしてください。

## よくある質問

### フォームでファイルのアップロードを受け付けられますか？

まだできません。ファイルを含む送信は 422 files_not_supported で拒否されます。代わりに、共有ドライブの URL などファイルへのリンクを尋ねてください。

### 見積もりフォームで図面、概要書、写真を集めるには？

url フィールドで共有フォルダーへのリンクを 1 つ求め、ヘルプテキストでリンクを知っている全員がフォルダーを閲覧できるようにと伝えます。依頼主は依頼を送ったあとでもフォルダーにファイルを追加できます。

### リンクがいくつかある見積もり依頼がスパムになったのはなぜですか？

リンクが 3 つ以上あるとスパムスコアに 2 が加わり、同じフィールドを 24 時間以内に再送すると 3 が加わって、しきい値の 5 に達します。リンクのフィールドは 1 つにし、依頼をスパムではないとマークしてメールと Webhook を送ってください。

### 予算のフィールドを任意にできますか？

はい。required をオフにし、最初の選択肢として Not sure yet のような値が空のものを追加します。空の選択では何も送られず、Ikiform は予算なしで依頼を保存します。

## その他のガイド

- [リード獲得フォーム](https://ikiform.com/ja/guides/lead-capture.md): 自分のサイトに置くリード獲得フォームです。返信先付きでメールを送り、チームチャットに通知し、CRM に流し込むので、見込み客がまだいるうちに返信できます。
- [プロジェクト問い合わせフォーム](https://ikiform.com/ja/guides/lead-capture/project-inquiry.md): スタジオやフリーランス向けのプロジェクト依頼フォームです。誰かが概要を読む前に、予算と時期で問い合わせを有望、検討、対象外に振り分けます。
- [デモ依頼フォーム](https://ikiform.com/ja/guides/lead-capture/demo-request.md): リードを保存してから、名前とメールアドレスを入力済みの状態で訪問者を Cal.com や Calendly に送るデモ予約フォームです。
- [HubSpot や Pipedrive にリードを送る](https://ikiform.com/ja/guides/lead-capture/leads-to-crm.md): 署名付きの Ikiform の Webhook を、HubSpot の連絡先 upsert や Pipedrive の人物とリードの呼び出しに変換し、配信がリトライされても連絡先が重複しないようにします。
- [相談申し込みフォーム](https://ikiform.com/ja/guides/lead-capture/consultation-request.md): 会計士、弁護士、コーチ、クリニック向けの相談申し込みフォームです。連絡方法と時間を尋ね、デリケートな詳細は電話のときに回します。
- [Next.js のリードフォーム](https://ikiform.com/ja/guides/lead-capture/nextjs.md): Next.js App Router のリードフォームです。サーバーアクションで Zod による検証を行い、ファーストタッチの UTM を Cookie に保持し、条件に合うリードをカレンダーに送ります。
