The safest model for integrating a form with a CRM and e-mail looks like this: the form sends data to your own backend, the backend validates the payload, maps fields, saves the lead in the CRM, triggers a transactional e-mail, and leaves a technical log. This keeps tokens out of the frontend and gives the company control over errors, deduplication, consents, and monitoring.
The quickest answer is: How to connect a website form to a CRM and email?
A practical guide to integrating a website form with a CRM and email: webhook, REST API, Make, Zapier, SMTP relay, RODO, and monitoring.
Why is the inbox alone not enough?
The most common problem is not that the form on the website does not work. The problem starts shortly after: the lead lands in an inbox, someone manually copies the data into the CRM, marketing cannot see the contact source, the sales representative responds late, and in the meantime some information disappears or goes to the wrong person.
A proper integration between a website form, CRM, and e-mail should do three things at the same time. First, save the contact in the CRM with field mapping and the lead source. Second, trigger an e-mail confirmation or a team notification. Third, leave a technical trace: a log, a status, and a way to check what happened if something goes wrong.
What should a correct data flow look like?
It is not advisable to connect the frontend directly to the CRM, because that can easily expose business logic, field scope, and tokens. A better pattern is to use your own backend or integration endpoint that receives the data, checks consent, maps fields, and only then calls the CRM and e-mail APIs.
What really needs to be designed is the data map. Which fields are required? Which go to the contact, which to the lead or sales opportunity, and which only to a note? Without defining the source of truth, the integration may only accelerate the chaos.
- Form
The user enters their data, subject, message, and operational consent.
- Validation
The frontend and backend check required fields, e-mail format, and content length.
- Backend
The endpoint hides tokens, normalizes data, and assigns a request ID.
- CRM
The system creates or updates a contact, lead, deal, or note.
- E-mail
An SMTP relay or ESP sends a confirmation to the customer and a notification to the team.
- Logs
The integration records statuses without excessive personal data.
- Alert
A 429 or 500 error, or a failed email delivery, triggers a notification.
- Report
The team sees the lead source, response time, status, and form performance.
What should be mapped between the form and the CRM?
| Field | Where it goes | Why it matters |
|---|---|---|
| first and last name | contact in CRM | helps personalize the response and assign the relationship |
| contact, deduplication, reply-to | the most important lead identifier and response channel | |
| phone | contact or lead | enables a callback for urgent inquiries |
| company | organization or contact property | helps qualify B2B and assign a segment |
| subject | lead, deal, tag, or pipeline | enables routing to the right person |
| message | CRM note or activity | preserves the inquiry context |
| page source and UTM | marketing properties | allows you to measure Google and Bing channels, campaigns, and content |
| consent and timestamp | consent record or submission metadata | supports accountability and GDPR handling |
Integration via webhook
A webhook is best when the form or middleware tool can send an HTTP event immediately after submission. It works well for forms such as: schedule a demo, request a quote, we will call you back, or download a resource.
The webhook should go to your endpoint or automation platform, not directly to the CRM without control. This lets you perform validation, deduplication, field mapping, and error handling. Livespace describes webhooks as a way to pass events in real time to external systems, while Zapier and Make are common tools for receiving such events.
Integration via REST API
A REST API is the best choice when you want full control over what goes into the CRM. You can first check whether the contact already exists, add custom properties, assign an owner, create a note, a separate sales opportunity, or a follow-up task.
HubSpot documents creating CRM contacts through the API and authentication through OAuth or private app tokens. Pipedrive provides an API for contacts, leads, deals, and activities. A custom endpoint has one more advantage: if you change your CRM in six months, the form can still send the same JSON, and you only change the adapter on the backend side.
Integration via Make or Zapier
If you need a fast MVP without a large amount of code, Make or Zapier is a reasonable path. Zapier promotes integrations with thousands of applications, and Make has an extensive ecosystem of ready-made modules, webhooks, and scenarios. With popular CRMs, you can build a form -> CRM -> email -> Slack flow in hours or days.
No-code has limits, however. You need to manage run history, queues, retries, delays, webhook limits, and operation costs. Zapier documents throttling and the 429 status when webhook limits are exceeded, and Make shows support for webhooks, queues, and logs. For critical processes, it is worth having monitoring outside the platform itself.
| Option | Best scenario | Limitation |
|---|---|---|
| Custom backend + API | sensitive data, multiple forms, deduplication, custom logic, ability to change CRM | requires development, testing, and maintenance |
| Make | quick MVP, popular SaaS tools, clear scenarios, webhooks, operational integrations | costs and limits increase with the number of operations |
| Zapier | simple marketing automations and a broad app catalog | at higher volume, you need to monitor rate limits and task history |
| WordPress plugin | form on WordPress, simple process, managed by marketing | less control over logic and migration between CRMs |
Sending emails via SMTP or SMTP relay
Email after a form submission usually covers two scenarios. The first is a transactional message: thank you, we will be in touch. The second is marketing communication, such as a newsletter. These two should not be mixed, either legally or technically.
SMTP is still a good standard, but in production it is better to use a relay or a transactional email provider rather than a regular private account. Google Workspace recommends SMTP relay for applications and devices, and Nodemailer identifies SMTP as a universal transport that lets you change providers by updating the configuration.
<p>Dziękujemy za wiadomość.</p>
<p>Otrzymaliśmy Twoje zgłoszenie i wrócimy z odpowiedzią w ciągu 1 dnia roboczego.</p>
<p>Jeśli sprawa jest pilna, odpowiedz na tę wiadomość.</p>
<p>Pozdrawiamy,<br>Zespół SmartCodeIT</p>JavaScript and Node.js integration example
The example below shows an architectural pattern, not ready-to-paste code that can be used without adjustment. The frontend sends data to its own endpoint, and the backend creates a contact in HubSpot and sends a confirmation e-mail via SMTP.
const form = document.querySelector("#lead-form");
form.addEventListener("submit", async (event) => {
event.preventDefault();
const payload = Object.fromEntries(new FormData(form).entries());
const response = await fetch("/api/lead", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload)
});
if (response.ok) {
form.reset();
alert("Dziękujemy! Otrzymaliśmy Twoje zgłoszenie.");
} else {
alert("Nie udało się wysłać formularza.");
}
});import express from "express";
import nodemailer from "nodemailer";
const app = express();
app.use(express.json());
app.post("/api/lead", async (req, res) => {
const email = String(req.body.email || "").trim();
const consent = req.body.consent === true || req.body.consent === "on";
if (!email || !consent) {
return res.status(400).json({ error: "Brakuje e-maila lub wymaganej zgody." });
}
const crmResponse = await fetch("https://api.hubapi.com/crm/v3/objects/contacts", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.HUBSPOT_TOKEN}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
properties: {
email,
firstname: String(req.body.firstname || "").trim(),
lastname: String(req.body.lastname || "").trim(),
lead_source_detail: "formularz-strony"
}
})
});
if (!crmResponse.ok) {
return res.status(502).json({ error: "CRM odrzucił zgłoszenie." });
}
const transporter = nodemailer.createTransport({
host: process.env.SMTP_HOST,
port: Number(process.env.SMTP_PORT || 587),
secure: false,
auth: { user: process.env.SMTP_USER, pass: process.env.SMTP_PASS }
});
await transporter.sendMail({
from: process.env.MAIL_FROM,
to: email,
subject: "Dziękujemy za kontakt",
html: "<p>Dziękujemy za wiadomość. Wrócimy z odpowiedzią w ciągu 1 dnia roboczego.</p>"
});
return res.status(201).json({ ok: true });
});PHP integration example
In PHP, a similar pattern can be built with cURL and PHPMailer. PHPMailer supports SMTP and UTF-8, which matters for Polish characters in forms and messages.
<?php
require __DIR__ . '/vendor/autoload.php';
use PHPMailer\PHPMailer\PHPMailer;
$email = filter_var($_POST['email'] ?? '', FILTER_VALIDATE_EMAIL);
$consent = isset($_POST['consent']);
if (!$email || !$consent) {
http_response_code(400);
echo json_encode(['error' => 'Brakuje e-maila lub wymaganej zgody.']);
exit;
}
$payload = [
'properties' => [
'email' => $email,
'firstname' => trim($_POST['firstname'] ?? ''),
'lastname' => trim($_POST['lastname'] ?? ''),
'lead_source_detail' => 'formularz-strony'
]
];
$ch = curl_init('https://api.hubapi.com/crm/v3/objects/contacts');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('HUBSPOT_TOKEN'),
'Content-Type: application/json'
],
CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_UNICODE)
]);
$crmBody = curl_exec($ch);
$crmStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($crmStatus < 200 || $crmStatus >= 300) {
http_response_code(502);
echo json_encode(['error' => 'CRM odrzucił zgłoszenie.']);
exit;
}
$mail = new PHPMailer(true);
$mail->isSMTP();
$mail->Host = getenv('SMTP_HOST');
$mail->Port = (int) (getenv('SMTP_PORT') ?: 587);
$mail->SMTPAuth = true;
$mail->Username = getenv('SMTP_USER');
$mail->Password = getenv('SMTP_PASS');
$mail->CharSet = 'UTF-8';
$mail->setFrom(getenv('MAIL_FROM'), 'SmartCodeIT');
$mail->addAddress($email);
$mail->Subject = 'Dziękujemy za kontakt';
$mail->Body = 'Dziękujemy za wiadomość. Wrócimy z odpowiedzią w ciągu 1 dnia roboczego.';
$mail->send();
http_response_code(201);
echo json_encode(['ok' => true]);Form-to-CRM plugins for WordPress
If the site runs on WordPress, you do not always need to start with custom code. Contact Form 7 is a good option for limited budgets and custom code, Gravity Forms for agency implementations and professional integrations, WPForms for convenient marketing operations, and Fluent Forms as a strong feature-to-price compromise.
Choose plugins when implementation speed and maintenance by marketing are the priority. Choose custom code when you have multiple forms, non-standard logic, custom statuses, or a need to migrate between CRMs.
Security, GDPR, testing, and monitoring
GDPR requires not only a legal basis, but also transparency, data minimization, security, and accountability. The form should collect only the fields needed for the first contact, separate operational communication from marketing communication, and store proof of consent where consent is the basis for processing.
In practice, you need to test validation, CRM responses, 4xx and 5xx errors, retry logic, duplicates, e-mail deliverability, and scenario monitoring. If a webhook or API returns 429, the integration should retry with backoff instead of silently losing the lead.
- keep CRM and SMTP tokens only on the server side
- store submission_id, timestamp, source_url, and integration status
- do not log full payloads containing personal data unless necessary
- separate the confirmation e-mail from the marketing newsletter
- add alerts for CRM, SMTP, and webhook errors, as well as limit overruns
- check deduplication by e-mail, external_id, or phone number
| Issue | Typical cause | What to check first |
|---|---|---|
| Lead does not reach the CRM | incorrect field name, missing scope, invalid token | API response log, HTTP status, application permissions |
| Form creates duplicates | no deduplication by email or external_id | find-or-create logic and source mapping |
| Email is not delivered | incorrect SMTP auth, From, or domain | relay/ESP, SPF, DKIM, DMARC, delivery log |
| No-code scenario runs unreliably | limits, no queues, or connection errors | run history, webhook logs, retry |
| API returns 429 | rate limiting on the CRM or intermediary side | backoff, batching, plan limits |
| Consent issue | marketing checkbox linked to inquiry handling | separate the contact basis from marketing consent |
Summary
If you want a fast solution, choose a form with a webhook and a scenario in Make or Zapier. If you want full control, a custom backend and the CRM REST API will be better. If you work on WordPress and want to shorten implementation, use a good form plugin with a webhook or CRM integration.
Regardless of the path, three principles remain constant: the backend as an intermediate layer, a separate transactional email mechanism, and monitoring of the entire flow. SmartCodeIT can design this type of MVP, connect forms to CRM and email, and add conversion analytics so leads do not get lost between tools.
FAQ
What is the best way to connect a form to a CRM?
The safest model is a form that sends data to the backend, and only then does the backend pass it to the CRM through an API or webhook. This keeps tokens and business logic out of the frontend.
Can Make or Zapier be used instead of code?
Yes, especially for MVPs and simple workflows. However, you need to manage limits, run history, retries, operation costs, and error monitoring.
Should a form send data directly to the CRM?
Usually not. A direct frontend connection to the CRM can expose tokens and make validation, deduplication, and error handling more difficult.
How can you avoid duplicate leads in the CRM?
It is worth using find-or-create logic based on email, phone, or external_id, and storing the submission_id and form source.
Does a confirmation email require marketing consent?
No, if it is an operational message related to handling the submission. Marketing consent is a separate process and should not be combined with the form confirmation.
What should be measured after integrating a form with a CRM?
First response time, the number of leads saved in the CRM, API errors, duplicates, email deliverability, lead sources, and conversion from form submission to consultation.
Does WordPress have ready-made CRM plugins?
Yes. WPForms, Gravity Forms, Fluent Forms, and Contact Form 7 can support webhooks or CRM integrations, depending on the plan and add-ons.
What data is needed for implementation?
The list of forms, fields to map, selected CRM system, email addresses, consent requirements, traffic sources, people responsible for leads, and error handling rules.
Can SmartCodeIT implement this type of integration?
Yes. SmartCodeIT can prepare the backend, webhooks, CRM integration, transactional emails, monitoring, tests, and conversion analytics.
Sources
- Google Search Central: AI features and your website
- HubSpot Developers: authentication
- HubSpot Developers: CRM contacts API
- Pipedrive API reference
- Pipedrive usage limits
- Livespace: webhooks in CRM
- Livespace API
- Zapier: Webhooks rate limits
- Make Help: webhooks
- Nodemailer: SMTP transport
- Google Workspace: SMTP relay
- PHPMailer GitHub
- UODO: rights under the GDPR
- UODO: information obligation
- ISAP: Electronic Communications Law
Do you want to connect your website forms with CRM, email, and conversion analytics? SmartCodeIT can design a secure endpoint, data mapping, monitoring, and the first working lead flow.
Schedule a CRM integration consultation