JavaScript iletişim formu e-posta gönderir
Formgong team ·
Bir JavaScript iletişim formunun yine de POST için bir adresi olmalıdır. fetch çağırın, alanları gönderin ve JSON yanıtını okuyun. Formgong bu çağrıyı sizin sunucunuz olmadan kabul eder. Kitaplık ve API yolu gerekmez. Ücretsiz planda Telegram hemen gelir, e-posta ise günlük özettir.
Bu JavaScript formunu kopyalayın
<form id="fg-contact" action="https://formgong.com/submit" method="POST">
<input type="hidden" name="access_key" value="fk_your_access_key">
<input type="hidden" name="_lang" value="en">
<label>Name <input type="text" name="name" autocomplete="name" placeholder="Your name" required></label>
<label>Email <input type="email" name="email" autocomplete="email" placeholder="you@example.com" required></label>
<label>Message <textarea name="message" placeholder="How can we help?" required></textarea></label>
<div aria-hidden="true" style="position:absolute;inset-inline-start:0;top:0;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)">
<label>Leave this field empty<input type="text" name="botcheck" tabindex="-1" autocomplete="off"></label>
</div>
<button type="submit">Send</button>
<p role="status"></p>
</form>
<script>
const form = document.querySelector("#fg-contact");
const status = form.querySelector("[role=status]");
form.addEventListener("submit", async (event) => {
event.preventDefault();
const button = form.querySelector("button");
button.disabled = true;
const fields = Object.fromEntries(new FormData(form));
try {
const response = await fetch(form.action, {
method: "POST",
headers: { "Content-Type": "application/json", Accept: "application/json" },
body: JSON.stringify(fields),
});
const result = await response.json();
status.textContent = result.message || (result.success ? "Sent. Thank you!" : "Could not send. Please try again.");
if (result.success) form.reset();
} catch {
status.textContent = "Connection failed. Please try again.";
} finally {
button.disabled = false;
}
});
</script><form id="fg-contact" action="https://formgong.com/submit" method="POST">
<input type="hidden" name="access_key" value="fk_your_access_key">
<input type="hidden" name="_lang" value="uk">
<label>Ім’я <input type="text" name="name" autocomplete="name" placeholder="Ваше ім’я" required></label>
<label>Email <input type="email" name="email" autocomplete="email" placeholder="you@example.com" required></label>
<label>Повідомлення <textarea name="message" placeholder="Чим ми можемо допомогти?" required></textarea></label>
<div aria-hidden="true" style="position:absolute;inset-inline-start:0;top:0;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)">
<label>Залиште це поле порожнім<input type="text" name="botcheck" tabindex="-1" autocomplete="off"></label>
</div>
<button type="submit">Надіслати</button>
<p role="status"></p>
</form>
<script>
const form = document.querySelector("#fg-contact");
const status = form.querySelector("[role=status]");
form.addEventListener("submit", async (event) => {
event.preventDefault();
const button = form.querySelector("button");
button.disabled = true;
const fields = Object.fromEntries(new FormData(form));
try {
const response = await fetch(form.action, {
method: "POST",
headers: { "Content-Type": "application/json", Accept: "application/json" },
body: JSON.stringify(fields),
});
const result = await response.json();
status.textContent = result.message || (result.success ? "Надіслано. Дякуємо!" : "Не вдалося надіслати. Спробуйте ще раз.");
if (result.success) form.reset();
} catch {
status.textContent = "Немає з’єднання. Спробуйте ще раз.";
} finally {
button.disabled = false;
}
});
</script><form id="fg-contact" action="https://formgong.com/submit" method="POST">
<input type="hidden" name="access_key" value="fk_your_access_key">
<input type="hidden" name="_lang" value="pl">
<label>Imię <input type="text" name="name" autocomplete="name" placeholder="Twoje imię" required></label>
<label>E-mail <input type="email" name="email" autocomplete="email" placeholder="ty@example.com" required></label>
<label>Wiadomość <textarea name="message" placeholder="W czym możemy pomóc?" required></textarea></label>
<div aria-hidden="true" style="position:absolute;inset-inline-start:0;top:0;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)">
<label>Pozostaw to pole puste<input type="text" name="botcheck" tabindex="-1" autocomplete="off"></label>
</div>
<button type="submit">Wyślij</button>
<p role="status"></p>
</form>
<script>
const form = document.querySelector("#fg-contact");
const status = form.querySelector("[role=status]");
form.addEventListener("submit", async (event) => {
event.preventDefault();
const button = form.querySelector("button");
button.disabled = true;
const fields = Object.fromEntries(new FormData(form));
try {
const response = await fetch(form.action, {
method: "POST",
headers: { "Content-Type": "application/json", Accept: "application/json" },
body: JSON.stringify(fields),
});
const result = await response.json();
status.textContent = result.message || (result.success ? "Wysłano. Dziękujemy!" : "Nie udało się wysłać. Spróbuj ponownie.");
if (result.success) form.reset();
} catch {
status.textContent = "Brak połączenia. Spróbuj ponownie.";
} finally {
button.disabled = false;
}
});
</script><form id="fg-contact" action="https://formgong.com/submit" method="POST">
<input type="hidden" name="access_key" value="fk_your_access_key">
<input type="hidden" name="_lang" value="tr">
<label>Ad <input type="text" name="name" autocomplete="name" placeholder="Adınız" required></label>
<label>E-posta <input type="email" name="email" autocomplete="email" placeholder="siz@ornek.com" required></label>
<label>Mesaj <textarea name="message" placeholder="Size nasıl yardımcı olabiliriz?" required></textarea></label>
<div aria-hidden="true" style="position:absolute;inset-inline-start:0;top:0;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)">
<label>Bu alanı boş bırakın<input type="text" name="botcheck" tabindex="-1" autocomplete="off"></label>
</div>
<button type="submit">Gönder</button>
<p role="status"></p>
</form>
<script>
const form = document.querySelector("#fg-contact");
const status = form.querySelector("[role=status]");
form.addEventListener("submit", async (event) => {
event.preventDefault();
const button = form.querySelector("button");
button.disabled = true;
const fields = Object.fromEntries(new FormData(form));
try {
const response = await fetch(form.action, {
method: "POST",
headers: { "Content-Type": "application/json", Accept: "application/json" },
body: JSON.stringify(fields),
});
const result = await response.json();
status.textContent = result.message || (result.success ? "Gönderildi. Teşekkürler!" : "Gönderilemedi. Lütfen tekrar deneyin.");
if (result.success) form.reset();
} catch {
status.textContent = "Bağlantı kurulamadı. Lütfen tekrar deneyin.";
} finally {
button.disabled = false;
}
});
</script><form id="fg-contact" action="https://formgong.com/submit" method="POST">
<input type="hidden" name="access_key" value="fk_your_access_key">
<input type="hidden" name="_lang" value="es">
<label>Nombre <input type="text" name="name" autocomplete="name" placeholder="Tu nombre" required></label>
<label>Correo electrónico <input type="email" name="email" autocomplete="email" placeholder="tu@ejemplo.com" required></label>
<label>Mensaje <textarea name="message" placeholder="¿En qué podemos ayudarte?" required></textarea></label>
<div aria-hidden="true" style="position:absolute;inset-inline-start:0;top:0;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)">
<label>Deja este campo vacío<input type="text" name="botcheck" tabindex="-1" autocomplete="off"></label>
</div>
<button type="submit">Enviar</button>
<p role="status"></p>
</form>
<script>
const form = document.querySelector("#fg-contact");
const status = form.querySelector("[role=status]");
form.addEventListener("submit", async (event) => {
event.preventDefault();
const button = form.querySelector("button");
button.disabled = true;
const fields = Object.fromEntries(new FormData(form));
try {
const response = await fetch(form.action, {
method: "POST",
headers: { "Content-Type": "application/json", Accept: "application/json" },
body: JSON.stringify(fields),
});
const result = await response.json();
status.textContent = result.message || (result.success ? "Enviado. ¡Gracias!" : "No se pudo enviar. Inténtalo de nuevo.");
if (result.success) form.reset();
} catch {
status.textContent = "Error de conexión. Inténtalo de nuevo.";
} finally {
button.disabled = false;
}
});
</script><form id="fg-contact" action="https://formgong.com/submit" method="POST">
<input type="hidden" name="access_key" value="fk_your_access_key">
<input type="hidden" name="_lang" value="fr">
<label>Nom <input type="text" name="name" autocomplete="name" placeholder="Votre nom" required></label>
<label>E-mail <input type="email" name="email" autocomplete="email" placeholder="vous@exemple.com" required></label>
<label>Message <textarea name="message" placeholder="Comment pouvons-nous vous aider ?" required></textarea></label>
<div aria-hidden="true" style="position:absolute;inset-inline-start:0;top:0;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)">
<label>Laissez ce champ vide<input type="text" name="botcheck" tabindex="-1" autocomplete="off"></label>
</div>
<button type="submit">Envoyer</button>
<p role="status"></p>
</form>
<script>
const form = document.querySelector("#fg-contact");
const status = form.querySelector("[role=status]");
form.addEventListener("submit", async (event) => {
event.preventDefault();
const button = form.querySelector("button");
button.disabled = true;
const fields = Object.fromEntries(new FormData(form));
try {
const response = await fetch(form.action, {
method: "POST",
headers: { "Content-Type": "application/json", Accept: "application/json" },
body: JSON.stringify(fields),
});
const result = await response.json();
status.textContent = result.message || (result.success ? "Envoyé. Merci !" : "Échec de l’envoi. Veuillez réessayer.");
if (result.success) form.reset();
} catch {
status.textContent = "Connexion impossible. Veuillez réessayer.";
} finally {
button.disabled = false;
}
});
</script><form id="fg-contact" action="https://formgong.com/submit" method="POST">
<input type="hidden" name="access_key" value="fk_your_access_key">
<input type="hidden" name="_lang" value="pt">
<label>Nome <input type="text" name="name" autocomplete="name" placeholder="O seu nome" required></label>
<label>E-mail <input type="email" name="email" autocomplete="email" placeholder="voce@exemplo.com" required></label>
<label>Mensagem <textarea name="message" placeholder="Como podemos ajudar?" required></textarea></label>
<div aria-hidden="true" style="position:absolute;inset-inline-start:0;top:0;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)">
<label>Deixe este campo vazio<input type="text" name="botcheck" tabindex="-1" autocomplete="off"></label>
</div>
<button type="submit">Enviar</button>
<p role="status"></p>
</form>
<script>
const form = document.querySelector("#fg-contact");
const status = form.querySelector("[role=status]");
form.addEventListener("submit", async (event) => {
event.preventDefault();
const button = form.querySelector("button");
button.disabled = true;
const fields = Object.fromEntries(new FormData(form));
try {
const response = await fetch(form.action, {
method: "POST",
headers: { "Content-Type": "application/json", Accept: "application/json" },
body: JSON.stringify(fields),
});
const result = await response.json();
status.textContent = result.message || (result.success ? "Enviado. Obrigado!" : "Não foi possível enviar. Tente novamente.");
if (result.success) form.reset();
} catch {
status.textContent = "Falha na ligação. Tente novamente.";
} finally {
button.disabled = false;
}
});
</script><form id="fg-contact" action="https://formgong.com/submit" method="POST">
<input type="hidden" name="access_key" value="fk_your_access_key">
<input type="hidden" name="_lang" value="ar">
<label>الاسم <input type="text" name="name" autocomplete="name" placeholder="اسمك" required></label>
<label>البريد الإلكتروني <input type="email" name="email" autocomplete="email" placeholder="you@example.com" required></label>
<label>الرسالة <textarea name="message" placeholder="كيف يمكننا مساعدتك؟" required></textarea></label>
<div aria-hidden="true" style="position:absolute;inset-inline-start:0;top:0;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)">
<label>اترك هذا الحقل فارغًا<input type="text" name="botcheck" tabindex="-1" autocomplete="off"></label>
</div>
<button type="submit">إرسال</button>
<p role="status"></p>
</form>
<script>
const form = document.querySelector("#fg-contact");
const status = form.querySelector("[role=status]");
form.addEventListener("submit", async (event) => {
event.preventDefault();
const button = form.querySelector("button");
button.disabled = true;
const fields = Object.fromEntries(new FormData(form));
try {
const response = await fetch(form.action, {
method: "POST",
headers: { "Content-Type": "application/json", Accept: "application/json" },
body: JSON.stringify(fields),
});
const result = await response.json();
status.textContent = result.message || (result.success ? "تم الإرسال. شكرًا لك!" : "تعذّر الإرسال. يرجى المحاولة مرة أخرى.");
if (result.success) form.reset();
} catch {
status.textContent = "فشل الاتصال. يرجى المحاولة مرة أخرى.";
} finally {
button.disabled = false;
}
});
</script><form id="fg-contact" action="https://formgong.com/submit" method="POST">
<input type="hidden" name="access_key" value="fk_your_access_key">
<input type="hidden" name="_lang" value="he">
<label>שם <input type="text" name="name" autocomplete="name" placeholder="השם שלך" required></label>
<label>אימייל <input type="email" name="email" autocomplete="email" placeholder="you@example.com" required></label>
<label>הודעה <textarea name="message" placeholder="איך נוכל לעזור?" required></textarea></label>
<div aria-hidden="true" style="position:absolute;inset-inline-start:0;top:0;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)">
<label>השאירו שדה זה ריק<input type="text" name="botcheck" tabindex="-1" autocomplete="off"></label>
</div>
<button type="submit">שליחה</button>
<p role="status"></p>
</form>
<script>
const form = document.querySelector("#fg-contact");
const status = form.querySelector("[role=status]");
form.addEventListener("submit", async (event) => {
event.preventDefault();
const button = form.querySelector("button");
button.disabled = true;
const fields = Object.fromEntries(new FormData(form));
try {
const response = await fetch(form.action, {
method: "POST",
headers: { "Content-Type": "application/json", Accept: "application/json" },
body: JSON.stringify(fields),
});
const result = await response.json();
status.textContent = result.message || (result.success ? "נשלח. תודה!" : "השליחה נכשלה. נא לנסות שוב.");
if (result.success) form.reset();
} catch {
status.textContent = "אין חיבור. נא לנסות שוב.";
} finally {
button.disabled = false;
}
});
</script><form id="fg-contact" action="https://formgong.com/submit" method="POST">
<input type="hidden" name="access_key" value="fk_your_access_key">
<input type="hidden" name="_lang" value="hi">
<label>नाम <input type="text" name="name" autocomplete="name" placeholder="आपका नाम" required></label>
<label>ईमेल <input type="email" name="email" autocomplete="email" placeholder="you@example.com" required></label>
<label>संदेश <textarea name="message" placeholder="हम आपकी कैसे मदद कर सकते हैं?" required></textarea></label>
<div aria-hidden="true" style="position:absolute;inset-inline-start:0;top:0;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)">
<label>इस फ़ील्ड को खाली छोड़ें<input type="text" name="botcheck" tabindex="-1" autocomplete="off"></label>
</div>
<button type="submit">भेजें</button>
<p role="status"></p>
</form>
<script>
const form = document.querySelector("#fg-contact");
const status = form.querySelector("[role=status]");
form.addEventListener("submit", async (event) => {
event.preventDefault();
const button = form.querySelector("button");
button.disabled = true;
const fields = Object.fromEntries(new FormData(form));
try {
const response = await fetch(form.action, {
method: "POST",
headers: { "Content-Type": "application/json", Accept: "application/json" },
body: JSON.stringify(fields),
});
const result = await response.json();
status.textContent = result.message || (result.success ? "भेज दिया गया। धन्यवाद!" : "भेजा नहीं जा सका। कृपया फिर से कोशिश करें।");
if (result.success) form.reset();
} catch {
status.textContent = "कनेक्शन विफल। कृपया फिर से कोशिश करें।";
} finally {
button.disabled = false;
}
});
</script><form id="fg-contact" action="https://formgong.com/submit" method="POST">
<input type="hidden" name="access_key" value="fk_your_access_key">
<input type="hidden" name="_lang" value="ja">
<label>お名前 <input type="text" name="name" autocomplete="name" placeholder="山田 太郎" required></label>
<label>メールアドレス <input type="email" name="email" autocomplete="email" placeholder="you@example.com" required></label>
<label>メッセージ <textarea name="message" placeholder="ご用件をご記入ください" required></textarea></label>
<div aria-hidden="true" style="position:absolute;inset-inline-start:0;top:0;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)">
<label>この欄は空のままにしてください<input type="text" name="botcheck" tabindex="-1" autocomplete="off"></label>
</div>
<button type="submit">送信</button>
<p role="status"></p>
</form>
<script>
const form = document.querySelector("#fg-contact");
const status = form.querySelector("[role=status]");
form.addEventListener("submit", async (event) => {
event.preventDefault();
const button = form.querySelector("button");
button.disabled = true;
const fields = Object.fromEntries(new FormData(form));
try {
const response = await fetch(form.action, {
method: "POST",
headers: { "Content-Type": "application/json", Accept: "application/json" },
body: JSON.stringify(fields),
});
const result = await response.json();
status.textContent = result.message || (result.success ? "送信しました。ありがとうございます。" : "送信できませんでした。もう一度お試しください。");
if (result.success) form.reset();
} catch {
status.textContent = "接続できませんでした。もう一度お試しください。";
} finally {
button.disabled = false;
}
});
</script><form id="fg-contact" action="https://formgong.com/submit" method="POST">
<input type="hidden" name="access_key" value="fk_your_access_key">
<input type="hidden" name="_lang" value="de">
<label>Name <input type="text" name="name" autocomplete="name" placeholder="Ihr Name" required></label>
<label>E-Mail <input type="email" name="email" autocomplete="email" placeholder="name@beispiel.de" required></label>
<label>Nachricht <textarea name="message" placeholder="Wie können wir Ihnen helfen?" required></textarea></label>
<div aria-hidden="true" style="position:absolute;inset-inline-start:0;top:0;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)">
<label>Lassen Sie dieses Feld leer<input type="text" name="botcheck" tabindex="-1" autocomplete="off"></label>
</div>
<button type="submit">Senden</button>
<p role="status"></p>
</form>
<script>
const form = document.querySelector("#fg-contact");
const status = form.querySelector("[role=status]");
form.addEventListener("submit", async (event) => {
event.preventDefault();
const button = form.querySelector("button");
button.disabled = true;
const fields = Object.fromEntries(new FormData(form));
try {
const response = await fetch(form.action, {
method: "POST",
headers: { "Content-Type": "application/json", Accept: "application/json" },
body: JSON.stringify(fields),
});
const result = await response.json();
status.textContent = result.message || (result.success ? "Gesendet. Vielen Dank!" : "Das Senden ist fehlgeschlagen. Bitte versuchen Sie es erneut.");
if (result.success) form.reset();
} catch {
status.textContent = "Die Verbindung ist fehlgeschlagen. Bitte versuchen Sie es erneut.";
} finally {
button.disabled = false;
}
});
</script>JSON yerine FormData gönderin
<script>
const form = document.querySelector("#fg-contact");
form.addEventListener("submit", async (event) => {
event.preventDefault();
const status = form.querySelector("[role=status]");
try {
const response = await fetch("https://formgong.com/submit", {
method: "POST",
headers: { Accept: "application/json" },
body: new FormData(form),
});
const result = await response.json();
status.textContent = result.message || (result.success ? "Gönderildi. Teşekkürler!" : "Gönderilemedi. Lütfen tekrar deneyin.");
if (!result.success) return;
form.reset();
} catch {
status.textContent = "Bağlantı kurulamadı. Lütfen tekrar deneyin.";
}
});
</script>Form zaten sayfadaysa yalnızca fetch çağrısı
async function onSubmit(event) {
event.preventDefault();
const fields = Object.fromEntries(new FormData(event.currentTarget));
const response = await fetch("https://formgong.com/submit", {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
// _lang: language of Formgong messages and the autoreply (multilingual site: document.documentElement.lang).
body: JSON.stringify({ _lang: "tr", ...fields, access_key: "fk_your_access_key" }),
});
const result = await response.json();
if (!result.success) throw new Error(result.message || "Gönderilemedi. Lütfen tekrar deneyin.");
return result.message; // localized "Sent. Thank you!"
}JavaScript ile formlar nasıl çalışır
İnsanlar e-posta gönderen bir JavaScript iletişim formu arar, fetch formu aramaz. fetch yalnızca POST yapan tarayıcı çağrısıdır. EmailJS, Axios ya da sunucu yolu gerekmez.
Accept başlığını application/json yapın. Yoksa uç nokta düz form gibi yönlendirme döner. Başarısız fetch hata fırlatır. Reddedilen kayıt success değerini false yapar ve gösterebileceğiniz bir ileti döner.
JavaScript ile kurulum
- Formgong'da bir form oluşturun ve erişim anahtarını kopyalayın.
- Yukarıdaki kodu yapıştırın. Bu bir form ve kısa bir betiktir: async ve await, JSON ve ağ hataları için try catch.
- Tuzak alanını boş ve ekran dışında tutun. Bir bot doldurursa kayıt spam olarak saklanır ve iletilmez.
- Betik istek sürerken düğmeyi kapatır, sonra yanıttaki iletiyi gösterir. Başarı formu temizler.
- Canlı sayfayı açın ve bir deneme gönderin. Gelen kutusuna bakın, telefona uyarı için Telegram'ı bağlayın.
JavaScript iletişim formunu gönderme yolları
| Seçenek | Sizin çalıştırdığınız şey | Ne alırsınız |
|---|---|---|
| mailto: | Sunucuda bir şey yok. Posta uygulaması açılır. | İleti ancak ziyaretçi gönderirse gelir. Telefonda kolay bozulur. |
| Kendi API yolunuz | Bir sunucu, SMTP ve bir sır. | Kontrol ettiğiniz e-posta. Spam, kesinti ve kod da sizde kalır. |
| EmailJS | Sayfadaki onların betiği. | Hizmetleri üzerinden e-posta. Burada fiyat yok. O gün fiyat sayfası yeniden bakılmadı. |
| Formspree | Yok. Tarayıcı Formspree'ye gönderir. | E-posta ve panel. Ücretsiz ayda 50 gönderim. Personal ayda 15 dolardır. |
| Formgong | Yok. fetch Formgong'a gönderir. | Telegram hemen. Free planda e-posta günlük özettir. Ayda 300 gönderim, veriler AB'de. |
Formspree fiyatları 2026-10-06 günü formspree.io/plans sayfasından alındı. Formgong sınırları ürün kodundan gelir. EmailJS bu aramada çıkar. Fiyatı o gün yeniden bakılmadı. Web3Forms.com HTTP 403 verdi, bu yüzden tabloda yok.
Fiyatlar · Formgong vs Formspree · HTML iletişim formu e-posta gönderir
Bileşen paketi: npm install @formgong/core (npm: @formgong/core)
Mevcut projeye ekleyin: npx formgong init (npm: formgong)
fetch, kitaplık ya da kendi sunucunuz?
Form düz JavaScript, küçük bir parça ya da pencere ise bu sayfayı kullanın. Ziyaretçi sayfada kalır.
JavaScript kapalı olabiliyorsa düz HTML kullanın. Yukarıdaki formun action değeri vardır, bu yüzden betik çalışmasa da gider.
Kendi sunucunuzu yalnızca kayıt uygulamanızdaki veriyi değiştirecekse yazın. EmailJS kendi betiğiyle gönderir. Formgong tek bir POST'tur.
Sorular ve yanıtlar
JavaScript sunucusuz bir formu e-postaya gönderir mi?
Tarayıcı SMTP konuşamaz. Alanları bir form uç noktasına POST edebilir. Postayı o uç nokta gönderir. Bu form için sunucu çalıştırmazsınız.
FormData mı JSON mu göndermeliyim?
JSON metin alanlarına uyar. FormData, form öğesi hazırsa ve dosya gönderiyorsanız uyar. İkisi de aynı gelen kutusuna gider. FormData için Content-Type koymayın.
Neden JSON yerine yönlendirme alıyorum?
Düz form POST'u yönlendirme döner. JSON için Accept başlığını application/json yapın. Sonra success ve iletiyi okuyun.
Hataları nasıl ele almalıyım?
Başarısız fetch hata fırlatır. Bu bir ağ hatasıdır. Reddedilen kayıt success değeri false olan JSON döner. O iletiyi gösterin ve yazılanı silmeyin.
EmailJS ya da başka bir kitaplık gerekir mi?
Hayır. fetch tarayıcıdadır. Zaten kullanıyorsanız bir kitaplık da olur. Aynı alanları ve aynı başlıkları gönderin.