Kirim formulir ke email Anda

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.

Preet SutharPendiri, Ikiform

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.

Siapa yang bisa mengirim lewat key email di browser, dan lewat endpoint formulirsdk email di browserendpoint formulirhalaman Andaservice, template,public keyskrip siapasajamenyalin ketiganilaitemplate Andadengan teks mereka,ke To-nyahalaman AndaID formulir, bukanrahasiaIkiformskor spam, ratelimit, domaindiizinkanhanya penerimaAndadiatur di dashboardlihat sourcekirimkirimemailSiapa yang bisa mengirim lewat key email di browser, dan lewat endpoint formulirsdk email di browserendpoint formulirhalaman Andaservice, template, public keyskrip siapa sajamenyalin ketiga nilaitemplate Andadengan teks mereka, ke To-nyahalaman AndaID formulir, bukan rahasiaIkiformskor spam, rate limit, domaindiizinkanhanya penerima Andadiatur di dashboardlihat sourcekirimkirimemail
  1. 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.
  2. Jika penerima template berasal dari variabel, key yang disalin juga menentukan siapa yang menerimanya.
  3. 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.
ID formulir juga bukan rahasia. Bedanya adalah apa yang bisa dilakukan orang asing dengannya: mengirim formulir Anda, bukan mengirim email Anda.

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:

ItemEmailJSIkiform
Yang dipegang browserService id, template id, dan public keyID formulir
Siapa yang menentukan penerimaTemplate, yang bisa membaca variabelHanya pengaturan dashboard Anda
Penyaringan spamCaptcha per template, jika Anda menambahkannyaHoneypot, skor spam, dan rate limit di setiap formulir, ditambah pemeriksaan manusia opsional
Pesan Anda setelahnyaDi inbox AndaDi dashboard, ekspor CSV, dan API, selain di inbox Anda
Email ke pengunjungYa, dengan template balasan otomatisTidak
Desain email Anda sendiriYa, template di editor merekaTidak, 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:

ContactForm.tsx, sebelum
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:

ContactForm.tsx, sesudah
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 dan 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_email menjadi email. EmailJS tidak peduli pada nama, tetapi Ikiform memakai field bernama email sebagai 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.
Memakai pemeriksaan manusia? Atur Spam check formulir ke Ikiform, lalu panggil 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

  1. Di Allowed domains formulir, tambahkan domain situs Anda, ditambah localhost selama pengembangan. Biarkan kosong untuk menerima kiriman dari mana saja.
  2. Cari emailjs dan service id lama Anda di situs hasil build. Tidak boleh ada yang cocok.
  3. Isi formulir di halaman Anda lalu kirim. Anda mendarat di halaman terima kasih Anda, atau halaman hosted milik Ikiform.
  4. Cek inbox setiap penerima notifikasi. Masing-masing mendapat email berisi field, dan Reply terkirim ke pengirim formulir jika formulir punya field email.
  5. 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

MasalahYang harus dilakukan
Reply masih terkirim ke IkiformField-nya masih user_email. Ganti namanya menjadi email, atau salah satu dari email, email_address, your_email, reply_to, contact_email.
422 validation_failedKiriman tidak cocok dengan definisi field formulir. error.fields menyebutkan setiap field dan alasannya. Samakan name input dengan ID field.
403 challenge_requiredSpam 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 spamDomain halaman tidak ada di Allowed domains formulir. Tambahkan, ditambah localhost untuk uji lokal. Subdomain dari domain yang terdaftar diizinkan.

Pertanyaan

Mentok di salah satu langkah, atau ingin panduan untuk situasi Anda? Email hello@ikiform.com.