JavaScript-форма, що надсилає лист на email
Formgong team ·
JavaScript-формі все одно потрібна адреса для POST. Викличте fetch, надішліть поля і прочитайте відповідь JSON. Formgong приймає цей виклик без вашого сервера. Бібліотека й API-шлях не потрібні. Власний SMTP теж не потрібен. На безкоштовному плані Telegram одразу, а пошта — щоденний дайджест.
Скопіюйте цю JavaScript-форму
<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>Надіслати FormData замість JSON
<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 ? "Надіслано. Дякуємо!" : "Не вдалося надіслати. Спробуйте ще раз.");
if (!result.success) return;
form.reset();
} catch {
status.textContent = "Немає з’єднання. Спробуйте ще раз.";
}
});
</script>Лише виклик fetch, якщо форма вже є на сторінці
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: "uk", ...fields, access_key: "fk_your_access_key" }),
});
const result = await response.json();
if (!result.success) throw new Error(result.message || "Не вдалося надіслати. Спробуйте ще раз.");
return result.message; // localized "Sent. Thank you!"
}Як працюють форми в JavaScript
Люди шукають JavaScript-форму, яка надсилає лист, а не форму fetch. fetch — це лише виклик браузера, який робить POST. EmailJS, Axios і серверний шлях не потрібні.
Надішліть заголовок Accept зі значенням application/json, інакше адреса відповість переходом, як звичайна форма. Збій fetch кидає помилку. Відхилена заявка повертає success зі значенням false і текст, який можна показати.
Налаштування в JavaScript
- Створіть форму у Formgong і скопіюйте ключ доступу.
- Вставте код вище. Це форма і короткий скрипт: async і await, JSON і try catch для мережевих помилок.
- Лишіть пастку для ботів порожньою і поза екраном. Якщо бот її заповнить, заявку збережено як спам і не доставлено.
- Скрипт вимикає кнопку на час запиту, потім показує текст відповіді. Успіх очищає форму.
- Відкрийте живу сторінку і надішліть тест. Перевірте вхідні, потім підключіть Telegram, якщо потрібен сигнал на телефон.
Як надіслати JavaScript-форму
| Варіант | Що ви запускаєте | Що ви отримуєте |
|---|---|---|
| mailto: | Нічого на сервері. Відкривається пошта. | Лист лише якщо відвідувач його надішле. На телефоні це легко ламається. |
| Власний API-шлях | Сервер, SMTP і секрет. | Пошту, якою керуєте ви. Ви також маєте спам, простої і код. |
| EmailJS | Їхній скрипт на сторінці. | Пошту через їхній сервіс. Тут немає ціни. Її не перевіряли на сторінці цін у цей день. |
| Formspree | Нічого. Браузер шле у Formspree. | Пошту і панель. Безкоштовно 50 заявок на місяць. Personal коштує 15 доларів на місяць. |
| Formgong | Нічого. fetch шле у Formgong. | Telegram одразу. На Free пошта — щоденний дайджест. 300 заявок на місяць, дані в ЄС. |
Ціни Formspree взято з formspree.io/plans 2026-10-06. Ліміти Formgong взято з коду продукту. EmailJS є в пошуку за цим запитом. Його ціну того дня не перевіряли. Web3Forms.com відповів HTTP 403, тому його немає в таблиці.
Тарифи · Formgong vs Formspree · HTML-форма, що надсилає лист на email
Пакет із компонентом: npm install @formgong/core (npm: @formgong/core)
Додати в наявний проєкт: npx formgong init (npm: formgong)
fetch, бібліотека чи власний сервер?
Беріть цю сторінку для звичайного JavaScript, невеликого віджета або модального вікна. Відвідувач лишається на сторінці.
Беріть звичайну HTML-форму, якщо JavaScript може бути вимкнено. Форма вище все одно має action, тож працює і без скрипта.
Пишіть власний сервер лише тоді, коли заявка має змінити дані у вашому застосунку. EmailJS шле через свій скрипт. Formgong — це один POST.
Питання та відповіді
Чи може JavaScript надіслати форму на пошту без сервера?
Браузер не говорить SMTP. Він може надіслати поля POST на бекенд форми. Цей бекенд надсилає лист. Для цієї форми ви не тримаєте сервер.
Надсилати FormData чи JSON?
JSON пасує текстовим полям. FormData пасує, коли форма вже є, і коли ви шлете файли. Обидва шляхи ведуть у ті самі вхідні. Для FormData не ставте Content-Type самі.
Чому я отримую перехід замість JSON?
Звичайний POST форми повертає перехід. Щоб отримати JSON, надішліть заголовок Accept зі значенням application/json. Потім прочитайте success і текст.
Як обробляти помилки?
Збій fetch кидає помилку. Це помилка мережі. Відхилена заявка повертає JSON, де success дорівнює false. Покажіть цей текст і лишіть те, що людина ввела.
Чи потрібні EmailJS або інша бібліотека?
Ні. fetch уже є в браузері. Бібліотека доречна, якщо ви її вже маєте. Надішліть ті самі поля і ті самі заголовки.