フォームをメールに送る1 分で読めます
キーをクライアントに置かない EmailJS の代替
お問い合わせフォームを EmailJS から移行。ブラウザー側のメールキーのリスク、コードの変更点、自動返信など失うものを解説します。
EmailJS はブラウザーからメールを送るので、サービス ID、テンプレート ID、公開キーがページの JavaScript に含まれ、誰でもコピーできます。フォームバックエンドならブラウザーにキーは要りません。フォームは URL に送信し、バックエンドがスパムを除外し、メッセージを保存し、あなたにメールで通知します。EmailJS の訪問者への自動返信はなくなるので、代わりに自分のメールツールから送ります。
ここが違う
EmailJS が人気なのには理由があります。サーバーなしで、静的サイトから本物のメールを送れるからです。そのためにブラウザーは、サービス ID、テンプレート ID、公開キーの 3 つの値で EmailJS を直接呼び出します。これらはバンドルに含まれ、ページのソースやネットワークタブで読めます。
EmailJS 自身の FAQ には、これらをコピーした人が送れるのはあなたのテンプレートとその内容だけで、任意のメールは送れないとあります。テンプレートの固定の文面についてはそのとおりです。しかしテンプレートの変数は呼び出し側が埋めるので、コピーしたキーを使えば、任意の名前、メッセージ、リンクを入れたテンプレートを、クォータの許す限り何度でも送れます。さらに、訪問者のアドレス宛の自動返信のようにテンプレートの To が変数なら、呼び出し側が受信者まで選べます。
- ブラウザーのメール SDK では、送信に必要なものがすべてページにあります。どこか別のスクリプトが ID とキーをコピーし、独自の文面であなたのテンプレートをクォータまで送れます。
- テンプレートの受信者が変数で決まるなら、コピーしたキーで受信者も選べます。
- フォームのエンドポイントでは、ページにあるのはフォーム ID だけです。送信はスパムを除外され、レート制限され、メールはダッシュボードで設定した受信者にしか届きません。
EmailJS には、キーを使えるドメインの制限やテンプレートへの CAPTCHA の追加など、これを絞り込む設定があります。使い続けるなら、プランに含まれているものを確認してオンにしてください。以下の比較は設計についてのもので、サービスの良し悪しの判定ではありません:
| Item | EmailJS | Ikiform |
|---|---|---|
| ブラウザーが持つもの | サービス ID、テンプレート ID、公開キー | フォーム ID |
| 受信者を決めるもの | テンプレート(変数を読むこともある) | ダッシュボードの設定だけ |
| スパムの除外 | 追加すればテンプレートごとに CAPTCHA | すべてのフォームにハニーポット、スパムスコア、レート制限。人間確認も任意で追加可能 |
| 送信後のメッセージ | 受信トレイの中 | 受信トレイに加え、ダッシュボード、CSV エクスポート、API |
| 訪問者へのメール | あり。自動返信テンプレートで | いいえ |
| 独自のメールデザイン | あり。エディターでテンプレートを作成 | なし。件名 New submission: <form name> の固定レイアウト |
自動返信やブランドに合わせたメールが目的なら、EmailJS か、メール API を使う自前のサーバーのほうが向いています。メッセージを安全に受信トレイへ届け、どこかに残しておきたいなら、フォームバックエンドが向いています。
フォームを移行する
EmailJS のお問い合わせフォームのチュートリアルをもとにした、React の典型的な EmailJS フォーム:
import emailjs from "@emailjs/browser";
import { type FormEvent, useRef, useState } from "react";
export function ContactForm() {
const form = useRef<HTMLFormElement>(null);
const [status, setStatus] = useState("");
async function onSubmit(event: FormEvent<HTMLFormElement>) {
event.preventDefault();
if (!form.current) return;
try {
await emailjs.sendForm("service_abc123", "template_xyz789", form.current, {
publicKey: "aBcDeFgHiJkLmNoPq",
});
setStatus("Message sent.");
} catch {
setStatus("Couldn't send your message.");
}
}
return (
<form ref={form} onSubmit={onSubmit}>
<input name="user_name" required />
<input name="user_email" type="email" required />
<textarea name="message" required />
<button>Send</button>
<p role="status">{status}</p>
</form>
);
}同じフォームを @ikiform/sdk の submit() で Ikiform に送信する版:
import { submit } from "@ikiform/sdk";
import { type FormEvent, useState } from "react";
const FORM_ID = "frm_xxxxxxxxxxxxxxxx";
export function ContactForm() {
const [status, setStatus] = useState<"idle" | "sending" | "sent">("idle");
const [fields, setFields] = useState<Record<string, string[]>>({});
const [error, setError] = useState("");
async function onSubmit(event: FormEvent<HTMLFormElement>) {
event.preventDefault();
setStatus("sending");
setFields({});
setError("");
const result = await submit(FORM_ID, new FormData(event.currentTarget));
if (result.ok) {
setStatus("sent");
return;
}
setFields(result.error.fields ?? {});
setError(result.error.code === "network_error" ? "You're offline. Try again." : result.error.message);
setStatus("idle");
}
if (status === "sent") return <p role="status">Message sent. We'll reply by email.</p>;
return (
<form onSubmit={onSubmit}>
<label htmlFor="user_name">Name</label>
<input id="user_name" name="user_name" required />
<label htmlFor="email">Email</label>
<input id="email" name="email" type="email" required />
{fields.email ? <p role="alert">{fields.email[0]}</p> : null}
<label htmlFor="message">Message</label>
<textarea id="message" name="message" required />
{fields.message ? <p role="alert">{fields.message[0]}</p> : null}
<input name="_gotcha" type="text" tabIndex={-1} autoComplete="off" hidden />
{error && !Object.keys(fields).length ? <p role="alert">{error}</p> : null}
<button disabled={status === "sending"}>{status === "sending" ? "Sending" : "Send"}</button>
</form>
);
}@emailjs/browserと 3 つの ID は不要になります。パッケージをアンインストールし、新しいフォームが動いたら EmailJS のテンプレートかサービスを削除して、キャッシュされた古いページから送信されないようにします。user_emailはemailになります。EmailJS は名前を気にしませんが、Ikiform はemailという名前のフィールドを返信先に使います。通知は届いた順にフィールドを並べるので、他の名前はそのままで構いません。submit()は例外を投げません。エラーのエンベロープを返すので、フォームの定義によるフィールドエラーがそれぞれの入力欄の下に表示されます。- ハニーポットは新しく加わったものです。EmailJS にはありませんでした。この hidden の入力欄は、設定なしで単純なボットを捕まえます。
- Allowed domains に自分のドメインを追加して、他のサイトからの送信がスパムとして扱われるようにします。
submit の前に challenge(FORM_ID) を呼んで、トークンを turnstileToken として渡します。React ガイドに例があります。自動返信を使っていた場合
Ikiform はフォームを入力した本人にはメールを送りません。通知メールが届くのはあなたとチームだけなので、自動返信、確認メール、ダブルオプトインはありません。それらは Webhook をきっかけに、自分のメールツールから送ってください。Resend や Postmark など、サーバーから操作する送信サービスなら、submission.created の Webhook ごとに、ブラウザーではなく信頼できるペイロードにある訪問者のアドレス宛に送れます。複数の受信者のガイドに、応用できるハンドラーがあります。
本当に必要か考えてみてください。お問い合わせフォームなら、ページに表示するお礼のメッセージで送信できたことは伝わりますし、1 時間後のあなたからの本物の返信はテンプレートに勝ります。
動作を確認する
- フォームの Allowed domains に自分のサイトのドメインと、開発中は
localhostを追加します。空にしておくと、どこからの送信でも受け付けます。 - ビルドしたサイトで
emailjsと古いサービス ID を検索します。何も一致しないはずです。 - ページのフォームに入力して送信します。自分のサンクスページか、Ikiform のサンクスページに移動します。
- 通知の各受信者の受信トレイを確認します。それぞれにフィールド入りのメールが届き、フォームに
emailフィールドがあれば Reply は送信者宛になります。 - ハニーポットを埋めて
_gotcha=botで送信します。成功の応答は返りますが、送信データはスパムとして保存され、メールも Webhook も送られません。
うまくいかないとき
| 問題 | 対処法 |
|---|---|
| 返信がまだ Ikiform 宛になる | フィールドがまだ user_email のままです。email、または email、email_address、your_email、reply_to、contact_email のどれかに名前を変えてください。 |
422 validation_failed | 送信がフォームのフィールド定義に合っていません。error.fields に各フィールドと理由が示されます。入力欄の name をフィールド ID に合わせてください。 |
403 challenge_required | フォームのスパムチェックが Ikiform に設定されていて、fetch の送信にトークンがありませんでした。送信のたびに @ikiform/sdk の challenge(formId) でトークンを取得するか、チェックをオフにしてください。 |
403 origin_not_allowed が返るか、すべての送信がスパムになる | ページのドメインがフォームの Allowed domains にありません。追加し、ローカルでのテスト用に localhost も追加してください。登録したドメインのサブドメインは許可されます。 |
よくある質問
量とプランによりますし、どちらも変わっていくので、最新の料金ページを比較してください。Ikiform に無料プランはなく、Pro か 1 回払いのパックで送信件数ごとに課金されます。
EmailJS によれば、コピーされたキーで送れるのはあなたのテンプレートだけで、独自のメールは送れません。ただし、テンプレートの変数は呼び出し側が埋め、受信者が変数ならそれも選べます。使い続けるなら、キーを自分のドメインに限定し、CAPTCHA を追加してください。
いいえ。ブラウザーのフォームは、キーなしでフォームの URL に送信します。シークレットキーは自分のサーバーから送信するためだけのもので、サーバー側の環境変数に置きます。
いいえ。Ikiform がメールを送るのはあなたとチームで、送信者には送らないので、自動返信や確認メールはありません。Webhook でメールツールに送り、そこから確認メールを送ってください。
はい。ただしメールのフィールドは別で、通知への返信が訪問者に届くよう email という名前にしてください。Ikiform は送信されたどんなフィールド名でも保存します。
手順で詰まったときや、あなたの状況に合うガイドがほしいときはメールでどうぞ: hello@ikiform.com