I'll start with my own, because it's the most useful example I have.
Last year the contact form on this site — a site I built, belonging to a developer who sells websites for a living — was returning a server error when it tried to send. The endpoint reported send_failed and nothing else. No detail about which part failed, no way to tell a bad API key from an unverified sending domain except by guessing and redeploying.
Meanwhile the form on the page looked completely normal.
If it can happen here, it is certainly happening on sites where nobody reads server logs for fun. So this is the specific list of ways a contact form loses leads without ever telling you.
Why the failure is always silent
Every other broken thing on a website announces itself. A dead page 404s. A broken image leaves a gap. A payment failure produces an angry customer.
A broken contact form produces nothing at all. The visitor submits, sees a thank-you message, and leaves satisfied. You see an empty inbox, which is indistinguishable from an ordinary quiet week.
Both parties believe the system worked. That's what makes this failure mode expensive — it can run for months, and the only symptom is a vague sense that the website "doesn't really bring in enquiries".
Failure 1: The credential that only exists on the developer's laptop
The most common one, and the cause of my own.
API keys are deliberately kept out of source code. They live in environment variables, set separately in each place the site runs. Which means there are two environments — the developer's machine and production — and the key can easily exist in only the first.
Locally, the form works perfectly. In production, the key is undefined, and what happens next depends entirely on how the code was written. Which brings us to the more interesting failure.
Failure 2: The helpful fallback that eats leads
Here's a pattern that appears in a lot of codebases, including mine. If the mail service isn't configured, don't show the user an error — fall back to opening their email client with the message pre-filled.
It's thoughtful. It is also, in practice, a lead shredder:
- Many people have no mail client configured at all, particularly on desktop. The link does nothing.
- Of those who do get a draft window, a large share never press send — the flow broke, and they were only mildly interested anyway.
- Nothing is logged. From your side, the visitor simply never existed.
The lesson isn't "never build a fallback". It's that a fallback which cannot be observed is worse than an error you'd have noticed. If you have one, it must record that it fired. A fallback firing a hundred times a month is a five-alarm signal — and if it's silent, it looks exactly like nobody visiting.
Failure 3: The error that was thrown away
This was the one I actually fixed, and it's worth describing precisely because the shape is so common.
The endpoint called the mail provider. When the provider rejected the send, the code returned a bare "send failed" and discarded the provider's response body — which is exactly where the reason lives. The provider had been perfectly clear. Its answer said things like domain is not verified, or invalid api key, or from address not allowed. My code caught all of that and threw it in the bin.
The result: every possible failure looked identical from the outside. A wrong key, an unverified sender domain and a permissions problem all produced the same useless message, and the only way to diagnose it was to guess, change something, redeploy and see.
The fix took a few lines:
- Log the full status and response body to the server console, where the hosting platform captures it.
- Return only the status code to the browser — enough to distinguish an auth failure from a sender-validation failure, without exposing a provider's internals to a visitor.
- Log in the catch branch too. A network failure reaching the provider had also been completely silent.
That last point is the general principle: an empty catch block is a decision to never find out. Handle the error, by all means — but write it down on the way past.
Failure 4: The mail sends, and lands in spam
Now the form is working, the provider accepts the send, everything reports success — and the message quietly lands in a spam folder.
The usual cause is a form that sends mail appearing to come from the visitor's own address. It seems convenient, because then reply just works. But you are now sending mail claiming to be from a domain you don't control and can't authenticate, which is precisely the pattern spam filters exist to catch.
The correct pattern:
- From: an address on your own verified domain.
- Reply-To: the visitor's address, so replying still works normally.
- SPF, DKIM and DMARC configured for your domain. Providers increasingly treat unauthenticated mail as suspicious by default rather than as a tiebreaker.
And check the spam folder during testing. A test you scored as a pass because "it didn't error" is not a pass.
Failure 5: Your own spam defence eating real enquiries
Forms need bot protection — leave one open and it fills with junk. But over-aggressive filtering rejects real people, and rejects them silently.
The honeypot approach is my preference: an input field hidden from humans, which bots fill in anyway. Anything with a value in it is a bot. Crucially, return success to the bot rather than an error, so it believes it worked and moves on instead of retrying.
Where this goes wrong is aggressive keyword or scoring rules. A genuine enquiry mentioning a budget, a URL and a deadline can look statistically spammy. If you filter, log what you rejected and read it occasionally.
How to actually prove your form works
Not "it looks fine". Prove it:
- Submit from a phone on mobile data, using an email address with no connection to your business. Not your office wifi, not your own laptop.
- Check the inbox and the spam folder. Both.
- Check the server logs for that submission. If nothing was logged, you have no visibility — fix that before anything else.
- Compare traffic to enquiries. Open analytics, find how many people reached your contact page last month, and compare with what you received. A large gap is a plumbing problem, not a marketing one.
- Put it in the calendar. Monthly. Forms almost never break on launch day — they break in month seven when a credential expires.
The real lesson
Before you spend money on advertising to fix "we don't get enquiries", spend twenty minutes proving the enquiry path works end to end. I've watched businesses conclude their website was useless when the truth was that every message it generated had been landing in a spam folder nobody opened.
More traffic through a broken form produces exactly as many leads as you're getting now. The other five reasons Indian business websites don't generate leads are worth reading too — but check the plumbing first, because it's the cheapest thing on the list and the most likely to be the whole answer.
I'm Divyansh Sood, a freelance developer in Himachal Pradesh. I published my own broken form because the useful posts are the ones written by people who got it wrong first. If you want yours checked, the free audit includes an end-to-end test of the enquiry path — and I'll tell you plainly if the problem is traffic rather than plumbing.