טפסי צור-קשר שעובדים — EmailJS, Resend, Telegram
מדריך טופס יצירת קשר מלא: EmailJS, Resend, Telegram ו-Google Sheets — קוד אמיתי, הקמה תוך 20 דק׳, הגנה מספאם, ולמה האימייל נופל לספאם
למי המדריך הזה: בנית אתר — דף נחיתה, פורטפוליו, אתר תדמית לעסק, חנות קטנה — ואתה צריך טופס יצירת קשר שבאמת יעבוד. אתה לא רוצה להקים שרת רק בשביל זה, אתה לא רוצה לשלם 40$ לחודש על תוסף וורדפרס, ואתה רוצה שההודעה תגיע אליך בלי ליפול לספאם. המדריך הזה מניח שאתה מכיר React ברמה בסיסית (useState, props, fetch), ושיש לך אתר בייצור או שכמעט שם.
טופס יצירת קשר הוא נקודת ההמרה הכי בסיסית באתר — ולכן הכי כדאי לבנות אותו נכון מההתחלה. אם אתה בונה דף נחיתה שלם, שווה לקרוא גם את המדריך על אופטימיזציית המרה לדף נחיתה — הטופס הוא חצי מהקרב, הטקסט שמסביבו הוא החצי השני (יש לי גם מדריך נפרד על קופירייטינג ממיר בעברית). וברגע שהליד נכנס, השאלה היא מה קורה איתו — שם נכנס משפך מעקב אוטומטי ללידים.
שאלה אחת לפני שמתחילים
לפני שתבחר טכנולוגיה, ענה לעצמך על שאלה אחת: כמה הודעות אתה מצפה לקבל בחודש?
- פחות מ-50 — דף נחיתה לעסק קטן, פורטפוליו, אתר חבר קהילה. EmailJS לבד יספיק לך. אל תסבך.
- 50 עד 500 — עסק שצומח, עו״ד, רואה חשבון, סטודיו עיצוב, רופא פרטי. תשלב EmailJS + Telegram, או תעבור ל-Resend עם דומיין משלך.
- 500 עד 5,000 — חנות, SaaS בתחילת הדרך, מותג עם טראפיק. Resend על דומיין משלך עם SPF/DKIM/DMARC, ו-Telegram להתראות, ו-Google Sheets ל-CRM בסיסי. בנפח כזה כבר שווה לשקול בוט WhatsApp שעונה אוטומטית — מכוסה במדריך על סוכן WhatsApp מבוסס AI.
- מעל 5,000 — אתה כבר מעבר לטופס יצירת קשר. אתה צריך CRM אמיתי (HubSpot, Pipedrive) + Resend או SendGrid + מערכת ticketing, ולרוב גם אוטומציה שמחברת בין הטופס לכלים האחרים — ראה n8n מול Make מול Zapier. זה לא המדריך הזה.
האם הטופס שלך מטפל בכרטיסי אשראי, ת״ז, מסמכים רפואיים? אם כן, אף אחד מהפתרונות במדריך הזה לא מספיק לבד — צריך לעבור על תקנות הגנת הפרטיות בעצמך. דבר עם עו״ד.
האם אתה צריך גם חיוב, חתימה דיגיטלית, סליקה באותו טופס? זה לא טופס צור קשר — זה checkout. תפנה לפתרון ייעודי (Stripe Checkout, Tranzila, Z-Credit).
5 הפתרונות לטופס יצירת קשר — מה בוחרים ולמה
| פתרון | מחיר חינם | מחיר ראשון בתשלום | מורכבות הקמה | יתרון עיקרי | חיסרון עיקרי |
|---|---|---|---|---|---|
| EmailJS | 200 הודעות/חודש | 9$/חודש לעד 2,000 | פשוט מאוד — 15 דק׳ | בלי שרת, בלי backend, רץ ישר מהדפדפן | טוקן ה-public key חשוף, פגיע ל-spam |
| Resend | 3,000/חודש, 100/יום | מ-20$/חודש (Pro, לעד 50,000) | בינוני — צריך API route | אמין, react-email, מיועד למפתחים | חובה backend, דורש דומיין מאומת |
| Telegram Bot | חינמי לחלוטין | אין | פשוט מאוד — 10 דק׳ | התראה מיידית בטלפון, ללא limits מעשיים | לא אימייל. לא ארכיב מסודר. ה-token חשוף בקוד פרונט. |
| Google Sheets | חינמי לחלוטין | אין (עד 6M cell/sheet) | בינוני — Apps Script | מקבל לידים ישר לגיליון, CRM מיניאטורי | אין התראה, צריך לבדוק ידנית, סלאו לעיתים |
| Formspree / Web3Forms | Formspree: 50/חודש, Web3Forms: 250/חודש | Formspree מ-15$/חודש | פשוט מאוד — endpoint אחד | אפס קוד, אפס הגדרות | תלוי בספק חיצוני, פיצ׳רים מוגבלים בחינמי |
ההמלצה שלי בקצרה:
- אתר חדש, עסק קטן, פחות מ-200 פניות בחודש — EmailJS לבד. גמרנו.
- אתר רציני שמייצג מותג — Resend על דומיין משלך + Telegram להתראה מיידית.
- אם אתה לא רוצה לכתוב backend בכלל — EmailJS + Telegram. שני HTTP calls מהדפדפן, וזהו.
המשך המדריך בא לתת לך את הקוד הפועל בכל אחד מהמסלולים, כדי שתוכל להעתיק-להדביק ולסגור את הסיפור הזה ב-20 דקות.
EmailJS מול Resend — ההכרעה ב-3 שאלות
זו ההתלבטות שמגיעה אליי הכי הרבה, אז הנה דרך מהירה להכריע. ענה על שלוש שאלות:
- יש לך כבר backend (Next.js API route, Firebase Function, Vercel function)? אם כן — Resend עולה לך 5 דקות והוא הבחירה הנכונה. אם אתה אתר React/Vite סטטי בלי שום צד שרת — EmailJS חוסך לך את כאב הראש.
- המייל נשלח מהדומיין שלך או מ-Gmail? אם אתה רוצה שכתובת השולח תהיה
[email protected]— חייבים Resend עם דומיין מאומת. EmailJS שולח דרך חשבון Gmail/Outlook אישי, אז כתובת השולח תהיה ה-Gmail שלך. - אתה דואג שמישהו ישרוף לך את המכסה? ב-EmailJS ה-public key חשוף בדפדפן, אז בוט יכול לשרוף את 200 ההודעות החודשיות. ב-Resend ה-API key חי בשרת בלבד, אז אין חשיפה כזו.
בקיצור: אתר סטטי קטן → EmailJS. מותג רציני עם backend → Resend. ואם אתה מתלבט אם בכלל לבנות backend או להישאר frontend בלבד, המדריך על אירוח Vercel מול Firebase עוזר להחליט איפה ה-API route יישב.
פתרון 1: EmailJS — הכי פשוט, בלי שרת
EmailJS הוא שירות שמאפשר לשלוח אימייל ישירות מהדפדפן, דרך חשבון Gmail/Outlook/SendGrid שאתה מחבר אליו. בלי backend. אתה כותב fetch אחד, וההודעה נשלחת.
הוא לא שרת אימייל בעצמו — הוא רק ״מתווך״ שמדבר עם החשבון שלך. אם השרת של EmailJS למטה — האימיילים שלך לא נשלחים. ברוב הימים זה לא קורה.
למה זה ה-default שלי לאתרים קטנים
- אפס backend, אפס API key סודי. אין מה לדאוג שזה ידלוף.
- 200 הודעות חינמיות בחודש זה הרבה מאוד לאתר תדמית.
- חיבור Gmail לוקח 3 דקות.
- ה-Template builder ידידותי — אפשר לשנות נוסח האימייל בלי לגעת בקוד.
אזהרה אמיתית: ה-public key שלך נמצא בקוד frontend, וכל אחד יכול לראות אותו. אם בוט מוצא אותו, הוא יכול לשרוף לך את ה-200 הודעות חודשיות. לכן בהמשך נוסיף honeypot ורידוד בקצב. אל תדלג.
1.1 הרשמה ויצירת Service
- כנס ל-emailjs.com, הירשם (Sign Up).
- בלוח הבקרה, לחץ Email Services → Add New Service.
- בחר Gmail (או Outlook / Yahoo / SMTP מותאם — כל חשבון אימייל שלך).
- תן שם פנימי (למשל
my_site_gmail), חבר לחשבון Gmail שלך דרך OAuth. - שמור את ה-Service ID שמופיע (משהו כמו
service_abc1234).
1.2 יצירת Template
- Email Templates → Create New Template.
- ב-To Email: כתוב את האימייל שאליו תרצה לקבל את ההודעות (האימייל שלך, לא של השולח).
- ב-From Name: השתמש במשתנה —
{{from_name}}. - ב-Reply To:
{{from_email}}— חשוב, אחרת תלחץ Reply ויענה לעצמך. - ב-Subject: למשל
פנייה חדשה מהאתר מאת {{from_name}}. - ב-Content: כתוב את גוף האימייל ותשתל משתנים. דוגמה:
שם: {{from_name}}
אימייל: {{from_email}}
טלפון: {{phone}}
הודעה:
{{message}}
נשלח מ: {{page_url}}
- שמור — תקבל Template ID (משהו כמו
template_xyz5678).
1.3 השגת Public Key
לך ל-Account → General. תמצא Public Key (משהו כמו aB3dE7fGhJk2mNp9). זה לא סוד באמת — הוא יישב בקוד frontend.
1.4 משתני סביבה ב-Vite
ב-קובץ .env.local בשורש הפרויקט:
VITE_EMAILJS_SERVICE_ID=service_abc1234
VITE_EMAILJS_TEMPLATE_ID=template_xyz5678
VITE_EMAILJS_PUBLIC_KEY=aB3dE7fGhJk2mNp9
חשוב: .env.local חייב להיות ב-.gitignore. אל תעלה אותו ל-GitHub. וגם — VITE_ הוא prefix שמאפשר לוויט לחשוף את המשתנה ל-client. זה תקין במקרה הזה כי הערכים האלה ממילא public.
1.5 התקנה
npm install @emailjs/browser
1.6 הקומפוננטה
צור src/components/ContactForm.jsx:
import { useState } from 'react';
import emailjs from '@emailjs/browser';
export default function ContactForm() {
const [formData, setFormData] = useState({
from_name: '',
from_email: '',
phone: '',
message: '',
website: '', // honeypot
});
const [status, setStatus] = useState('idle'); // idle | sending | success | error
const [errorMsg, setErrorMsg] = useState('');
const handleChange = (e) => {
setFormData({ ...formData, [e.target.name]: e.target.value });
};
const handleSubmit = async (e) => {
e.preventDefault();
// Honeypot — בוט ימלא את השדה הזה, אדם לא יראה אותו
if (formData.website) {
setStatus('success'); // לבוטים נראה "הצלחה"
return;
}
setStatus('sending');
setErrorMsg('');
try {
await emailjs.send(
import.meta.env.VITE_EMAILJS_SERVICE_ID,
import.meta.env.VITE_EMAILJS_TEMPLATE_ID,
{
...formData,
page_url: window.location.href,
},
{ publicKey: import.meta.env.VITE_EMAILJS_PUBLIC_KEY }
);
setStatus('success');
setFormData({ from_name: '', from_email: '', phone: '', message: '', website: '' });
} catch (err) {
setStatus('error');
setErrorMsg(err?.text || 'שליחה נכשלה. נסה שוב.');
}
};
if (status === 'success') {
return <p className="success">תודה! קיבלנו את ההודעה ונחזור אליך עד 24 שעות.</p>;
}
return (
<form onSubmit={handleSubmit} noValidate>
<label>
שם מלא
<input
name="from_name"
value={formData.from_name}
onChange={handleChange}
required
/>
</label>
<label>
אימייל
<input
type="email"
name="from_email"
value={formData.from_email}
onChange={handleChange}
required
/>
</label>
<label>
טלפון
<input
type="tel"
name="phone"
value={formData.phone}
onChange={handleChange}
/>
</label>
<label>
הודעה
<textarea
name="message"
value={formData.message}
onChange={handleChange}
rows={5}
required
/>
</label>
{/* Honeypot — נסתר מהמשתמש, נראה לבוט */}
<input
type="text"
name="website"
value={formData.website}
onChange={handleChange}
tabIndex={-1}
autoComplete="off"
style={{ position: 'absolute', left: '-9999px', opacity: 0 }}
aria-hidden="true"
/>
<button type="submit" disabled={status === 'sending'}>
{status === 'sending' ? 'שולח...' : 'שליחה'}
</button>
{status === 'error' && <p className="error" role="alert">{errorMsg}</p>}
</form>
);
}
זהו. 80 שורות, ויש לך טופס שעובד. אם תרצה לבדוק שזה עובד — מלא, שלח, וודא שההודעה הגיעה. אם לא — לך ל-EmailJS dashboard → Email History ותראה מה קרה.
1.7 איך לדעת אם חרגתי מהמכסה
EmailJS שולח לך התראה למייל כשאתה מתקרב למכסה. אבל הנה המלכודת השקטה ששורפת לידים: כשאתה חורג מ-200 ההודעות, EmailJS מתעלם מהבקשה — מחזיר תשובה שנראית כמו הצלחה (HTTP 200 ברוב המקרים), והקוד שלך מציג ״תודה, ההודעה התקבלה״. המשתמש בטוח ששלח, אתה לא קיבלת כלום, ואף אחד לא ידע. זו בדיוק הסיבה שהשילוב עם Telegram (פתרון 5) שווה זהב — ערוץ שני שתמיד מודיע לך.
מה לעשות בפועל:
- בדוק אחת לחודש ב-EmailJS dashboard → Email History כמה הודעות נשלחו, מול 200 המכסה.
- קבע התראה ב-Google Calendar ל-1 בכל חודש — ״בדוק מכסת EmailJS״. 30 שניות.
- אם אתה חוצה 150 בחודש בעקביות — שדרג ל-Personal ב-9$/חודש (2,000 הודעות) או עבור ל-Resend. אל תחכה שתשרף.
- אם אתה רוצה גיבוי טכני ולא רק תזכורת — חבר Telegram כערוץ מקביל, ככה שגם בחודש חריג ההתראה תגיע אליך בלי תלות במכסת האימייל.
פתרון 2: Resend — אמין יותר, דורש Backend
Resend הוא ספק אימייל ״מהדור החדש״ שתפח בשנתיים האחרונות (Stripe-style API, react-email לתבניות). יש לו 3,000 מיילים חינמיים בחודש (100 ביום), אבל בניגוד ל-EmailJS — אתה לא יכול לקרוא אליו ישירות מהדפדפן, כי ה-API key שלו פרטי לחלוטין.
לכן הקוד כאן דורש endpoint משלך — Next.js API route, Vercel Serverless Function, Firebase Cloud Function או Express. נדגים עם Next.js כי זה הכי נפוץ.
מתי לבחור Resend במקום EmailJS
- אתה שולח מהדומיין שלך (
[email protected]) — לא דרך Gmail. - אתה רוצה SPF/DKIM/DMARC תקינים, כדי שהמייל לא ינחת בספאם.
- אתה צריך תבניות אימייל עם עיצוב (לוגו, צבעים, כפתורים) — react-email מצוין לזה.
- אתה רוצה ש-API key לא יהיה חשוף בדפדפן.
- אתה כבר עובד עם Next.js / Vercel / Firebase Functions — הוספת API route עולה לך 5 דקות.
2.1 הרשמה ב-Resend
- כנס ל-resend.com, הירשם.
- API Keys → Create API Key, תן לו שם (למשל
production_send). העתק. הוא יוצג רק פעם אחת. - שמור ב-
.env.local:
RESEND_API_KEY=re_xxxxxxxxxxxxxxxxxxxxxxxx
[email protected]
(שים לב — בלי VITE_ או NEXT_PUBLIC_. זה סוד אמיתי.)
2.2 אימות דומיין (חובה לפרודקשן)
ב-Resend, Domains → Add Domain. הכנס את הדומיין שלך (yourdomain.co.il).
תקבל 3 רשומות DNS שצריך להוסיף בנותן הדומיין שלך (Cloudflare, Namecheap, GoDaddy):
TXT send.yourdomain.co.il "v=spf1 include:amazonses.com ~all"
CNAME resend._domainkey.yourdomain.co.il resend._domainkey.amazonses.com
TXT _dmarc.yourdomain.co.il "v=DMARC1; p=none; rua=mailto:[email protected]"
אלה דוגמאות — תעתיק את הערכים המדויקים שמופיעים אצלך ב-Resend. ההמתנה להפצה: 30 דק׳ עד 48 שעות. בלי זה — האימייל יגיע לספאם של Gmail. במדור Deliverability בהמשך נסביר על SPF/DKIM/DMARC לעומק.
2.3 התקנה
npm install resend react-email @react-email/components
2.4 ה-API route
צור app/api/contact/route.ts (Next.js 14 App Router):
import { Resend } from 'resend';
import { NextResponse } from 'next/server';
const resend = new Resend(process.env.RESEND_API_KEY);
// rate limit פשוט בזיכרון — לעומס נמוך זה מספיק
const lastSendByIp = new Map<string, number>();
const COOLDOWN_MS = 30_000; // אפשר לשלוח אחת ל-30 שניות מאותו IP
export async function POST(req: Request) {
const ip = req.headers.get('x-forwarded-for') ?? 'unknown';
const now = Date.now();
const last = lastSendByIp.get(ip);
if (last && now - last < COOLDOWN_MS) {
return NextResponse.json(
{ error: 'rate_limited', retryAfter: COOLDOWN_MS - (now - last) },
{ status: 429 }
);
}
let body;
try {
body = await req.json();
} catch {
return NextResponse.json({ error: 'invalid_json' }, { status: 400 });
}
const { name, email, phone, message, website } = body;
// Honeypot
if (website) {
return NextResponse.json({ ok: true });
}
// ולידציה בסיסית
if (!name || !email || !message) {
return NextResponse.json({ error: 'missing_fields' }, { status: 400 });
}
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
return NextResponse.json({ error: 'invalid_email' }, { status: 400 });
}
if (message.length > 5000) {
return NextResponse.json({ error: 'message_too_long' }, { status: 400 });
}
try {
await resend.emails.send({
from: 'Contact Form <[email protected]>',
to: [process.env.CONTACT_TO_EMAIL!],
replyTo: email,
subject: `פנייה חדשה מ-${name}`,
html: `
<div dir="rtl" style="font-family: Arial, sans-serif; line-height: 1.6;">
<h2>פנייה חדשה מהאתר</h2>
<p><strong>שם:</strong> ${escapeHtml(name)}</p>
<p><strong>אימייל:</strong> ${escapeHtml(email)}</p>
<p><strong>טלפון:</strong> ${escapeHtml(phone || 'לא צוין')}</p>
<p><strong>הודעה:</strong></p>
<p>${escapeHtml(message).replace(/\n/g, '<br>')}</p>
</div>
`,
});
lastSendByIp.set(ip, now);
return NextResponse.json({ ok: true });
} catch (err) {
console.error('[contact] resend error:', err);
return NextResponse.json({ error: 'send_failed' }, { status: 500 });
}
}
function escapeHtml(str: string) {
return String(str)
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
2.5 הקומפוננטה בפרונט
const handleSubmit = async (e) => {
e.preventDefault();
setStatus('sending');
try {
const res = await fetch('/api/contact', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(formData),
});
if (!res.ok) {
const data = await res.json().catch(() => ({}));
if (data.error === 'rate_limited') {
throw new Error('המתן 30 שניות ונסה שוב');
}
throw new Error('שליחה נכשלה');
}
setStatus('success');
} catch (err) {
setStatus('error');
setErrorMsg(err.message);
}
};
2.6 react-email — תבנית עם עיצוב (אופציונלי אבל יפה)
// emails/ContactEmail.tsx
import { Html, Head, Body, Container, Heading, Text, Hr } from '@react-email/components';
export default function ContactEmail({ name, email, phone, message }) {
return (
<Html dir="rtl" lang="he">
<Head />
<Body style={{ fontFamily: 'Arial, sans-serif', backgroundColor: '#f6f6f6', padding: '24px' }}>
<Container style={{ backgroundColor: '#fff', padding: '32px', borderRadius: '8px' }}>
<Heading>פנייה חדשה מהאתר</Heading>
<Text><strong>שם:</strong> {name}</Text>
<Text><strong>אימייל:</strong> {email}</Text>
<Text><strong>טלפון:</strong> {phone || 'לא צוין'}</Text>
<Hr />
<Text style={{ whiteSpace: 'pre-wrap' }}>{message}</Text>
</Container>
</Body>
</Html>
);
}
וב-API route, החלף את ה-html ב-react:
import { render } from '@react-email/render';
import ContactEmail from '../../../emails/ContactEmail';
await resend.emails.send({
from: 'Contact Form <[email protected]>',
to: [process.env.CONTACT_TO_EMAIL!],
replyTo: email,
subject: `פנייה חדשה מ-${name}`,
html: await render(ContactEmail({ name, email, phone, message })),
});
עכשיו יש לך טמפלייט עברי, RTL, רספונסיבי, שאתה עורך כקומפוננטה React. זה למה Resend אוהבים מפתחים.
פתרון 3: Telegram Webhook — fallback מצוין
הפתרון הכי לא מוערך בעיניי. תוך 10 דקות אתה מקבל התראה בטלפון על כל פנייה — צליל, באנר, הכל. אין מכסות (Telegram לא מגביל בוטים בשליחה לעצמך), הכל חינמי, וזה עובד.
מהי הקריצה כאן? Telegram Bot API מקבל קריאות HTTP מכל מקור, כולל מהדפדפן (CORS פתוח). ה-token של הבוט הוא טכנית סוד, אבל כשהוא רק שולח לצ׳אט הפרטי שלך — הסיכון מינימלי. במקרה הגרוע, מישהו גילה את הטוקן וישלח אליך הודעות ספאם בטלגרם. תחסום את הבוט ותיצור חדש.
3.1 יצירת הבוט
- בטלגרם, חפש את @BotFather.
- שלח
/newbot. - תן שם תצוגה (
MyContactBot) ו-username (mycontact_bot). - תקבל token — משהו כמו
7234567890:AAGxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx. שמור.
3.2 איתור ה-chat_id שלך
הבוט יודע לשלוח רק לצ׳אטים שדיברו איתו. תפתח את הבוט החדש שלך בטלגרם, ושלח לו /start (או כל הודעה).
עכשיו פתח בדפדפן:
https://api.telegram.org/bot7234567890:AAGxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/getUpdates
(החלף את ה-token. שמור גם את המילה bot בהתחלה.)
תראה JSON עם chat.id — מספר כמו 123456789. זה ה-chat_id שלך. שמור.
3.3 משתני סביבה
VITE_TELEGRAM_BOT_TOKEN=7234567890:AAGxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
VITE_TELEGRAM_CHAT_ID=123456789
אזהרת ביטחון: הטוקן בקוד פרונט = פוטנציאל לוועדל. למי שאיכפת לו — תעטוף ב-API route משלך (Next.js / Vercel function). למי שלא — תחיה עם זה, וכשמישהו מציק תחליף בוט.
3.4 פונקציית שליחה
// src/utils/sendTelegram.js
export async function sendTelegram({ name, email, phone, message }) {
const token = import.meta.env.VITE_TELEGRAM_BOT_TOKEN;
const chatId = import.meta.env.VITE_TELEGRAM_CHAT_ID;
const text = [
'*פנייה חדשה מהאתר*',
'',
`*שם:* ${name}`,
`*אימייל:* ${email}`,
`*טלפון:* ${phone || 'לא צוין'}`,
'',
'*הודעה:*',
message,
'',
`_${new Date().toLocaleString('he-IL')}_`,
].join('\n');
const res = await fetch(`https://api.telegram.org/bot${token}/sendMessage`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
chat_id: chatId,
text,
parse_mode: 'Markdown',
}),
});
if (!res.ok) {
const err = await res.json().catch(() => ({}));
throw new Error(err.description || 'Telegram send failed');
}
return res.json();
}
3.5 שימוש בקומפוננטה
import { sendTelegram } from '../utils/sendTelegram';
// בתוך handleSubmit:
await sendTelegram(formData);
זהו. תקבל הודעה בטלפון תוך שניות.
3.6 הגרסה הבטוחה — לעטוף את הטוקן ב-API route
אם הזכרת קודם שהטוקן חשוף בפרונט מטריד אותך — וזה לגיטימי — הנה הגרסה הנכונה. הטוקן יושב בשרת, הפרונט רק שולח את הנתונים, ואף אחד לא רואה את הטוקן ב-DevTools. זה אותו מאמץ כמעט, ואם כבר יש לך backend ל-Resend, אתה משתמש בו ממילא.
// app/api/telegram/route.ts (Next.js App Router)
import { NextResponse } from 'next/server';
export async function POST(req: Request) {
const { name, email, phone, message, website } = await req.json();
if (website) return NextResponse.json({ ok: true }); // honeypot
if (!name || !message) {
return NextResponse.json({ error: 'missing_fields' }, { status: 400 });
}
const token = process.env.TELEGRAM_BOT_TOKEN; // בלי VITE_ / NEXT_PUBLIC_
const chatId = process.env.TELEGRAM_CHAT_ID;
const text = [
'*פנייה חדשה מהאתר*', '',
`*שם:* ${name}`,
`*אימייל:* ${email}`,
`*טלפון:* ${phone || 'לא צוין'}`, '',
'*הודעה:*', message,
].join('\n');
const res = await fetch(`https://api.telegram.org/bot${token}/sendMessage`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ chat_id: chatId, text, parse_mode: 'Markdown' }),
});
if (!res.ok) return NextResponse.json({ error: 'telegram_failed' }, { status: 502 });
return NextResponse.json({ ok: true });
}
עכשיו ה-fetch בפרונט פונה ל-/api/telegram במקום ישירות ל-Telegram, והטוקן לא עוזב את השרת לעולם. הבחירה בין הגרסה החשופה לגרסה העטופה היא בדיוק אותה התלבטות של EmailJS מול Resend — נוחות מול אבטחה. אתר תדמית קטן יכול לחיות עם החשוף; מותג שמכבד את עצמו יעטוף.
פתרון 4: Google Sheets — CRM מיניאטורי
לפעמים מה שבאמת רוצים זה לראות את כל הלידים בטבלה אחת, מסודר, שאפשר לסנן ולמיין. Google Sheets + Apps Script נותנים את זה חינם, ובלי backend.
4.1 יצירת הגיליון
צור Google Sheet חדש. בשורה הראשונה — כותרות:
תאריך | שם | אימייל | טלפון | הודעה | URL
4.2 כתיבת ה-Apps Script
ב-Sheet: Extensions → Apps Script. תפתח עורך קוד. החלף הכל ב:
function doPost(e) {
try {
const data = JSON.parse(e.postData.contents);
const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
sheet.appendRow([
new Date(),
data.name || '',
data.email || '',
data.phone || '',
data.message || '',
data.url || '',
]);
return ContentService
.createTextOutput(JSON.stringify({ ok: true }))
.setMimeType(ContentService.MimeType.JSON);
} catch (err) {
return ContentService
.createTextOutput(JSON.stringify({ ok: false, error: String(err) }))
.setMimeType(ContentService.MimeType.JSON);
}
}
4.3 פריסה כ-Web App
- Deploy → New deployment → Web app.
- Description:
contact form receiver. - Execute as: Me.
- Who has access: Anyone (זה רק נראה מפחיד — הקוד שלך לא חשוף, רק נקודת הקצה).
- Deploy — קבל URL כמו
https://script.google.com/macros/s/AKfycb.../exec. - שמור.
4.4 שליחה מהפרונט
export async function sendToSheet({ name, email, phone, message }) {
const url = import.meta.env.VITE_SHEET_WEBHOOK_URL;
await fetch(url, {
method: 'POST',
mode: 'no-cors', // חשוב — Google Apps Script לא שולח CORS headers נכונים
headers: { 'Content-Type': 'text/plain;charset=utf-8' },
body: JSON.stringify({
name,
email,
phone,
message,
url: window.location.href,
}),
});
// עם no-cors אי אפשר לקרוא response. אם הצריך הרצה — סמוך על שכזה הצלחה.
}
שים לב ל-no-cors — זו הדרך היחידה לדבר עם Apps Script מהדפדפן בלי שגיאת CORS. החיסרון: אתה לא יכול לקרוא את התשובה, רק לסמוך שזה עבד.
פתרון 5: שילוב מומלץ — אימייל + Telegram יחד
ההגדרה האהובה עליי: EmailJS שולח אימייל מסודר לארכיון, Telegram שולח התראה מיידית בטלפון, Google Sheet שומר רישום ל-CRM. שלושה ערוצים במקביל, מכל אחד יוצא ערך אחר.
const handleSubmit = async (e) => {
e.preventDefault();
if (formData.website) return; // honeypot
setStatus('sending');
// שלח לכולם במקביל. נכשלים בשקט אם אחד נופל.
const results = await Promise.allSettled([
emailjs.send(
import.meta.env.VITE_EMAILJS_SERVICE_ID,
import.meta.env.VITE_EMAILJS_TEMPLATE_ID,
formData,
{ publicKey: import.meta.env.VITE_EMAILJS_PUBLIC_KEY }
),
sendTelegram(formData),
sendToSheet(formData),
]);
// הצלחה אם לפחות אחד הצליח
const anyOk = results.some(r => r.status === 'fulfilled');
setStatus(anyOk ? 'success' : 'error');
// לוג שגיאות לקונסולה — לא למשתמש
results.forEach((r, i) => {
if (r.status === 'rejected') {
console.error(`Channel ${i} failed:`, r.reason);
}
});
};
למה זה טוב? אם EmailJS חוצה מכסה, Telegram עדיין מודיע לך. אם Google מכבים את Apps Script לדקה, האימייל הולך. אתה לא מאבד אף ליד.
ולידציה רצינית — react-hook-form + zod
החלק הזה אופציונלי לאתר תדמית קטן, וחובה לכל מה שמעבר. הוא מטפל בולידציה client-side, בהודעות שגיאה בעברית, ובמניעת submit של זבל.
התקנה
npm install react-hook-form zod @hookform/resolvers
Schema
// src/schemas/contact.ts
import { z } from 'zod';
// טלפון ישראלי: 0XX-XXXXXXX או +972...
const israeliPhone = /^(?:\+972|0)(?:[23489]|5[0-9]|7[2-9])-?\d{7}$/;
export const contactSchema = z.object({
name: z
.string()
.min(2, 'שם קצר מדי')
.max(60, 'שם ארוך מדי'),
email: z
.string()
.email('כתובת אימייל לא תקינה')
.max(120, 'כתובת אימייל ארוכה מדי'),
phone: z
.string()
.regex(israeliPhone, 'מספר טלפון ישראלי לא תקין')
.optional()
.or(z.literal('')),
message: z
.string()
.min(10, 'תכתוב לי משהו מהותי — לפחות 10 תווים')
.max(2000, 'הודעה ארוכה מדי'),
website: z.string().max(0, '').optional(), // honeypot — חייב להישאר ריק
consent: z.literal(true, {
errorMap: () => ({ message: 'חובה לאשר את מדיניות הפרטיות' }),
}),
});
export type ContactInput = z.infer<typeof contactSchema>;
הקומפוננטה
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { contactSchema } from '../schemas/contact';
export default function ContactForm() {
const {
register,
handleSubmit,
formState: { errors, isSubmitting },
reset,
} = useForm({ resolver: zodResolver(contactSchema) });
const onSubmit = async (data) => {
if (data.website) return; // honeypot
// ... שליחה
reset();
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<label>
שם
<input {...register('name')} />
{errors.name && <span className="error">{errors.name.message}</span>}
</label>
<label>
אימייל
<input type="email" {...register('email')} />
{errors.email && <span className="error">{errors.email.message}</span>}
</label>
<label>
טלפון (אופציונלי)
<input type="tel" {...register('phone')} placeholder="050-1234567" />
{errors.phone && <span className="error">{errors.phone.message}</span>}
</label>
<label>
הודעה
<textarea {...register('message')} rows={5} />
{errors.message && <span className="error">{errors.message.message}</span>}
</label>
<input type="text" {...register('website')} style={{ display: 'none' }} aria-hidden="true" />
<label className="checkbox">
<input type="checkbox" {...register('consent')} />
קראתי ואני מסכים ל<a href="/privacy">מדיניות הפרטיות</a>
{errors.consent && <span className="error">{errors.consent.message}</span>}
</label>
<button type="submit" disabled={isSubmitting}>
{isSubmitting ? 'שולח...' : 'שליחה'}
</button>
</form>
);
}
הגנה מספאם — 4 שכבות
שכבה 1: Honeypot (חובה, חינמי, חוסם 60% מהבוטים)
שדה נסתר ש-CSS מסתיר מהמשתמש אבל בוט יראה ב-DOM וימלא. אם הוא מולא — דחה את ההודעה בשקט.
<input
type="text"
name="website"
tabIndex={-1}
autoComplete="off"
style={{ position: 'absolute', left: '-9999px', opacity: 0 }}
aria-hidden="true"
/>
אל תקרא לשדה honeypot או bot_trap — בוטים מודרניים מתעלמים משמות כאלה. תן שם תמים: website, url, nickname.
שכבה 2: Rate limit
אם יש לך backend (Resend, Express, Firebase Function) — שמור בזיכרון (Map) או ב-Upstash/Redis את ה-IP האחרון ששלח, ודחה אם הוא שלח לפני פחות מ-30 שניות.
קוד הדוגמה ב-Resend למעלה (סעיף 2.4) מציג את זה. ל-production עם traffic — תעבור ל-Upstash:
import { Ratelimit } from '@upstash/ratelimit';
import { Redis } from '@upstash/redis';
const ratelimit = new Ratelimit({
redis: Redis.fromEnv(),
limiter: Ratelimit.slidingWindow(3, '60 s'), // 3 בקשות בדקה
});
const { success } = await ratelimit.limit(ip);
if (!success) return NextResponse.json({ error: 'rate_limited' }, { status: 429 });
אם אין לך backend (טופס EmailJS / Telegram טהור) — תעשה rate limit client-side עם localStorage. זה לא בלתי-עביר, אבל מצמצם את 95% מהמקרים:
const last = Number(localStorage.getItem('lastContactSubmit') || 0);
if (Date.now() - last < 30_000) {
alert('המתן 30 שניות לפני שליחה נוספת');
return;
}
localStorage.setItem('lastContactSubmit', String(Date.now()));
שכבה 3: CAPTCHA (כשבאמת חוטפים ספאם)
עד שלא חוטפים — אל תוסיף. CAPTCHA הורגת קונברז׳ן ב-15-30% בממוצע. אם הספאם מגיע בעיקר מבוטים אוטומטיים ולא מבני אדם, יש ב-2026 גם גישה שקטה לגמרי בלי פאזל בכלל — זיהוי בוטים בצד שרת לפי טביעת אצבע של הבקשה, שמכוסה במדריך על זיהוי בוטים עם BotID. זה משלים את Turnstile, לא מחליף אותו.
ההמלצה ב-2026: Cloudflare Turnstile. חינמי לחלוטין (עד מיליון אימותים בחודש), invisible לרוב המשתמשים, וטוב יותר מ-reCAPTCHA / hCaptcha לדיני קונברז׳ן. חשוב: ל-hCaptcha אין בכלל מצב ״אינביזיבל״ אמיתי כמו ב-reCAPTCHA v3 — תמיד מוצג פאזל ברירת מחדל. וגם reCAPTCHA v3 כבר לא בחירה נקייה ב-2026: רוב עורכי הדין באירופה דורשים הסכמת cookie לפני טעינתו, מה שהופך אותו לכאב ראש משפטי. לכן ל-2026 הבחירה היא Turnstile.
// קוד מינימלי ל-Turnstile (אחרי שיש לך Site Key)
import { Turnstile } from '@marsidev/react-turnstile';
<Turnstile
siteKey={import.meta.env.VITE_TURNSTILE_SITE_KEY}
onSuccess={(token) => setCfToken(token)}
/>
// ב-handleSubmit, צרף את ה-token לבקשה
body: JSON.stringify({ ...formData, cfToken }),
ב-backend אמת את ה-token דרך https://challenges.cloudflare.com/turnstile/v0/siteverify.
שכבה 4: סינון תוכן
זה שולי, אבל אם אתה מקבל הרבה ספאם פרסומי — תוסיף בלאקליסט מילים פשוט בצד שרת:
const SPAM_WORDS = ['casino', 'viagra', 'cialis', 'crypto signal', 'forex profit'];
const messageLower = message.toLowerCase();
if (SPAM_WORDS.some(w => messageLower.includes(w))) {
return NextResponse.json({ ok: true }); // שקט. הם לא יודעים שזרקנו.
}
Deliverability — למה האימיילים שלך נופלים לספאם
זה הסעיף שאף אחד לא רוצה לקרוא, ושכל אחד צריך. אם אתה שולח דרך Gmail (EmailJS) — אתה מוגן, כי Gmail עצמו דואג ל-deliverability. אם אתה שולח דרך Resend עם דומיין משלך — חובה להגדיר SPF/DKIM/DMARC, אחרת המייל ינחת בספאם.
נדייק את העובדה, כי מסתובבת בלבול: דרישות האכיפה הרשמיות של Google ו-Yahoo (שנכנסו לתוקף בפברואר 2024) מחייבות SPF + DKIM + DMARC לשולחים בנפח — מעל 5,000 מיילים ביום לכתובות Gmail. טופס צור-קשר קטן כמעט אף פעם לא מגיע לסף הזה. אבל אל תיתלה בזה: גם שולח קטן בלי אימות נכון נופל לספאם בפועל, כי מסנני הספאם של Gmail/Outlook מנקדים שולח לא מאומת כחשוד. במילים אחרות — אתה לא חייב לפי האות הקטנה של הכלל, אבל בלי שלוש הרשומות תגלה שחצי מהפניות שלך לא הגיעו. תגדיר אותן בכל מקרה.
שלוש הרשומות (זמן: 10 דקות בנותן הדומיין)
# SPF — מי מורשה לשלוח בשם הדומיין שלי
TXT yourdomain.co.il "v=spf1 include:amazonses.com ~all"
# DKIM — חתימה דיגיטלית על כל מייל
CNAME resend._domainkey.yourdomain.co.il resend._domainkey.amazonses.com
# DMARC — מה לעשות אם SPF/DKIM נכשלו
TXT _dmarc.yourdomain.co.il "v=DMARC1; p=none; rua=mailto:[email protected]"
הערכים המדויקים — תקבל מ-Resend dashboard (Domains → Records). אל תעתיק מהמדריך הזה בלי לבדוק. אחרי הוספה — ההפצה לוקחת 30 דקות עד 48 שעות.
DMARC policy: התחל עם p=none (רק מדווח, לא חוסם). אחרי שבועיים ש-Resend dashboard מראה ירוק בכל מקום — שדרג ל-p=quarantine, ואחרי עוד שבועיים — p=reject.
בדיקה:
- שלח לעצמך אימייל מהטופס.
- ב-Gmail → "Show original" → תראה
SPF: PASS,DKIM: PASS,DMARC: PASS. - או לך ל-mail-tester.com, שלח אליהם — תקבל ציון 0-10. כל מה שמעל 9 טוב.
חוק הספאם הישראלי + GDPR — מה אסור לי לעשות?
זה לא ייעוץ משפטי. דבר עם עו״ד אם אתה ב-doubt.
חוק הספאם (תיקון 40 לחוק התקשורת, 2008)
הכלל המרכזי: אסור לשלוח דבר פרסומת ללא הסכמה מפורשת מראש (Opt-In). ״דבר פרסומת״ כולל אימייל, SMS, פקס, הודעה אוטומטית.
מה זה אומר לטופס צור-קשר?
- טופס ״צור קשר״ עצמו אינו ספאם — אתה לא שולח, אתה מקבל.
- כשאתה עונה למשתמש — זה לא ספאם, כי הוא יזם.
- אסור לך להוסיף אותו אוטומטית לרשימת תפוצה של ניוזלטר אחרי הפנייה. זה ספאם.
- אם תרצה לשלוח לו עדכונים — חייב צ׳קבוקס נפרד בטופס (לא מסומן מראש!) שאומר ״אני מסכים לקבל עדכונים שיווקיים״.
- כל הודעה שיווקית חייבת לכלול אפשרות הסרה — קישור ״הסר״ שעובד מיד.
הפיצוי בלי הוכחת נזק: עד 1,000 ₪ לכל הודעה.
תיקון 13 לחוק הגנת הפרטיות (נכנס לתוקף 2025)
- חובה למסור למשתמש לפני שאתה אוסף ממנו פרטים: מי אתה, למה אתה אוסף, מה תעשה עם המידע, האם יועבר לצד שלישי, וכמה זמן תשמור.
- זה נעשה דרך מדיניות פרטיות — דף נפרד באתר, ולינק אליו ליד הטופס.
- זכות עיון ומחיקה — המשתמש יכול לבקש לראות איזה מידע יש לך עליו, ולמחוק אותו. תהיה ערוך לכך.
GDPR (אם יש לך לקוחות מהאיחוד האירופי)
- חל גם על עסקים ישראלים שמתחזקים מידע של אזרחי EU.
- דורש הסכמה מפורשת ופעילה (checkbox לא מסומן מראש).
- זכות מחיקה ("right to be forgotten") — חובה לתמוך.
- קנסות עד 20M€ או 4% מהמחזור העולמי.
מה לעשות בפועל (Checklist מינימלי)
- [ ] צ׳קבוקס ״אני מאשר את מדיניות הפרטיות״ — חובה, לא מסומן מראש.
- [ ] לינק לדף מדיניות פרטיות ליד הצ׳קבוקס.
- [ ] בדף מדיניות הפרטיות: מי, למה, איפה (איזה כלים — EmailJS, Resend, Google Sheets), כמה זמן, איך למחוק.
- [ ] אל תוסיף את האימייל אוטומטית לרשימת תפוצה.
- [ ] אם אתה כן רוצה ניוזלטר — צ׳קבוקס נפרד, opt-in.
שגיאות נפוצות שתיתקל בהן
"Forbidden" / 403 מ-EmailJS — בדוק שה-public key נכון, ושהוספת את הדומיין שלך ב-EmailJS dashboard תחת Account → Security → Allow EmailJS API for.
האימייל מ-Resend נופל לספאם של Gmail — חסר לך DMARC או שה-SPF/DKIM לא הופצו עוד. תפתח את האימייל ב-Gmail, "Show original", ובדוק שלושת השדות. תן ל-DNS להתפשט 24 שעות.
Telegram מחזיר "Bad Request: chat not found" — לא שלחת /start לבוט מהחשבון שאת ה-chat_id שלו אתה משתמש בו. תחזור על שלב 3.2.
Google Apps Script מחזיר HTML במקום JSON — לרוב זה אומר ש-Apps Script זרק exception לפני שהקוד שלך רץ. סביר להניח שלא פרסת מחדש אחרי שינוי קוד. כל שינוי בקוד דורש Deploy → Manage deployments → Edit → New version → Deploy.
הטופס נשלח פעמיים — אחרי submit, נטרל את הכפתור (disabled={status === 'sending'}). זה לא קישוט, זו דרך לחסום double-submit.
"CORS error" כשמדברים עם Telegram מהדפדפן — לא אמור לקרות, Telegram מחזיר Access-Control-Allow-Origin: *. אם זה קורה, סביר שיש לך proxy/adblocker שחוסם. נסה במכון אינקוגניטו.
מוזרויות עם RTL באימייל — חלק מ-clients (Outlook הישן) לא מכבדים dir="rtl". תעטוף ב-<div dir="rtl" style="text-align: right;">.
EmailJS quota מתמלאת באמצע החודש — כנראה בוט מצא את ה-public key. הוסף honeypot. אם זה לא עוזר, הוסף client-side rate limit ב-localStorage. אם זה ממשיך — תחליף ל-Resend.
שאלות נפוצות
מה ההבדל בין EmailJS ל-Resend, ומה עדיף לטופס יצירת קשר?
EmailJS רץ ישירות מהדפדפן בלי שרת — אתה כותב קריאת fetch אחת וההודעה נשלחת דרך חשבון Gmail/Outlook שחיברת. Resend דורש endpoint בצד שרת (API route) כי ה-API key שלו פרטי, אבל בתמורה אתה שולח מהדומיין שלך עם SPF/DKIM/DMARC תקינים. לאתר סטטי קטן עם פחות מ-200 פניות בחודש — EmailJS מספיק. למותג רציני עם backend קיים — Resend הוא הבחירה האמינה יותר.
האם טופס יצירת קשר עם EmailJS חינמי באמת?
כן, עד 200 הודעות בחודש בתוכנית החינמית של EmailJS (נכון ל-2026). מעבר לזה התוכנית בתשלום מתחילה ב-9$ לחודש עבור עד 2,000 הודעות. ל-Resend המכסה החינמית גדולה יותר — 3,000 הודעות בחודש — אבל עם תקרה של 100 ביום, וזה מה שלרוב מאלץ לשדרג ל-Pro (מ-20$ לחודש) הרבה לפני שמגיעים ל-3,000 החודשיים.
למה האימייל מהטופס נופל לתיקיית הספאם של Gmail?
הסיבה הכי שכיחה היא שאתה שולח מדומיין משלך בלי SPF, DKIM ו-DMARC מוגדרים נכון. מאז פברואר 2024 Gmail ו-Yahoo דורשים את שלוש הרשומות האלה מכל שולח עם דומיין משלו, אחרת המייל נחסם או נזרק לספאם. אם אתה שולח דרך EmailJS (כלומר דרך Gmail עצמו) — אתה מוגן אוטומטית. אם דרך Resend — חובה להגדיר את הרשומות ב-DNS ולחכות 30 דקות עד 48 שעות להפצה.
האם אני חייב CAPTCHA כדי לעצור ספאם?
לא, ולרוב כדאי להימנע ממנו בהתחלה. CAPTCHA פוגע בהמרה ב-15 עד 30 אחוז. תתחיל מ-honeypot (שדה נסתר שחוסם כ-60% מהבוטים) ו-rate limit, ורק אם אתה באמת חוטף ספאם תוסיף Cloudflare Turnstile — שהוא חינמי, בלתי-נראה לרוב המשתמשים, וטוב יותר מ-reCAPTCHA ל-2026.
האם מותר להוסיף את מי שמילא את הטופס לרשימת התפוצה שלי?
לא, לא בלי הסכמה מפורשת ונפרדת. טופס יצירת קשר אינו אישור לקבל דיוור שיווקי — לפי חוק הספאם הישראלי (תיקון 40) ו-GDPR, אסור להוסיף אדם אוטומטית לניוזלטר רק כי פנה אליך. אם אתה רוצה לשלוח לו עדכונים, צריך צ׳קבוקס נפרד שאינו מסומן מראש שאומר במפורש שהוא מסכים לקבל תוכן שיווקי.
האם Telegram יכול להחליף אימייל בטופס יצירת קשר?
הוא מצוין כהתראה מיידית בטלפון, אבל לא כתחליף מלא לאימייל. ב-Telegram אין ארכיון מסודר שאפשר לחפש בו, אין reply נוח, וקשה לשתף לידים עם צוות. ההגדרה הטובה ביותר היא שילוב: EmailJS או Resend לארכיון מסודר, Telegram להתראה מיידית, ו-Google Sheets לרישום ל-CRM. שלושתם רצים במקביל עם Promise.allSettled כך שגם אם אחד נופל, לא מאבדים את הליד.
איפה צריך לשבת ה-API route של Resend?
בכל מקום שמריץ קוד צד שרת — Next.js API route, Vercel Serverless Function, Firebase Cloud Function או שרת Express. אם האתר שלך כבר על Vercel או Firebase, זה עניין של קובץ אחד. אם אתה אתר React/Vite סטטי בלי backend, או שתוסיף פונקציה אחת (ראה Vercel מול Firebase) או שתישאר עם EmailJS שלא דורש שרת בכלל.
לסיכום
טופס יצירת קשר לא צריך לקחת יותר מ-20 דקות, וגם לא צריך שרת אם אתה לא רוצה אחד. ההכרעה המעשית:
- אתר קטן, פחות מ-200 פניות בחודש — EmailJS לבד. אפס backend, אפס דאגות.
- מותג רציני עם דומיין משלך — Resend על דומיין מאומת (SPF/DKIM/DMARC חובה) + Telegram להתראה מיידית.
- לא רוצה לכתוב backend — EmailJS + Telegram, שני HTTP calls מהדפדפן.
בכל מסלול: honeypot זה חובה, rate limit מומלץ, CAPTCHA רק כשבאמת חוטפים ספאם, וצ׳קבוקס הסכמה למדיניות פרטיות זה לא אופציונלי בישראל של 2026. ואל תשכח את מה שקורה אחרי שהליד נכנס — מעקב אוטומטי ללידים הוא ההבדל בין ליד שמתפספס לבין לקוח.
מקורות
- EmailJS Pricing — מכסות ותוכניות
- EmailJS — Can I use EmailJS for free? — פרטי המכסה החינמית
- Resend Pricing — תמחור רשמי
- Resend Account Quotas and Limits — מגבלות ופירוט
- Resend — Implementing DMARC — מדריך DMARC רשמי
- Telegram Bot API — תיעוד רשמי של Telegram
- Google Apps Script — POST endpoints — מדריך הקמת web app
- Best Free Form Backend Services 2026 — סקירה השוואתית
- SPF, DKIM, DMARC setup 2026 — מדריך deliverability מפורט
- חוק הספאם — כל זכות) — פירוט החוק והפיצויים
- תיקון 13 לחוק הגנת הפרטיות — מדריך לבעלי אתרים
- Cloudflare Turnstile — חלופה ל-CAPTCHA, חינמית
- react-email — תבניות אימייל ב-JSX
- react-hook-form + zod — ולידציה עם schema
רוצה שאני אקים לך את הצינור הזה (טופס + EmailJS + Telegram + Resend + הגנה מספאם + מדיניות פרטיות) ביום עבודה? דבר איתי ב-WhatsApp. בלי קסמים — רק קוד שעובד. 30 דקות שיחה חינם.