WordPress Email + Contact Form Anti‑Spam (All‑Free) Playbook
Stack: Brevo (Free) + FluentSMTP (Free) + WPForms Lite (Free) + Cloudflare Turnstile (Free)
Goal: Reliable outbound email delivery (form notifications, password resets) + strong inbound spam protection, using only free tools.
0) What you’re building (mental model)
Flow
- Visitor submits your WPForms Lite contact form
- Turnstile blocks bots / verifies humans
- WPForms triggers email notifications using WordPress
wp_mail() - FluentSMTP intercepts
wp_mail()and sends via Brevo Email API (v3) (not “basic SMTP login”) - Brevo delivers mail with your domain authenticated (SPF/DKIM/DMARC)
Why this stack
- No Google Workspace app passwords stored in WordPress (API key instead)
- Brevo Free supports transactional emails and includes 300 email sends/day (daily reset, no rollover)
- FluentSMTP includes Email Logs (useful for troubleshooting and keeping a local “copy” of notifications)
Sources: Brevo free limits/transactional access (https://help.brevo.com/hc/en-us/articles/208580669-FAQs-What-are-the-limits-of-the-Free-plan), Brevo plans overview (https://help.brevo.com/hc/en-us/articles/208589409-About-Brevo-s-pricing-plans), FluentSMTP email logs (https://fluentsmtp.com/docs/fluentsmtp-email-logs-feature/)
1) Prereqs (do these first)
You need
- Admin access to WordPress
- Access to your domain’s DNS records (where you manage TXT/CNAME)
- A dedicated sender address you’ll use for WordPress, recommended:
wordpress@yourdomain.comornoreply@yourdomain.com
- A place to store secrets (password manager)
Strongly recommended (security)
- Enable 2FA on WordPress admin accounts
- Enable 2FA on Brevo
- Use an admin email that isn’t public
2) Brevo setup (account → domain auth → sender → API key)
2.1 Create your Brevo account
- Sign up for Brevo
- Verify your email
- Turn on 2FA (recommended)
2.2 Authenticate your domain in Brevo (SPF + DKIM + DMARC)
This is the deliverability “make-or-break” step.
- In Brevo, go to Settings → Senders, Domains & Dedicated IPs → Domains
- Click Add a domain
- Brevo will show you DNS records to add, typically:
- Brevo code (TXT) — domain ownership verification
- DKIM records (CNAME/TXT depending on DNS provider) — email signing
- DMARC record (TXT) — policy + reporting
Follow Brevo’s official “Authenticate your domain” guide for your DNS provider UI:
https://help.brevo.com/hc/en-us/articles/12163873383186-Authenticate-your-domain-with-Brevo-Brevo-code-DKIM-DMARC
DNS nuance: SPF “one record only” (merge, don’t add a second)
- Each domain can have only one SPF record; it can include multiple services.
Google: https://support.google.com/a/answer/10683907 - If you already have Google Workspace SPF, Google’s “only Workspace” record is:
v=spf1 include:_spf.google.com ~all
Source: https://support.google.com/a/answer/33786
✅ Correct approach: merge Brevo’s SPF include into your existing SPF record.
Brevo will show you the exact include to use (commonly include:spf.brevo.com, but copy what Brevo gives you).
Example (if you use Workspace + Brevo):
v=spf1 include:_spf.google.com include:spf.brevo.com ~all(Your real record may differ; always use the include Brevo provides.)
Extra SPF guidance: multiple SPF records fail SPF checks and should be merged into one (https://mailtrap.io/blog/multiple-spf-records/)
DNS nuance: DMARC “one record per domain/subdomain”
Keep one DMARC record per domain/subdomain; do not create duplicates (or DMARC can break).
Example guidance: https://dmarcly.com/blog/can-i-have-multiple-dmarc-records-on-my-domain
Practical DMARC best practice (safe rollout):
- Start with
p=none(monitoring) and review reports before tightening later.
Note: Brevo will provide a DMARC record value; if you already have DMARC, you’ll need to combine reporting addresses (rua) into the single record instead of creating a second DMARC record.
2.3 Verify a Sender email in Brevo (“From Email”)
Brevo expects you to send “From” an email identity you’ve set up.
- In Brevo go to Settings → Senders, Domains & Dedicated IPs → Senders
- Add a sender:
- From email:
wordpress@yourdomain.com - From name: Your brand name
- From email:
- Complete the email verification step (Brevo sends a verification email)
2.4 Create a Brevo API key (v3) for WordPress
- In Brevo: Settings → SMTP & API → API Keys
- Click Generate a new API key
- Name it something obvious:
wp-prod-fluentsmtp
- Copy it and store it in your password manager
Brevo API key guide: https://help.brevo.com/hc/en-us/articles/209467485-Create-and-manage-your-API-keys
Brevo API auth concept (header is api-key): https://developers.brevo.com/docs/how-it-works
Security best practices
- One key per integration (so you can rotate/revoke safely)
- If compromised: deactivate the key immediately (Brevo supports deactivate/reactivate)
3) WordPress setup (plugins + sending + logging)
3.1 Install the plugins
In WordPress Admin → Plugins → Add New:
- Install + Activate WPForms Lite
- Install + Activate FluentSMTP
3.2 Configure FluentSMTP → Brevo connection (API method)
- WordPress Admin → FluentSMTP → Settings
- Add Connection → choose Brevo
- Fill the fields:
- From Email:
wordpress@yourdomain.com
Must be a sender you verified in Brevo. (FluentSMTP’s Brevo doc)
https://fluentsmtp.com/docs/setting-up-sendinblue-mailer-in-fluent-smtp/ - From Name: e.g., “Solanasis”
- API Key: paste your Brevo API key
- From Email:
- Save
- Send a Test Email from FluentSMTP
3.3 Turn on FluentSMTP Email Logs (optional but recommended)
Why: it gives you a local record of outgoing emails and delivery status (helpful for troubleshooting and as a “copy” of contact submissions).
- FluentSMTP → Email Logs (or Settings → enable logging depending on version)
- Confirm you can see test emails in the log
Docs: https://fluentsmtp.com/docs/fluentsmtp-email-logs-feature/
Privacy note: email logs can contain message content (names/emails/messages).
Only admins should have access.
4) WPForms Lite setup (form + notifications + “store a copy” options)
4.1 Create your contact form
WPForms → Add New
- Choose “Simple Contact Form” template (or blank)
- Recommended fields:
- Name
- Message
- Optional: “Company”, “Phone” (only if you need them)
4.2 Notification email settings (critical deliverability best practice)
WPForms → your form → Settings → Notifications
Set:
- Send To Email Address: your receiving inbox (e.g.,
hello@yourdomain.com) - From Name: your brand name
- From Email:
wordpress@yourdomain.com✅ (same verified sender) - Reply-To: the visitor’s email field (so you can reply directly)
Why this matters:
- If you set “From Email” to the visitor’s email, many systems will fail DMARC alignment and your mail may be rejected or spam-filtered.
4.3 “Store a copy” of submissions on the WordPress site (free options)
WPForms Lite does not store entries in your WordPress database by default; WPForms explains you can back them up remotely using Lite Connect, but restoring/viewing entries requires upgrading.
https://wpforms.com/docs/how-to-use-lite-connect-for-wpforms/
So, free “copy” strategies:
Option A (recommended): use FluentSMTP Email Logs as your on-site copy
- Ensure your WPForms notification email includes the submitted fields
- FluentSMTP will log the email contents and status (success/failed)
- This is often “good enough” for small sites
Docs: https://fluentsmtp.com/docs/fluentsmtp-email-logs-feature/
Option B: enable WPForms Lite Connect Entry Backups (off-site safety net)
WPForms → Settings → General
- Under Lite Connect, toggle Enable Entry Backups ON
WPForms describes this as a way to back up entries remotely and restore later upon upgrade.
https://wpforms.com/docs/how-to-use-lite-connect-for-wpforms/
Reality check: this is not “view entries inside WP for free.” It’s a backup/restore path.
5) Anti‑spam: Cloudflare Turnstile (free, low-friction)
5.1 Create a Cloudflare account (Turnstile does NOT require moving your DNS)
You can use Turnstile even if your DNS isn’t on Cloudflare.
5.2 Create a Turnstile widget + keys in Cloudflare
In Cloudflare dashboard → Turnstile → Add widget
- Widget name:
contact-form - Hostnames: add both if you use both:
yourdomain.comwww.yourdomain.com
- Mode: Managed (recommended)
- Save and copy:
- Site Key
- Secret Key
5.3 Add the Turnstile keys to WPForms
WPForms doc path:
- WPForms → Settings → CAPTCHA tab → select Turnstile → paste keys
Source: https://wpforms.com/docs/setting-up-cloudflare-turnstile/
5.4 Enable Turnstile on your form
In WPForms form builder:
- Either add the Turnstile field, or
- Form Settings → Spam Protection and Security → enable Turnstile (UI varies by version)
5.5 Add extra anti‑spam layers (still free)
- Enable WPForms honeypot / modern anti-spam (usually on by default)
- Enable a minimum time to submit (helps against bots)
- Avoid auto-replies to the submitter unless you truly need them (spammers exploit them)
6) Testing & Verification (how to prove it’s all working)
6.1 The “smoke test” sequence (10 minutes)
Do these in order:
- Brevo domain status
- Brevo → Domains → your domain shows Authenticated / Verified
- Brevo sender status
- Brevo → Senders →
wordpress@yourdomain.comshows Verified
- Brevo → Senders →
- FluentSMTP connection
- FluentSMTP → Settings shows Brevo connection as active
- FluentSMTP test email
- FluentSMTP → send test to your personal inbox
- WPForms live submission
- Submit your contact form from the live page (incognito)
- Turnstile verification
- Confirm you see Turnstile challenge (or “managed” invisible pass)
- Email delivery confirmation
- Confirm you received the WPForms notification
- Email header authentication
- In Gmail: “Show original” → confirm SPF/DKIM/DMARC = PASS
- FluentSMTP log confirmation
- FluentSMTP → Email Logs → your test + notification show Success
6.2 Where to check “truth” for each layer
- WordPress / FluentSMTP: Email Logs + test email results
- Brevo: Transactional email activity / events (delivery, bounce, blocked)
- Mailbox: Email headers show actual SPF/DKIM/DMARC results
6.3 How to read headers (Gmail example)
Open the received email → “More” menu → Show original.
Look for lines similar to:
SPF: PASSDKIM: PASSDMARC: PASS
If DMARC fails but SPF/DKIM pass, it’s often a From identity alignment problem (see troubleshooting).
7) Troubleshooting Playbook (symptoms → diagnosis → fixes)
Use this section like a decision tree. Start with your symptom and follow the steps.
7.1 Symptom: Emails don’t send at all (no notification, no test email)
Step 1 — Confirm WP is triggering email
- Submit the form once
- Check FluentSMTP → Email Logs
- If there’s no log entry, WPForms may not be firing a notification (or caching is serving a stale form page)
Step 2 — Confirm FluentSMTP is configured
- FluentSMTP → Settings:
- Brevo connection exists
- “From Email” matches your verified sender
Step 3 — Confirm the Brevo API key
- Re-copy the API key from Brevo and paste it again
- Ensure the key wasn’t revoked
Step 4 — Test again
- Send FluentSMTP test email
Common fixes
- Wrong API key pasted (extra spaces)
- Using a “From Email” that is not verified in Brevo
- Plugin conflict: another SMTP plugin is active (disable other mailer plugins)
7.2 Symptom: FluentSMTP test email works, but WPForms notification doesn’t send
Step 1 — Check WPForms notifications are enabled
- WPForms → form → Settings → Notifications
- Ensure notifications are ON and “Send To Email” is correct
Step 2 — Submit the form
- If no log entry appears in FluentSMTP, WPForms isn’t triggering
wp_mail()
Likely causes
- Form isn’t actually embedded on the page you’re testing
- Caching / page builder saved old shortcode/module
- You’re testing a different form than the one you configured
Fix
- Re-embed the form
- Clear cache (WP cache plugin + host cache)
- Test in an incognito window
7.3 Symptom: Emails send but never arrive (missing) or arrive late
Step 1 — Check Brevo events
- Look for “Delivered” vs “Blocked” vs “Bounced”
Step 2 — Check spam / promotions tabs
- Gmail: Spam + Promotions
- Microsoft: Junk + Other
Step 3 — Check your recipient domain
- Some org mail systems quarantine automated contact emails
Fix
- Ensure domain auth is complete (SPF/DKIM/DMARC)
- Use a consistent From identity (
wordpress@…) - Add a subject prefix like “[Website]” so you can filter reliably
7.4 Symptom: Emails land in spam
Step 1 — Confirm domain auth
- Brevo → your domain shows authenticated
- Headers show SPF/DKIM/DMARC PASS
Step 2 — Ensure “From” is your domain
- WPForms notification “From Email” should be
wordpress@yourdomain.com - Visitor email must be Reply-To, not From
Step 3 — Reduce spam-trigger content
- Avoid “free”, “urgent”, excessive links
- Keep notification template plain text or simple HTML
Fix
- Repair SPF/DKIM/DMARC
- Align From identity
- Add DMARC monitoring and tighten later after reports look good
7.5 Symptom: SPF fails / “permerror” / “too many DNS lookups”
What this means Your SPF record is invalid, duplicated, or has too many included lookups.
Diagnosis
- You have multiple SPF records → must merge into one
- You added too many
include:mechanisms
Fix
- Merge SPF into ONE record
- Remove old/duplicate SPF TXT records
- Prefer minimal SPF: only includes you truly use
7.6 Symptom: DKIM fails
Diagnosis
- DKIM record not published correctly
- Wrong record type (TXT vs CNAME) for your DNS provider
- DNS record published at wrong hostname (common copy/paste error)
Fix
- Re-add DKIM exactly as Brevo provides
- Wait for DNS propagation (can be minutes to hours)
- Verify the DKIM hostnames match what Brevo expects
7.7 Symptom: DMARC fails even though SPF & DKIM pass
Diagnosis Usually “alignment”:
- The domain used in the visible From: header doesn’t align with the domain authenticated by SPF/DKIM.
Common cause in WordPress
- WPForms set “From Email” to the visitor’s address → DMARC fails
Fix
- Force From Email to your domain sender (
wordpress@...) - Use Reply-To for the visitor
7.8 Symptom: Turnstile not showing, or form won’t submit
Diagnosis
- Hostname mismatch (you used
yourdomain.combut page iswww.yourdomain.com) - Cached JS / minified scripts interfering
- Conflicting CAPTCHA scripts (reCAPTCHA + Turnstile both injected)
Fix
- In Cloudflare Turnstile widget settings, add BOTH hostnames
- Clear all caches
- Disable other CAPTCHA features/plugins for this form
- Use WPForms “No-Conflict” mode if available in your version (WPForms docs cover this)
7.9 Symptom: You’re suddenly hitting Brevo 300/day limit
Diagnosis
- Bot spam is triggering form submissions (even if you don’t see them)
- Auto-replies might be doubling sends
Fix
- Add Turnstile + minimum submit time
- Disable any auto-reply to the submitter
- Tighten WPForms spam settings
- Consider adding a second filter (Akismet) if spam persists
8) Diagnostics Toolkit (quick checks you can do anytime)
8.1 Confirm DNS records exist (SPF/DKIM/DMARC)
Use your DNS provider’s UI, or a DNS lookup tool:
- SPF: TXT at root domain
- DMARC: TXT at
_dmarc.yourdomain.com - DKIM: at hostnames Brevo provided
8.2 Confirm FluentSMTP is “owning” wp_mail()
- Disable any other SMTP/mailer plugin
- Send FluentSMTP test email
- Check Email Logs for every send
8.3 Confirm form is the one you edited
- WPForms → check Form ID
- Confirm page embeds correct form ID/shortcode/module
9) Hardening checklist (quick wins)
Brevo
- 2FA enabled
- One API key per integration
- Revoke keys you don’t use
WordPress
- Unique admin username (not “admin”)
- 2FA for admins
- Keep plugins/themes updated
- Limit admin users
- Backups enabled
- If you store email logs, restrict who can see them
Form
- Turnstile enabled
- Minimal fields (less data collected = less risk)
- No autoresponder unless needed
- From = your domain, Reply-To = submitter
10) “Known limitations” (so you don’t get surprised)
- WPForms Lite does not provide an on-site entries dashboard by default; Lite Connect backs up entries for later restore on upgrade.
https://wpforms.com/docs/how-to-use-lite-connect-for-wpforms/ - FluentSMTP email logging is the best free “on-site copy” workaround, but it means form content is stored in your WordPress database.
Appendix A — Copy/paste templates
Recommended “From” identity
- From Name:
Your Brand - From Email:
wordpress@yourdomain.com - Reply-To:
{visitor_email_field}
SPF example (Workspace + Brevo)
v=spf1 include:_spf.google.com include:spf.brevo.com ~allUse Brevo’s provided include value.
Appendix B — Reference links (official)
- Brevo: Free plan limits (300/day): https://help.brevo.com/hc/en-us/articles/208580669-FAQs-What-are-the-limits-of-the-Free-plan
- Brevo: Pricing plans overview (includes transactional on Free): https://help.brevo.com/hc/en-us/articles/208589409-About-Brevo-s-pricing-plans
- Brevo: Create/manage API keys: https://help.brevo.com/hc/en-us/articles/209467485-Create-and-manage-your-API-keys
- Brevo: Authenticate domain (Brevo code + DKIM + DMARC): https://help.brevo.com/hc/en-us/articles/12163873383186-Authenticate-your-domain-with-Brevo-Brevo-code-DKIM-DMARC
- Brevo API: Auth header (
api-key): https://developers.brevo.com/docs/how-it-works - FluentSMTP: Brevo mailer setup: https://fluentsmtp.com/docs/setting-up-sendinblue-mailer-in-fluent-smtp/
- FluentSMTP: Email logs feature: https://fluentsmtp.com/docs/fluentsmtp-email-logs-feature/
- WPForms: Turnstile setup: https://wpforms.com/docs/setting-up-cloudflare-turnstile/
- WPForms: Lite Connect entry backups: https://wpforms.com/docs/how-to-use-lite-connect-for-wpforms/
- Google Workspace: SPF record guidance: https://support.google.com/a/answer/33786
- Google Workspace: “one SPF record per domain”: https://support.google.com/a/answer/10683907