A Contact Form 7 setup usually fails quietly. The form posts, the green confirmation appears, the visitor walks away satisfied, and nothing arrives in the inbox. Or one person gets the notification and the person who should answer it does not. Or everything arrives for six months and then stops on the day the host changes its mail policy, and nobody notices until a customer calls to ask why they were ignored.
None of that shows up as an error. That is the part worth understanding before changing any settings, because it determines where to look. Contact Form 7 is a form renderer and a mail dispatcher. It is not a message store, and it is not a delivery system. Everything below follows from those two facts.
What the plugin actually does on submit
Contact Form 7 is the most installed form plugin on WordPress, with over ten million active installations. The current release at the time of writing is 6.1.7, and the plugin listing states that it requires WordPress 6.7 and PHP 7.4 or later.
Its own privacy notice on the WordPress.org plugin page is the clearest description of its behaviour: with the default configuration, the plugin, in itself, does not track users by stealth, write any user personal data to the database, send any data to external servers, or use cookies.
Read the second clause again. A submitted message is never written to the database. It is turned into an email, handed to WordPress, and forgotten. If the email does not arrive, the message does not exist anywhere. There is no outbox, no retry, no log to check. This single design decision causes most of the problems people are trying to solve when they search for configuration help.
The same notice lists the services that receive personal data when you switch on optional features: reCAPTCHA from Google, Akismet from Automattic, Constant Contact, Brevo, Stripe, and Turnstile from Cloudflare. Each of those is off until you enable it, which is useful to know when a compliance review asks what leaves the site.
The Mail tab, field by field
Open a form and the Mail tab holds six settings. Most broken setups are broken in one of the first two.
To. The recipient. It accepts several addresses separated by commas, which is how small teams usually handle shared coverage. Sending one notification to four people works, and it also means four inboxes now hold four copies of a message that only one person will answer.
From. This is where deliverability is decided. A common instinct is to put the visitor's address here, using the mail tag from the email field, so that hitting reply goes straight back to them. Doing that makes the site send mail claiming to be from an address on a domain it has no authority over. SPF and DMARC checks on the receiving side are designed to catch exactly that, and the result is a message that lands in spam or is rejected outright. The From address should be on your own domain. Put the visitor's address in Reply-To instead, inside Additional headers, and the reply behaviour you wanted still works.
Subject. Worth making specific. A subject of "Contact form submission" from every form on the site removes any chance of filtering or routing in the mail client later. Including the form name and a field value, such as the enquiry type, costs nothing and makes rules possible.
Additional headers. One header per line. Reply-To: [your-email] belongs here. So does Cc: or Bcc: if a second party needs a copy without appearing in the thread.
Message body. Plain text by default. Mail tags in square brackets are replaced with what the visitor typed. The stock contact form ships with [your-name], [your-email], [your-subject] and [your-message], and any field you add becomes a tag of the same name. If you add a field to the Form tab and forget to add its tag here, the field is collected and then discarded on the way out.
File attachments. Attaching uploads to the notification works, and it also means the file only exists inside an email. Large attachments are also a common cause of silent send failures.
Mail (2), the acknowledgement
Below the first template is a checkbox for a second mail, usually used to send the visitor a copy of what they submitted. Set To as [your-email], keep From on your own domain, and include the same field tags so the person has a record. It is the cheapest trust signal a contact form has, and it cuts down the follow-up messages asking whether anything was received.
There is a second benefit that is easy to miss. The acknowledgement is also a delivery test that runs on every real submission. If visitors stop reporting that they received a copy, the site's mail path has broken, and you find out from the traffic you already have rather than from a monitoring tool you have to remember to check.
Why mail goes missing even when the settings are right
WordPress sends mail through its wp_mail function, which by default hands the message to PHP's built-in mail transport on the web server. That server is almost never set up as a legitimate sender for your domain. It has no SPF alignment, it signs nothing with DKIM, and its IP address may be shared with hundreds of other sites, some of which are sending spam.
The fix is to stop sending from the web server. Route wp_mail through an authenticated SMTP connection or a transactional mail provider using one of the SMTP plugins, and set up SPF, DKIM and DMARC records for the domain you send from. Once that is in place, failures start producing bounce messages instead of silence, which is the real improvement.
Two more checks are worth doing on any form that has been running for a while. Open the raw headers of a notification that did arrive and look at the Authentication-Results line. It will tell you whether SPF and DKIM passed, and guessing about deliverability without reading that line wastes days. Then send a test to an address on a completely different provider from the one you use daily, because a message can pass on one and be filed as junk on another.
Spam handling, and the cost of each option
A public contact form collects bot traffic within days of going live. Contact Form 7 ships with no filtering switched on, so this is a deliberate choice rather than a default you inherit, and each option trades something away.
Akismet checks submissions against a central spam database. It is the least intrusive option for visitors, because there is nothing to click, and it is the most intrusive on privacy, because the submission content and the sender's IP address go to Automattic for scoring. Marking fields with the Akismet options in the form tag is what activates it.
reCAPTCHA v3 scores the visitor in the background rather than showing a challenge. That keeps the form clean, and it sends visitor data to Google on every page where the script loads, including pages with no form on them unless you restrict it.
Turnstile from Cloudflare covers similar ground with a different provider, which matters mainly if your compliance position already treats one of these companies differently from the other.
A honeypot field costs nothing and sends no data anywhere. It stops naive bots and does nothing against targeted submissions. It is a reasonable first step precisely because it has no downside to reverse.
The practical order is to start with the option that leaks the least, watch the volume for a fortnight, and escalate only if real spam is reaching people. Turning on the heaviest filter first means never learning whether it was needed, while permanently adding a third party to the data path.
Keep a copy of every submission
Given that the plugin stores nothing, the most valuable thing you can add to a Contact Form 7 setup is a record that survives a mail failure.
| Approach | What it gives you | What it costs |
|---|---|---|
| Notification email only | Nothing beyond the inbox it landed in | Any delivery failure loses the message permanently |
| Flamingo | Submissions listed and searchable in the WordPress admin | Personal data now sits in your site database |
| CFDB7 | Submissions saved to a database table, exportable as CSV | Same data exposure, plus a second plugin to maintain |
| A form tool with its own response store | Submissions held outside the site, with status per response | Moving the form off WordPress |
Flamingo is made by the same author and describes itself as a message storage plugin originally created for Contact Form 7, which does not store submitted messages. It has over 800,000 active installations. CFDB7 takes the same approach and reports over 600,000. Both note in their own listings that they store submitters' personal information in the database on the server that hosts the website, which is a real change to your data footprint and should be reflected in the site's privacy policy and retention practice.
Either one converts a lost email from a lost customer into an inconvenience. That alone justifies the install.
What configuration cannot fix
After SMTP is authenticated, tags are aligned, and a storage plugin is holding copies, a category of problem remains, and no amount of time in the Mail tab will touch it. It is the handling problem.
An email in a shared mailbox has no owner. Two people open it, both assume the other replied, and nobody did. Or one person replies from their own address, so the thread continues somewhere the rest of the team cannot see. There is no state on a message beyond read and unread, so "waiting on the customer" and "nobody has looked at this" appear identical in the list. When the same person submits three forms over two months, those are three unrelated emails rather than one history.
Adding recipients makes this worse rather than better, because responsibility spreads out until it belongs to no one. What the situation needs is a queue where each submission carries an owner and a stage, where the reply is sent from the same screen as the submission so the record stays whole, and where a returning person is recognised as the same person. That is a different category of tool from a form renderer, and it is worth looking at what response handling involves and the situations it tends to be used for before deciding whether the current setup is worth extending.
What to change first
Fix the From address to your own domain and put the visitor in Reply-To, then route mail through authenticated SMTP and confirm a real send passes SPF and DKIM. Install a storage plugin the same afternoon so that no future failure is silent. If the bottleneck turns out to be who answers rather than whether mail arrives, try the same intake on a tool that carries owners and stages natively, such as Halict.
Q1. Why does Contact Form 7 say the message was sent when no email arrives?
The plugin reports success once WordPress accepts the message for sending, not once a mail server delivers it. If the host's mail transport drops the message, or the receiving server rejects it for failing SPF or DMARC, the visitor still sees the green confirmation. Routing mail through authenticated SMTP is what makes failures visible as bounces instead of silence.
Q2. Can the From field be set to the visitor's email address?
It works technically, and it damages deliverability. Your site would be claiming to send on behalf of a domain it has no authority over, which is what SPF and DMARC are built to detect. Keep From on your own domain and add Reply-To: [your-email] under Additional headers to get the same reply behaviour.
Q3. Where are Contact Form 7 submissions stored?
Nowhere, by default. The plugin's own privacy notice states that with the default configuration it does not write any user personal data to the database. Submissions exist only as the emails it sends, which is why a storage plugin such as Flamingo or CFDB7 is usually added alongside it.
Q4. How many recipients should the notification go to?
As few as will guarantee someone sees it. Sending to four addresses feels safer but creates four copies of a message with no owner, which is the most common cause of a reply never being written. One monitored address, or a tool that assigns an owner per response, solves it more reliably than a longer To field.
Q5. Does adding reCAPTCHA or Akismet change what data leaves the site?
Yes. The plugin listing states that enabling these features may send the submitter's personal data, including their IP address, to the service provider. That applies to reCAPTCHA, Akismet, Constant Contact, Brevo, Stripe and Turnstile. Check each provider's privacy policy and reflect the choice in your own before switching one on.
