# 自作のニュースレターフォームでダブルオプトインを行う

> Ikiform は確認メールを送らないので、ダブルオプトインはメールツールで行います。中継が各登録を未確認として追加し、ツールがリンクを送ります。

公開日 2026-10-25 · https://ikiform.com/ja/guides/newsletter-signup/double-opt-in

Ikiform は登録した本人にメールを送らないので、確認メールはニュースレターを配信するツールから送る必要があります。中継が Ikiform の署名付き Webhook を受け取り、読者を未確認としてそのツールに追加し、ツールが本人にリンクをメールで送り、クリックして初めて購読者になります。この機能をオンにする方法はツールごとに異なり、中継はすでに購読している人に 2 通目の確認メールを送ってはいけません。

## ここが違う

Ikiform はフォームを入力した本人にはメールを送りません。通知メールが届くのはあなたとチームだけなので、自動返信、確認メール、ダブルオプトインはありません。それらは [Webhook](https://ikiform.com/ja/docs/webhooks.md) をきっかけに、自分のメールツールから送ってください。プロバイダーの埋め込みなら、確認はプロバイダーのフォームの設定項目です。自分のフォームでは 2 つのシステムが関わり、確認はリストを管理する側の役目です。大事なのは、各登録が確認メールを送らせる状態でそのツールに届き、送るべきでないときには送らせないようにすることです。

ダブルオプトインはメールツール内の状態遷移です。読者は未確認の状態で始まり、配信は受け取れず、クリックして初めて購読者になります。Ikiform の役目は、中継が `204` を返した時点で終わります。

図: ダブルオプトインの登録の流れ、フォームから確認済みの購読者まで

1. 読者が同意のチェックボックスにチェックを入れてフォームを送信し、フォームは Ikiform に送信します。
2. Ikiform は登録を保存し、署名付きの Webhook を中継に送ります。
3. 中継は署名を検証し、読者を未確認としてメールツールに追加します。
4. メールツールが読者に確認リンクをメールで送ります。
5. クリックすると、ツールが確認済みにして、以降すべての号を送ります。
6. クリックしなければ未確認のままで、ニュースレターは届きません。

確認メールの文面、リンクで開くページ、リマインダーなど、中継以降のことはすべてメールツールで行われます。

## 各ツールでの設定

どのツールにも独自の「未確認」の概念があり、API で追加した新しい購読者をその状態にする方法もそれぞれ異なります。ここを間違えると、購読者がメールなしで最初から確認済みとして追加されます:

| ツール | API での登録に確認メールを送る方法 | 落とし穴 |
| --- | --- | --- |
| [Kit](https://ikiform.com/ja/guides/newsletter-signup/kit.md) | `state: "inactive"` で購読者を作成してから、インセンティブメールがオンのフォームに追加します。Kit の一括フォームのドキュメントでは、これでインセンティブメールが送られるとされています。単体のエンドポイントは自分のアドレスでテストしてください | 購読者の作成はデフォルトで `state: "active"` になり、そのエンドポイントではあとから状態を変えられません |
| [MailerLite](https://ikiform.com/ja/guides/newsletter-signup/mailerlite.md) | 購読設定で **Double opt-in for API and integrations** をオンにします。あわせて `status: "unconfirmed"` も送ってください。MailerLite が既存の購読者にメールを送るにはこれが必要です | すでにアクティブなアドレスに `unconfirmed` を送ると、もう一度確認を求めることになります |
| [beehiiv](https://ikiform.com/ja/guides/newsletter-signup/beehiiv.md) | 購読の作成で `double_opt_override: "on"` を送るか、パブリケーション自体の設定を使うなら `"not_set"` を送ります | `"off"` にすると、メールなしで購読者がすぐにアクティブになります |

頼る前に、それぞれ自分のアドレスでテストしてください。ツールの設定は変わりますし、件名、文面、リンクで開くページなど、メール自体の設定はツール側で行います。

## 確認を 1 回だけ求める中継

素朴な中継は、Webhook が届くたびに確認を求めます。それがまずいケースは 2 つあります。1 分間に 3 回送信した読者には 3 通のメールが届き、他人のアドレスを登録するボットは、試すたびにその被害者の受信箱に確認メールを届けてしまいます。この Cloudflare Worker は、アドレスごとに 1 日 1 回まで確認をツールに依頼します:

`src/index.ts`:

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

export interface Env {
  IKIFORM_WEBHOOK_SECRET: string;
  TOOL_API_KEY: string;
  SEEN: KVNamespace;
}

const DAY = 86_400;

async function digest(text: string) {
  const bytes = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(text));
  return [...new Uint8Array(bytes)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
}

export default {
  async fetch(request: Request, env: Env) {
    if (request.method !== "POST") return new Response(null, { status: 405 });
    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" || event.data.fields.consent !== true) {
      return new Response(null, { status: 204 });
    }

    const email = String(event.data.fields.email).trim().toLowerCase();
    const key = `confirm:${await digest(email)}`;
    if (await env.SEEN.get(key)) return new Response("Confirmation already requested today", { status: 200 });

    const answer = await addUnconfirmed(env, email, event.data.fields.first_name);
    if (answer.status === 429) {
      return new Response("Rate limited", { status: 503, headers: { "retry-after": answer.headers.get("retry-after") ?? "60" } });
    }
    if (!answer.ok) return new Response(`Email tool answered ${answer.status}`, { status: 502 });

    await env.SEEN.put(key, event.id, { expirationTtl: DAY });
    return new Response(null, { status: 204 });
  },
};
```

`wrangler.jsonc`:

```json
{
  "$schema": "node_modules/wrangler/config-schema.json",
  "name": "newsletter-relay",
  "main": "src/index.ts",
  "compatibility_date": "2026-10-01",
  "routes": [{ "pattern": "hooks.example.com", "custom_domain": true }],
  "kv_namespaces": [{ "binding": "SEEN", "id": "<your KV namespace id>" }]
}
```

- `./tool` の `addUnconfirmed` は、上の表にあるツールの呼び出しです。本体は Kit、MailerLite、beehiiv のページからコピーしてください。
- KV のキーは小文字にしたアドレスの SHA-256 なので、ストアにアドレスそのものは保存されません。1 日で期限切れになります。
- キーはツールがリクエストを受け付けたあとにだけ書き込まれます。ツールが失敗すれば Ikiform がリトライし、そのリトライはブロックされません。
- 繰り返しに `200` を返すと、Ikiform は配信が成功したと判断してリトライしません。理由はボディで配信ログに残ります。
- Worker はカスタムドメインで動かします。Ikiform は `workers.dev` のホスト名を Webhook の URL として受け付けません。URL のルールとそれぞれの応答の意味は [Webhook のドキュメント](https://ikiform.com/ja/docs/webhooks.md)にすべてあり、各配信を 1 回だけ保存する中継は[自分のサーバー](https://ikiform.com/blog/form-submissions-to-your-own-server.md)で紹介しています。

> KV は拠点間で結果整合性なので、同じアドレスへの配信が数秒以内に 2 件あると、どちらも通ることがあります。確認メールならそれで問題ありません。厳密な保証が必要なら、キーを Durable Object か一意な列を持つデータベースに保存してください。

## フォームに書くべきこと

「ご登録ありがとうございます」と表示されたのにニュースレターのフォルダーに何もなければ、読者は失敗したと思います。移動先のページで、この後どうなるかを伝えてください:

1. 成功時の一文かサンクスページで、開くべきメールがあることを伝えます:「あと少しです。お送りしたメールを開いて、アドレスを確認してください。」
2. 探すべき送信者名を伝え、数分たっても届かなければ迷惑メールフォルダーを見るよう案内します。
3. メールツールで、確認リンクで開くページを自分の「登録が完了しました」ページに設定すれば、流れが自分のサイトで終わります。

フォームの同意チェックボックスと確認メールは役割が違います。チェックボックスは、あなたのページで誰かが同意したことを記録します。クリックは、そのアドレスが同意した本人のものであることを証明します。ほとんどのリストでは両方が必要です。[ニュースレターのフォームテンプレート](https://ikiform.com/forms/newsletter-signup)には必須のチェックボックスがあります。

## ハマりどころ

- **既存の購読者。** すでに確認済みの人が、別のページからもう一度登録します。未確認に戻さないでください。先にアドレスを照会する中継は [MailerLite のページ](https://ikiform.com/ja/guides/newsletter-signup/mailerlite.md)で紹介しています。
- **配信を停止した人。** 登録が、配信停止を取り消してよいという許可になるとは限りません。beehiiv は `reactivate_existing: true` を送ったときだけ再有効化し、MailerLite は `resubscribe: true` のときだけ再購読させます。フォームでそう明記しているときだけ送ってください。
- **リンクスキャナー。** 企業のメールフィルターの中には、受信メールのリンクを開いて確認するものがあります。ページを開いただけで確認するツールだと、誰もクリックしていないアドレスをスキャナーが確認してしまいます。ツールの確認ページでボタンを押させるかどうかを確認してください。
- **到達率。** 確認メールは、読者があなたから受け取る最初のメールです。ツールで認証済みのドメインから送らないと迷惑メールに入り、登録が完了しません。
- **未確認の人がたまっていきます。** まだ購読者ではありません。リマインダーを送るかどうかをツールで決め、あとはそっとしておきましょう。

## 動作を確認する

1. 自分のアドレスでフォームを送信します。ページに受信トレイを確認するよう表示されます。
2. Ikiform の **Webhooks** で配信を開きます。`succeeded` と、リレーの `204` が表示されます。
3. メールツールで購読者を開きます。ツールによって、未確認、非アクティブ、保留中のいずれかになっています。
4. 確認メールを開いてクリックします。購読者がアクティブまたは確認済みになります。
5. 1 日以内に同じアドレスでもう一度送信します。配信には「Confirmation already requested today」と共に `200` が表示され、2 通目のメールは届きません。
6. すでに確認済みのアドレスで登録します。確認済みのまま変わらず、新しい確認メールも届きません。

## よくある質問

### Ikiform はダブルオプトインの確認メールを送れますか？

いいえ。Ikiform はフォームを送信した本人にメールを送りません。確認メールはメールツールが送り、そのきっかけは Ikiform の Webhook からリレーや自動化ツールを経由して届きます。

### ダブルオプトインを使っても、同意のチェックボックスは必要ですか？

両者の役割は異なります。チェックボックスは、本人がページ上で同意したことをタイムスタンプ付きで記録します。確認のクリックは、本人がそのアドレスの持ち主であることを証明します。ほとんどのリストでは両方を残しています。

### 購読者に確認メールが届かなかったのはなぜですか？

おそらくリレーが購読者を確認済みとして作成しています。Kit の購読者作成はデフォルトで active になり、MailerLite では API のダブルオプトイン設定をオンにし、既存の購読者には unconfirmed のステータスを指定する必要があり、beehiiv では double_opt_override を off にするとメールが省略されます。ツールで購読者の状態を確認してください。

### リレーの代わりに Zapier や Make を使えますか？

はい。Ikiform の Webhook を自動化ツールに向け、メールツール用のアクションを使ってください。アクションのオプションで購読者が未確認の状態で作成されることを確認しましょう。フィルターのステップを追加しない限り、1 日 1 回のガードはなくなります。

## その他のガイド

- [ニュースレター登録フォーム](https://ikiform.com/ja/guides/newsletter-signup.md): 自分のマークアップでニュースレター登録フォームを作り、同意を記録し、ボットの登録を防ぎ、購読者を Kit、MailerLite、beehiiv など任意のツールに渡します。
- [Kit (ConvertKit)](https://ikiform.com/ja/guides/newsletter-signup/kit.md): 購読者を作成し、特典メールのために Kit のフォームに追加し、設置場所のタグを付けるリレーで、自作のニュースレターフォームを Kit につなぎます。
- [MailerLite](https://ikiform.com/ja/guides/newsletter-signup/mailerlite.md): 自作の登録フォームを MailerLite につなぎます。リレーが新しい読者をダブルオプトインのために未確認として追加し、購読者に二度確認を求めることはありません。
- [beehiiv](https://ikiform.com/ja/guides/newsletter-signup/beehiiv.md): 自作の登録フォームを beehiiv につなぎます。リレーがダブルオプトインをオンにし、設置場所を UTM ソースに、ページをリファラーにして各購読を作成します。
- [静的サイト](https://ikiform.com/ja/guides/newsletter-signup/static-site.md): Hugo、Jekyll、Eleventy、Astro の静的サイトにニュースレター登録フォームを追加し、メールツールの API キーをページに入れず、確認はツールで行います。
- [Next.js のニュースレターフォーム](https://ikiform.com/ja/guides/newsletter-signup/nextjs.md): Next.js のフッターのニュースレターフォームです。同意のチェックと Turnstile を行うサーバーアクションが Ikiform に送信し、ルートハンドラーが読者を Kit に追加します。
