Kirim formulir ke email Anda5 menit baca
Alternatif EmailJS yang menjauhkan key dari client
Pindahkan formulir kontak dari EmailJS: mengapa key email di sisi browser berisiko, apa yang berubah di kode Anda, dan apa yang Anda lepaskan, seperti balasan otomatis.
EmailJS mengirim email dari browser, jadi service id, template id, dan public key Anda ikut terkirim di JavaScript halaman untuk disalin siapa saja. Form backend tidak butuh key di browser: formulir mengirim ke sebuah URL, lalu backend menyaring spam, menyimpan pesan, dan mengirimi Anda email. Anda kehilangan balasan otomatis EmailJS ke pengunjung, yang bisa Anda kirim dari alat email Anda sendiri.
Apa yang berbeda di sini
EmailJS populer karena alasan yang bagus: ia mengirim email sungguhan dari situs statis tanpa server. Untuk itu, browser memanggil EmailJS langsung dengan tiga nilai: service id, template id, dan public key. Ketiganya ada di bundle Anda, bisa dibaca di source halaman atau tab network.
FAQ EmailJS sendiri menyatakan bahwa orang yang menyalinnya hanya bisa mengirim template Anda dengan konten Anda, bukan email sembarangan. Itu benar untuk teks tetap di template. Tetapi pemanggil yang mengisi variabel template, jadi key yang disalin bisa mengirim template Anda dengan nama, pesan, dan link apa pun, sesering yang diizinkan kuota Anda. Dan jika To pada template berupa variabel, seperti pada balasan otomatis ke alamat pengunjung, pemanggil juga yang memilih penerimanya.
- Dengan SDK email di browser, halaman memegang semua yang dibutuhkan untuk mengirim. Skrip di tempat lain bisa menyalin ID dan key lalu mengirim template Anda dengan teksnya sendiri, hingga batas kuota Anda.
- Jika penerima template berasal dari variabel, key yang disalin juga menentukan siapa yang menerimanya.
- Dengan endpoint formulir, halaman hanya memegang ID formulir. Kiriman disaring dari spam dan dibatasi rate limit, dan email hanya dikirim ke penerima yang Anda atur di dashboard.
EmailJS punya pengaturan yang mempersempit ini, seperti membatasi domain mana yang boleh memakai key Anda dan menambahkan captcha ke template. Cek mana yang termasuk dalam paket Anda dan nyalakan jika Anda tetap memakainya. Perbandingan di bawah ini soal desain, bukan vonis atas layanannya:
| Item | EmailJS | Ikiform |
|---|---|---|
| Yang dipegang browser | Service id, template id, dan public key | ID formulir |
| Siapa yang menentukan penerima | Template, yang bisa membaca variabel | Hanya pengaturan dashboard Anda |
| Penyaringan spam | Captcha per template, jika Anda menambahkannya | Honeypot, skor spam, dan rate limit di setiap formulir, ditambah pemeriksaan manusia opsional |
| Pesan Anda setelahnya | Di inbox Anda | Di dashboard, ekspor CSV, dan API, selain di inbox Anda |
| Email ke pengunjung | Ya, dengan template balasan otomatis | Tidak |
| Desain email Anda sendiri | Ya, template di editor mereka | Tidak, tata letak tetap dengan subjek New submission: <form name> |
Jika balasan otomatis atau email bermerek adalah tujuannya, EmailJS, atau server Anda sendiri dengan API email, lebih cocok. Jika Anda ingin pesan masuk ke inbox dengan aman dan tersimpan di suatu tempat, form backend lebih cocok.
Pindahkan formulirnya
Formulir EmailJS yang umum di React, berdasarkan tutorial formulir kontak mereka:
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>
);
}Formulir yang sama yang mengirim ke Ikiform dengan submit() dari @ikiform/sdk:
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/browserdan ketiga ID dihapus. Uninstall package-nya, dan hapus template atau service EmailJS setelah formulir baru berfungsi, agar salinan halaman yang ter-cache berhenti mengirim.user_emailmenjadiemail. EmailJS tidak peduli pada nama, tetapi Ikiform memakai field bernamaemailsebagai reply-to. Nama lain boleh tetap, karena notifikasi mencantumkan field sesuai urutan datangnya.submit()tidak pernah melempar error. Fungsi ini mengembalikan envelope error, sehingga error field dari definisi formulir tampil di bawah input-nya.- Honeypot-nya baru. EmailJS tidak punya; input tersembunyi ini menangkap bot paling sederhana tanpa setup.
- Tambahkan domain Anda di Allowed domains, agar kiriman dari situs lain ditandai sebagai spam.
challenge(FORM_ID) sebelum submit dan teruskan token-nya sebagai turnstileToken. Panduan React menunjukkan caranya.Jika Anda memakai balasan otomatis
Ikiform tidak mengirim email ke orang yang mengisi formulir. Email notifikasi hanya dikirim ke Anda dan tim, jadi tidak ada autoresponder, email konfirmasi, atau double opt-in. Kirim semua itu dari alat email Anda, dipicu oleh webhook. Layanan pengiriman yang Anda kendalikan dari server, seperti Resend atau Postmark, bisa mengirimnya di setiap webhook submission.created, dengan alamat pengunjung dari payload tepercaya, bukan dari browser. Panduan beberapa penerima punya handler yang bisa Anda sesuaikan.
Tanyakan apakah Anda membutuhkannya. Pesan terima kasih di halaman formulir kontak sudah memberi tahu pengunjung bahwa kirimannya berhasil, dan balasan sungguhan dari Anda sejam kemudian lebih baik daripada template.
Pastikan berfungsi
- Di Allowed domains formulir, tambahkan domain situs Anda, ditambah
localhostselama pengembangan. Biarkan kosong untuk menerima kiriman dari mana saja. - Cari
emailjsdan service id lama Anda di situs hasil build. Tidak boleh ada yang cocok. - Isi formulir di halaman Anda lalu kirim. Anda mendarat di halaman terima kasih Anda, atau halaman hosted milik Ikiform.
- Cek inbox setiap penerima notifikasi. Masing-masing mendapat email berisi field, dan Reply terkirim ke pengirim formulir jika formulir punya field
email. - Kirim dengan honeypot terisi,
_gotcha=bot. Kiriman tetap mendapat jawaban sukses, tetapi disimpan sebagai spam dan tidak memicu email atau webhook.
Jika ada yang salah
| Masalah | Yang harus dilakukan |
|---|---|
| Reply masih terkirim ke Ikiform | Field-nya masih user_email. Ganti namanya menjadi email, atau salah satu dari email, email_address, your_email, reply_to, contact_email. |
422 validation_failed | Kiriman tidak cocok dengan definisi field formulir. error.fields menyebutkan setiap field dan alasannya. Samakan name input dengan ID field. |
403 challenge_required | Spam check formulir diatur ke Ikiform dan kiriman fetch tidak membawa token. Ambil token dengan challenge(formId) dari @ikiform/sdk sebelum setiap pengiriman, atau matikan pemeriksaannya. |
403 origin_not_allowed, atau setiap kiriman masuk ke spam | Domain halaman tidak ada di Allowed domains formulir. Tambahkan, ditambah localhost untuk uji lokal. Subdomain dari domain yang terdaftar diizinkan. |
Pertanyaan
Tergantung volume dan paket, dan keduanya berubah dari waktu ke waktu, jadi bandingkan halaman harga terbaru. Ikiform tidak punya paket gratis; tagihannya per kiriman, dengan Pro atau paket sekali bayar.
EmailJS menyatakan key yang disalin hanya bisa mengirim template Anda, bukan email kustom. Namun pemanggil tetap mengisi variabel template, dan jika penerimanya berupa variabel, mereka juga yang memilihnya. Batasi key ke domain Anda dan tambahkan captcha jika Anda tetap memakainya.
Tidak. Formulir di browser mengirim ke URL formulir Anda tanpa key. Secret key hanya ada untuk mengirim dari server Anda sendiri, dan tempatnya di environment variable sisi server.
Tidak. Ikiform mengirim email ke Anda dan tim, bukan ke pengirim formulir, jadi tidak ada autoresponder atau email konfirmasi. Kirim webhook ke alat email Anda dan kirim konfirmasinya dari sana.
Bisa, kecuali field email: beri nama email agar balasan notifikasi terkirim ke pengunjung. Ikiform menyimpan nama field apa pun yang Anda kirim.
Mentok di salah satu langkah, atau ingin panduan untuk situasi Anda? Email hello@ikiform.com.