Why your form emails land in spam
An inquiry sitting in a spam folder is a lost inquiry. The most common cause is one line in your form settings. Then come the three DNS records every domain should have, what Gmail and Outlook have required since 2024 and the audit of our own domain, gap included.
An inquiry sitting in a spam folder costs more than an inquiry nobody wrote. The visitor made an effort, they are waiting for an answer and they hear nothing. Next time they write to somebody else.
The most common cause is one line in the form settings. After that come three DNS records every domain should have. In order.
The mistake that costs the most
Plenty of contact forms send their notification like this:
From: visitor@gmail.com
To: info@your-domain.com
It feels convenient, because you can reply straight from your inbox. To the receiving server it looks like this: a machine belonging to your-domain.com claims to be sending mail on behalf of gmail.com. Servers have been checking that claim for years, and Google publishes a strict policy for its own domain. The outcome ranges from a spam label to outright rejection.
The fix is to split sender from return address:
From: hola@primero.link
Reply-To: visitor@gmail.com
The sender stays a domain your server is allowed to send for. The visitor address goes in Reply-To, so hitting reply still reaches the right person. In our case that lives in the page header of the contact page:
email:
subject: 'Inquiry via primero.link: '
reply_to: ''
In a ready-made form plugin the setting usually sits under "From" and "Reply to". If the From field contains a placeholder like {email}, you have found the line that is costing you inquiries.
The three records
| Record | What it answers | Where it lives |
|---|---|---|
| SPF | Which servers may send for this domain? | TXT record on the domain |
| DKIM | Did this really come from there and arrive unaltered? | TXT record under selector._domainkey |
| DMARC | What should happen when a check fails, and where do reports go? | TXT record under _dmarc |
Two terms show up in every guide:
Alignment means the domain in the visible From line matches the domain that SPF or DKIM verified. A technically perfect signed delivery through a service provider still fails DMARC while the visible sender points somewhere else.
Policy is what DMARC recommends to the receiver: p=none to observe, p=quarantine for the spam folder, p=reject to refuse. The usual path starts at none, reads the reports for a few weeks and then tightens.
What the big mailboxes require
| Who | Since | What |
|---|---|---|
| Google, every sender | 1 February 2024 | SPF or DKIM, valid reverse DNS on the sending IP, TLS, spam rate under 0.3 percent |
| Google, from 5,000 messages a day | 1 February 2024 | SPF and DKIM and DMARC, alignment, one-click unsubscribe |
| Microsoft, from 5,000 messages a day to outlook.com, hotmail.com, live.com | 5 May 2025 | SPF and DKIM and DMARC with at least p=none |
Microsoft started in May 2025 by routing those messages to the junk folder. These days they get refused outright, with a code worth memorizing:
550 5.7.515 Access denied, sending domain does not meet
the required authentication level
The five thousand threshold sounds far away when a form triggers five inquiries a month. It is also the wrong number to watch. For a small sender the decision rests on the reputation of the domain, and passing authentication checks is how that reputation gets built.
New since May 2026
DMARC has a new edition. RFC 9989, 9990 and 9991 from May 2026 obsolete RFC 7489 and split the specification into three documents. Three changes touch records that already exist:
| Change | What it means for your record |
|---|---|
pct= is gone |
Percentage rollout has been removed. If you have pct=100 in there, drop it |
t=y arrives |
Test mode: the receiver applies the next milder step |
| Tree walk instead of a list | The responsible domain is found through DNS queries, up to eight levels |
np= arrives |
A separate rule for subdomains that do not exist, against invented senders |
The audit of our own domain
Checked on 19 September 2026, with the same three queries listed below.
| Check | Result | Verdict |
|---|---|---|
| SPF | v=spf1 mx a include:_spf.webhosting.systems ~all |
fine. The form sends through the same machine that receives our mail, which the mx mechanism covers |
| DMARC | v=DMARC1; p=quarantine; rua=…; ruf=…; fo=1; pct=100 |
policy in place, reports arriving. pct=100 has been pointless since May 2026 |
| DKIM | no answer under any of the common selectors | gap. The key is either missing or sitting under a selector we could not guess |
That last row is why this post exists. A domain on p=quarantine with no DKIM rests entirely on SPF. That holds while mail travels the direct path. It breaks the moment a message gets forwarded, because forwarding breaks SPF and leaves DKIM intact. So the next job on our own list is switching DKIM on in the server panel and verifying the record. The selector is readable afterwards in the headers of a message that actually went out.
The finding is a common one. Hosting packages tend to ship SPF preconfigured, DMARC is something you add yourself and DKIM is a switch in the control panel that nobody flipped.
A five minute check
dig +short TXT your-domain.com # SPF is the line starting v=spf1
dig +short TXT _dmarc.your-domain.com # DMARC
dig +short TXT default._domainkey.your-domain.com # DKIM, selector varies
The selector is the only tricky part. It gets assigned during setup and is called default, dkim, s1 or something else depending on the provider. The headers of a real message give it away: in Gmail, open "Show original" and look for DKIM-Signature, where s= holds the selector.
To test deliverability itself, send one message to a Gmail address and one to an Outlook address. Whatever lands in spam for you lands in spam for your customers.
What you can do today
- Check what your form sets as the sender. If it is the visitor address, switch it to your own and move the visitor into Reply-To.
- Have the form store a copy. A record on the server is the second trail that makes a failure visible. Every inquiry we get is saved as a file, separately from the email.
- Run the three queries above.
- Set DMARC to
p=nonewith a reporting address if nothing is there yet, read the reports for two weeks, then move toquarantine. - Send a test inquiry through your own form and see where it arrives. Once a quarter is a good rhythm.
If you want to know whether inquiries from your site are arriving reliably: drop us a line with your domain. We will look at the three records and tell you what is missing.
Sources
How current this post is
Unchanged in substance since it was published.
Common questions about deliverability
Why can the form not use the visitor address as the sender?
Because your server is then claiming to write on behalf of a domain that belongs to somebody else. The receiving server checks whether your server is allowed to send for that domain, and the answer is no. With a strict DMARC policy on the visitor domain, the message gets quarantined or rejected. The fix is to keep your own address as the sender and put the visitor address in Reply-To. Replying still works with one click.
What is the difference between SPF, DKIM and DMARC?
SPF lists the servers allowed to send for your domain. DKIM signs every message with a key whose public half sits in DNS, which proves the message came from you and arrived unaltered. DMARC ties both to the visible From address and tells the receiver what to do when the check fails. Without DMARC, SPF and DKIM are two tests with no consequence attached.
Do I need this for five emails a month?
Yes, for a different reason than a newsletter sender. Google has required at least SPF or DKIM from every sender since 1 February 2024. More important day to day: a low volume domain has no reputation for a filter to lean on, so authentication carries more weight for you than for a sender pushing a thousand messages a day.
What does the tilde in ~all mean?
Softfail. Messages from servers that are absent from your list should be accepted and marked as suspicious. The stricter -all means hardfail, so reject. Softfail is the usual starting point because a forgotten sending path still gets through. Once you are sure you know every path, move to -all.
What changed for DMARC in 2026?
RFC 9989, 9990 and 9991 were published in May 2026 and obsolete RFC 7489. Three things matter in practice. The pct= tag is gone, replaced by t=y for test mode. The responsible domain is now found by walking up the DNS tree instead of consulting a maintained list. And np= lets you set a separate rule for mail claiming to come from subdomains that do not exist.
How would I even notice that inquiries are going missing?
Most reliably by having the form store a copy. If an inquiry sits in your records and the matching email never arrived, you have proof. Without that second trail you find out when a customer asks why nobody replied.