The Form Said Thanks. The Inbox Stayed Empty.
Photo: Google, Public domain, via Wikimedia Commons
It is, without much competition, the number one message a UK builder gets a fortnight after handover. "Someone filled in the contact form on Tuesday and we never got it. It says it sent, though."
The form is telling the truth, sort of. It submitted. What it can't tell you is whether the email survived the trip, because by the time it leaves PHP, everything is somebody else's problem — and one of those somebodies is a shared host that drops mail silently and logs nothing useful.
So this is a diagnostic, not a settings dump. Work down it in order and you'll find where the chain breaks.
Know the chain before you poke at it
Elementor Pro's form widget hands the submission to its own handler, which builds an email and passes it to WordPress's wp_mail() function. wp_mail() passes it to the server's PHP mail system. The host's mail transfer agent picks it up and sends it out to the recipient's provider, which decides whether it's legitimate.
Five links. Any of them can fail, and four of them fail silently. That's the whole reason this feels haunted.
Step 1: did the entry exist?
Before email, before DNS, before anything: go to Elementor's submissions screen in the WordPress dashboard and look for the entry.
This single check splits the problem in half.
If the entry is there — the form processed correctly and the failure is downstream. It's delivery. Skip to step 3.
If the entry isn't there — the form never completed. Something stopped the request before the handler ran. Usual suspects:
- A caching or security plugin blocking the admin-ajax request that forms use to submit.
- A honeypot field being autofilled by a browser extension or password manager on real humans.
- reCAPTCHA keys that are wrong for the domain, or a v3 score so low that everything is being treated as spam.
- A required field that fails validation only on certain devices — file uploads on iOS are a classic.
Test in a private window while logged out. Half of "the form is broken" reports are the client testing while logged in, triggering a spam rule aimed at logged-in users.
Step 2: check where it was meant to go
The recipient address in the form's actions-after-submit settings. This sounds insultingly basic until you find the client's old @btinternet.com address still sitting in there from the template you duplicated. Also check the subject line — some hosts treat very generic subjects as spam signals, and a subject full of emoji isn't helping anyone.
Then check the From address. Elementor lets you set the sender name and email. Default behaviour often uses an address on your own domain, which is correct — but only if that domain is authenticated. Set From to your domain and Reply-To to the visitor's email. Never the other way round, or you've built yourself a spoofing machine.
Step 3: the shared host problem
Here's the bit that explains most cases. On cheap shared hosting, PHP's mail() function is often a thin wrapper that gets the message as far as the local mail queue and then gives up. No bounce, no error, no log entry. The form returns success because PHP was satisfied.
Several UK budget hosts also restrict outbound mail, or throttle it, or block port 25 entirely to stop their IP ranges being used for spam. Ask support directly: "Is PHP mail() available, and is outbound SMTP on 587 permitted?" A one-line answer saves you an afternoon.
The fix is SMTP, and it's not optional on client sites. Install a dedicated SMTP plugin and route mail through a real provider — a transactional service, the host's own authenticated SMTP, or a Microsoft 365 / Google Workspace relay if the client already has one. Transactional providers are usually the better call: better logs, better deliverability, and a dashboard that shows you exactly what happened to a specific message.
Data residency is worth a thought here. If the client is UK-based and the form collects personal details, a provider with EU or UK processing regions keeps your privacy paperwork simple. Mention it before they ask.
Step 4: SPF, DKIM and DMARC on a normal cPanel setup
SMTP alone doesn't get you into the inbox. The receiving provider wants proof you were allowed to send.
SPF is a single TXT record on the sending domain listing who may send for it. Two rules: include your SMTP provider's include string, and have exactly one SPF record. Two records is a fail, and it's a mistake people make constantly when they migrate hosts and add a new one rather than editing the old.
DKIM is a key pair. Your provider gives you a TXT or CNAME record with a selector (something like selector._domainkey), you add it in DNS, and the provider signs each message. DKIM is the one that actually survives forwarding, so don't skip it.
DMARC is a TXT record at _dmarc telling receivers what to do when the first two fail. Start with p=none and a reporting address. Wait a fortnight. Read the reports. Then move to p=quarantine. Going straight to a hard reject policy on a domain that also sends ordinary business email is how you lose invoices.
Practical notes for UK hosts: the DNS editors at the big registrars and cPanel hosts all work slightly differently, and some have a habit of appending the domain to whatever you type in the name field. If your record ends up as _dmarc.example.co.uk.example.co.uk, that's why. Give propagation time, then verify with a public DNS checker rather than assuming.
Step 5: test like a stranger
The most common testing mistake is sending the test to your own inbox on the same server. That proves nothing — it can pass while every external delivery fails.
Do this instead:
- Send from a private window, logged out, to a Gmail address and a Microsoft address. Two providers, because they filter differently.
- Have someone on a different network submit the form.
- Open the received message and read the authentication headers. You want SPF, DKIM and DMARC all showing pass.
- Check the spam folder before you declare victory. Inbox placement is a separate problem from delivery, and a mildly spammy subject line or a link-heavy body will land you in Junk on a brand-new domain.
A brand-new domain with no sending history will be treated with suspicion for a few weeks regardless. Build that into expectations rather than fighting it.
Before you hand it over
A short checklist that prevents the post-launch ticket:
Spam protection. The honeypot is free, needs no third-party script and stops the bulk of dumb bots — it's the right default for a brochure site. reCAPTCHA v3 catches more, but it adds a script and a Google dependency, and in the UK it needs a mention in your cookie notice. Cloudflare Turnstile is a decent middle ground. Pick per site, not by habit.
Upload limits. Never promise a client a 25MB CV upload without checking PHP's upload_max_filesize and post_max_size first. Set the form's own limit comfortably below the server's, so a visitor gets a clear validation message rather than an unexplained failure.
Where entries go. Elementor stores submissions in the database, and that's your safety net — when mail fails, the entries are still there. Tell the client where to find them. Then agree a retention period and make sure the privacy policy matches it, because holding personal data indefinitely "in case" is a compliance problem waiting to happen.
Then send five real test submissions from five different addresses, on a real domain, after DNS has fully propagated. Not before. The number of sites that get signed off while a DKIM record is still resolving is genuinely depressing.