ニュースレター登録フォーム2 分で読めます
自作のニュースレターフォームの登録を MailerLite に送る
自作の登録フォームを MailerLite につなぎます。リレーが新しい読者をダブルオプトインのために未確認として追加し、購読者に二度確認を求めることはありません。
自作のフォームを Ikiform に送信し、Webhook を MailerLite の API を呼ぶリレーに向けます。リレーはまずアドレスを検索します。新しい読者は unconfirmed として作成され、API の設定がオンなら MailerLite がダブルオプトインのメールを送ります。既存の購読者には新しいグループが追加されるだけです。この検索があるからこそ、確認済みの購読者が再び確認を求められずに済みます。
MailerLite で異なる点
MailerLite の購読者作成のエンドポイントは upsert です。/api/subscribers への 1 回の POST で新しい購読者を作成するか既存の購読者を更新し、201 か 200 を返します。破壊的ではないので、省略したグループやフィールドは元のままです。落とし穴は status です。アカウント設定の Double opt-in for API and integrations がオンなら、MailerLite は API で追加された新しい購読者に確認メールを送ります。既存のアクティブな購読者や配信停止した購読者に送られるのは、呼び出しで status: "unconfirmed" を送ったときだけです。
MailerLite のヘルプによると、既存のアクティブな購読者や配信停止した購読者には、呼び出しに "status": "unconfirmed" が含まれない限り確認メールは送られません。つまり、常に unconfirmed を送るリレーでは、熱心な読者が再登録するたびに新たに確認を求めることになります。解決策は、送る内容を決める前にアドレスを検索することです。
- リレーが Ikiform の Webhook を検証します。
- MailerLite にメールアドレスで購読者を問い合わせます。
- 見つからない場合:ステータス unconfirmed と設置場所のグループで作成し、MailerLite が確認メールを送ります。
- 見つかり、アクティブか未確認の場合:ステータスなしでグループを追加するので、確認の状態は何も変わりません。
- 見つかり、配信停止済みの場合:何もしないので、登録が配信停止をひそかに取り消すことはありません。
MailerLite を設定する
- MailerLite で購読の設定を開き、Double opt-in for API and integrations をオンにします。確認メールはそこで編集します。MailerLite は API で追加されたすべての購読者に同じメールを送ります。
- 「Website footer」や「Blog posts」のように設置場所ごとにグループを作り、各グループの id を控えておきます。
- Integrations で API トークンを作成し、リレーの環境変数用に保管しておきます。
リレー
これは Express のサーバーです。署名は Ikiform が送ったバイト列そのものが対象で、先に JSON を解析すると変わってしまうので、生のボディをテキストとして読みます。
import express from "express";
import { verifyWebhook, WebhookVerificationError } from "@ikiform/sdk/webhooks";
const API = "https://connect.mailerlite.com/api";
const GROUPS: Record<string, string> = {
footer: process.env.MAILERLITE_GROUP_FOOTER!,
post: process.env.MAILERLITE_GROUP_POST!,
};
function mailerlite(path: string, init: RequestInit = {}) {
return fetch(`${API}${path}`, {
...init,
headers: {
Authorization: `Bearer ${process.env.MAILERLITE_API_KEY}`,
"Content-Type": "application/json",
Accept: "application/json",
},
});
}
async function subscribe(email: string, name: string | undefined, source: string) {
const found = await mailerlite(`/subscribers/${encodeURIComponent(email)}`);
if (found.status !== 200 && found.status !== 404) return found;
const groups = [GROUPS[source] ?? process.env.MAILERLITE_GROUP_FOOTER!];
const fields = name ? { name } : {};
if (found.status === 404) {
return mailerlite("/subscribers", {
method: "POST",
body: JSON.stringify({ email, fields, groups, status: "unconfirmed" }),
});
}
const existing = await found.json();
if (existing.data.status === "unsubscribed") return new Response(null, { status: 208 });
return mailerlite("/subscribers", { method: "POST", body: JSON.stringify({ email, fields, groups }) });
}
const app = express();
app.post("/hooks/mailerlite", express.text({ type: "application/json", limit: "512kb" }), async (req, res) => {
let event;
try {
event = await verifyWebhook({ payload: req.body, headers: req.headers, secret: process.env.IKIFORM_WEBHOOK_SECRET! });
} catch (error) {
if (error instanceof WebhookVerificationError) return res.status(400).send(error.reason);
return res.status(500).end();
}
if (event.type !== "submission.created") return res.status(204).end();
const { email, first_name, consent, source } = event.data.fields;
if (consent !== true || typeof email !== "string") return res.status(200).send("Skipped");
const answer = await subscribe(
email,
typeof first_name === "string" ? first_name : undefined,
typeof source === "string" ? source : "footer",
);
if (answer.status === 208) return res.status(200).send("Unsubscribed earlier, left alone");
if (answer.status === 429) {
return res.status(503).set("retry-after", answer.headers.get("retry-after") ?? "60").send("MailerLite rate limit");
}
if (!answer.ok) return res.status(502).send(`MailerLite answered ${answer.status}: ${await answer.text()}`);
res.status(204).end();
});
app.listen(Number(process.env.PORT ?? 3000));- MailerLite はトークンを
Authorization: Bearerで受け取ります。ベース URL はhttps://connect.mailerlite.com/apiです。 GET /api/subscribers/{email}はメールアドレスか id を受け付け、購読者が存在しなければ404を返します。groupsには既存のグループの id を指定します。間違った id は422で拒否され、リレーはそれを MailerLite のメッセージ付きの502として返します。fields.nameは MailerLite のデフォルトの名のフィールドです。カスタムフィールドは、送る前に MailerLite に存在している必要があります。208は配信停止済みの読者を表す内部用の目印です。Ikiform には200と、配信ログのメモとして見えます。
ポート 443 の公開 HTTPS の URL が得られる場所ならどこにでもデプロイし、その URL を Ikiform の Webhooks に追加して、whsec_ のシークレットを IKIFORM_WEBHOOK_SECRET に入れます。リトライとペイロードについては Webhook のドキュメントに、データベースを使った同じ Express の構成は自前のサーバーにあります。
同意の記録はどこに残るか
MailerLite の作成の呼び出しは subscribed_at、ip_address、opted_in_at、optin_ip を受け付けます。IP のフィールドは省いてください。Ikiform の Webhook には訪問者の IP アドレスもそのハッシュも含まれないので、リレーには送るべき正しい値がなく、でっち上げた値はないよりも悪いからです。
登録の記録は Ikiform に残ります。送信データには consent: true が、タイムスタンプ、オリジン、リファラー、国と一緒に保存されます。確認の記録は MailerLite にあり、読者がリンクをクリックした日時が記録されます。この 2 つで、いつチェックボックスにチェックが入り、いつ本人のアドレスであることが確かめられたかを示せます。必要なときは Submissions から Ikiform 側を CSV でエクスポートしてください。
レート制限
MailerLite の API 全体の上限は 1 分あたり 120 リクエストです。リレーは 1 件の登録につき 2 回呼び出すので、1 分あたり約 60 件の登録が収まります。それを超えると MailerLite は 429 を返し、リレーは Retry-After 付きの 503 を返し、Ikiform は同じ配信をあとでリトライします。
| MailerLite の応答 | リレーの応答 | Ikiform |
|---|---|---|
201 または 200 | 204 | 配信成功 |
429 | Retry-After 付きの 503 | 待ってからリトライ |
401 | 502 | リトライ。トークンを直してから、失敗した配信で Retry now を使う |
422 | エラー付きの 502 | リトライ。たいていはグループの id かフィールド名の間違い |
ハマりどころ
status: "active"は送らない。 その人を購読済みとして扱いますが、それでも確認メールが送られるかどうかは MailerLite のドキュメントに書かれていません。送るステータスでテストしてください。- 再購読は選択の問題。 MailerLite には、配信停止した人向けの
resubscribeフラグがあります。フォームでそう明記し、読者が再び購読することをわかっている場合にだけ送ってください。 - 設定のオン・オフが重要。 MailerLite が API での登録に確認メールを送るのは、Double opt-in for API and integrations がオンのときだけです。
- 確認メールは 1 つ。 API のダブルオプトインのメールは、API でのすべての登録で共通です。設置場所ごとに文面を変えたいなら、MailerLite のフォームを分けて使ってください。
- Ikiform での重複。 Ikiform は受け付けたすべての送信を保持し、MailerLite はメールアドレスごとに 1 人の購読者を保持します。購読者数は Ikiform のダッシュボードではなく MailerLite で数えてください。
動作を確認する
- Ikiform でエンドポイントからテストを送ります。配信には
204が表示されます。 - 自分の新しいアドレスで購読します。MailerLite ではフッターのグループに未確認の購読者として表示され、確認メールが届きます。
- 確認してから、ブログ記事からもう一度購読します。購読者はアクティブのままで 2 つ目のグループに加わり、新しい確認メールは届きません。
- MailerLite でそのアドレスを配信停止にし、もう一度購読します。配信ログに配信停止のメモが表示され、MailerLite では配信停止のままです。
よくある質問
はい。フォームを Ikiform に送信し、リレーに MailerLite の API で各登録を正しいグループ付きで追加させます。フォームは自分のマークアップのまま、ニュースレターは引き続き MailerLite が送ります。
MailerLite の購読の設定で Double opt-in for API and integrations がオフになっているか、リレーが購読者を active として作成しています。設定をオンのままにし、ステータス unconfirmed を送り、自分のアドレスでテストしてください。
このリレーでは届きません。先にアドレスを検索し、unconfirmed を送るのは新しい購読者の場合だけです。既存の購読者は新しいグループに追加されるだけで、ほかには何も変わりません。
フォームの非表示の source 入力欄に設置場所ごとに違う値を入れ、リレーで各値を MailerLite のグループ id に対応付けます。2 つ目の設置場所から登録した既存の購読者は、そのグループにも加わり、最初のグループもそのまま残ります。
いいえ。Ikiform はフォームを送信した人に一切メールを送りません。確認メール、毎号のニュースレター、配信停止のリンクは MailerLite が送ります。
手順で詰まったときや、あなたの状況に合うガイドがほしいときはメールでどうぞ: hello@ikiform.com