TL;DR
The form works, the lead saves to the database, but the confirmation email lands in spam — in 2026 the usual causes are missing SPF, DKIM and DMARC records and sending from a domain that does not authorize the application server. Below is a practical guide for Next.js sites: from DNS to testing, with record examples and a post-launch checklist on DevStudioIT Cloud with submissions stored in Branchly.
Who this is for
- Companies whose customers do not receive contact form confirmations
- Developers configuring SMTP (Resend, Brevo, SendGrid, own Postfix)
- Marketing worried that “CRM replies also go to spam”
- Domain owners who see “Unauthenticated” next to mail in Gmail
Keyword (SEO)
spf dkim dmarc contact form, transactional email deliverability, website emails going to spam, email dns configuration 2026
Three pillars of authentication — what each does
| Mechanism | Layer | Question it answers |
|---|---|---|
| SPF | DNS TXT | Is this SMTP server allowed to send mail for the domain? |
| DKIM | DNS TXT + header signature | Was message content altered after sending? |
| DMARC | DNS TXT | What to do on SPF/DKIM fail — report, quarantine or reject? |
Without SPF and DKIM, Gmail and Outlook since 2024–2026 filter more aggressively. Bulk marketing is a separate topic — here we focus on transactional mail: form confirmation, admin copy, password reset, invoice PDF.
Typical form flow on a corporate site
- User submits form on
example.com - Route Handler (Next.js) validates, saves lead to Branchly (branchly.cloud)
- Server calls mail provider API (e.g. Resend) with
From: contact@example.com - Provider sends via its SMTP infrastructure
- Recipient mailbox checks SPF/DKIM/DMARC for
example.com
Problem: step 4 uses provider IPs not listed in the domain SPF → soft fail → spam folder.
Apps on DevStudioIT Cloud (devstudioit.cloud) do not send mail “directly from Node” in production — we use a transactional provider API with correct DNS. More stable than open port 25 on a VPS.
SPF — sample record
One domain, Resend as provider:
; DNS TXT for example.com
example.com. IN TXT "v=spf1 include:amazonses.com include:_spf.resend.com ~all"Rules:
- One SPF record per domain (combine includes)
~all= soft fail during migration; target-allhard fail- Include every provider (Google Workspace for office mail ≠ Resend for transactional — often one SPF with multiple includes)
After DNS change wait for propagation (up to 48 h) and test:
dig TXT example.com +shortDKIM — selector and record
Provider generates keys; add CNAME or TXT in DNS:
; Resend example
resend._domainkey.example.com. IN CNAME xxx.dkim.resend.com.Mail header shows DKIM-Signature: v=1; a=rsa-sha256; d=example.com; s=resend; .... Selector s= must match DNS. Key rotation yearly or after incident; providers often offer a second selector for zero-downtime rotation.
DMARC — policy and reports
Start with monitoring, not immediate reject:
_dmarc.example.com. IN TXT "v=DMARC1; p=none; rua=mailto:dmarc-reports@example.com; pct=100; adkim=s; aspf=s"After 2–4 weeks of XML reports (rua):
p=quarantine— suspicious mail to spamp=reject— target for production domains sending only via authorized sources
DMARC requires alignment: From: domain must align with SPF or DKIM domain (strict aspf=s; adkim=s hardens against spoofing but demands disciplined config).
From, Reply-To and content — deliverability traps
| Mistake | Effect | Fix |
|---|---|---|
From: noreply@gmail.com |
No trust | From: contact@yourdomain.com |
| Missing Reply-To | Replies go nowhere | Reply-To: sales@example.com |
| HTML-only, no plain text | Spam filters | multipart/alternative |
| Links to unknown domains | Lower score | links on own domain |
| No List-Unsubscribe | Worse marketing delivery | required for newsletters |
Form emails should include context: “We received your submission from example.com on …” — distinguishes transaction from phishing.
Next.js implementation — fragment
// lib/mail/send-contact-confirmation.ts
import { Resend } from 'resend';
const resend = new Resend(process.env.RESEND_API_KEY);
export async function sendContactConfirmation({
to,
name,
locale,
}: {
to: string;
name: string;
locale: 'pl' | 'en' | 'de';
}) {
const from = 'DevStudio.it <contact@devstudioit.com>';
await resend.emails.send({
from,
to,
replyTo: 'hello@devstudioit.com',
subject: locale === 'en' ? 'Submission received' : 'Potwierdzenie zgłoszenia',
text: `Hi ${name},\n\nWe received your submission.\n\nDevStudio.it team`,
html: `<p>Hi ${name},</p><p>We received your submission.</p>`,
});
}API keys live in env on DevStudioIT Cloud, not in the repo. Log provider message IDs alongside submissions in Branchly — helps support for “mail did not arrive”.
Post-launch testing
- mail-tester.com — one-off score /10
- Gmail — “Show original” → SPF PASS, DKIM PASS, DMARC PASS
- Microsoft Message Header Analyzer — for Outlook
- Test inboxes: Gmail, Outlook, regional providers
- Monitor bounce and complaint rate at provider (>0.1% complaints = reputation issue)
FAQ
Is SPF enough without DKIM?
Not in 2026 — most large providers require both. DMARC without SPF/DKIM alignment adds little value.
Can I send with @gmail.com via API?
No — use your own domain with verified DNS. Gmail as From through Resend/SendGrid still fails SPF.
What about internal admin notifications?
Same DNS stack — From: forms@example.com, To: office@example.com. If office uses Google Workspace, SPF must include Google and the transactional provider.
Will DMARC p=reject break forwards?
Yes — forwards can break alignment. Consider a subdomain for transactional: notify.example.com with its own DMARC.
CTA
Form saves leads but mail disappears? We configure DNS, sending and deliverability monitoring.
- Report a mail issue — SPF/DKIM/DMARC audit for your domain
- Websites — forms, Branchly, DevStudioIT Cloud hosting
About the author
We build fast websites, web/mobile apps, AI chatbots and hosting setups — with a focus on SEO and conversion.
Recommended links
From theory to production — Branchly, our hosting stack and shipped work.
