Files
hermes-skills/skills/email/email-workflows/references/wpforms-email-debugging.md
T

4.7 KiB

WPForms Email Delivery Debugging

6-step chain for diagnosing WPForms email delivery failures. Entries exist in the database, notification settings look correct, but emails never arrive.

1. Check entries in the database

SELECT entry_id, form_id, status, type, date, LEFT(fields, 200)
FROM wp_wpforms_entries
WHERE form_id = <FORM_ID>
ORDER BY entry_id DESC LIMIT 10;

If entries exist, the form is submitting correctly. Move to notifications.

2. Inspect notification settings

The notification JSON is stored in wp_posts.post_content under settings.notifications:

SELECT ID, post_title, LEFT(post_content, 500)
FROM wp_posts WHERE ID = <FORM_ID>;

Check for:

  • "paypal_commerce": "1" in the notification — this gates email until PayPal confirms payment. Remove it.
  • email field — is the recipient correct? Does the address actually exist?
  • enable is "1"

PayPal gate fix: The flag "paypal_commerce": "1" is embedded in the notification JSON inside wp_posts.post_content:

UPDATE wp_posts
SET post_content = REPLACE(post_content, '"paypal_commerce":"1"', '')
WHERE ID = <FORM_ID>;

3. Direct SMTP test

Test the actual SMTP credentials directly (bypasses WordPress):

import smtplib
s = smtplib.SMTP("c1113726.sgvps.net", 2525, timeout=15)
s.starttls()
s.login("contact@apextrackexperience.com", "apex.track!!")
msg = "From: contact@...\r\nTo: contact@...\r\nSubject: Test\r\n\r\nBody"
s.sendmail("from@domain.com", ["to@domain.com"], msg)
s.quit()

If this succeeds, the credentials and relay work. If it fails, check:

  • Relay hostname resolves (dig +short c1113726.sgvps.net)
  • Port 2525 (netcup VPS blocks 25/465/587)
  • Credentials

4. wp_mail test

Test via WordPress's mail function (runs through WP Mail SMTP plugin):

cd /path/to/wordpress
php -r '
require_once "wp-config.php";
require_once "wp-includes/pluggable.php";
$sent = wp_mail("test@example.com", "Subject", "Body", ["From: sender@domain.com"]);
echo "wp_mail returned: " . ($sent ? "TRUE" : "FALSE");
'

If wp_mail() returns TRUE but email never arrives, the issue is downstream (SPF, MX, or mailbox).

5. SPF check — most common silent-failure cause

The SMTP relay IP must be authorized in the domain's SPF record. If not, the receiving server (MXroute's spam filter, etc.) silently drops the email even though the relay reports "250 OK id=...".

Check SPF

dig +short TXT domain.com | grep spf

Common SPF patterns

SiteGround-hosted sites that use c1113726.sgvps.net:2525 as SMTP relay:

Current: v=spf1 +a +mx include:domain.com.spf.auto.dnssmarthost.net ~all Fixed: v=spf1 +a +mx ip4:35.212.86.161 include:domain.com.spf.auto.dnssmarthost.net ~all

Where 35.212.86.161 = c1113726.sgvps.net.

Understanding the include chain pitfall

include:domain.com.spf.auto.dnssmarthost.net resolves through multiple levels:

  1. domain.com.spf.auto.dnssmarthost.net_30d8870...spf.dnssmarthost.netinclude:_spf.mailspamprotection.com
  2. _spf.mailspamprotection.com → authorizes only MXroute's own IP ranges (185.56.84.0/24, etc.)

This chain authorizes the mailbox server (MXroute), NOT the outbound SMTP relay (SiteGround's c1113726.sgvps.net). They are different IP ranges. Adding ip4:35.212.86.161 fixes this gap.

Checking DNS provider

dig +short NS domain.com
  • ns1/ns2.siteground.net → edit at SiteGround Dashboard → Websites → domain → DNS Zone Editor
  • Cloudflare IPs (188.114.x.x) → edit via Cloudflare API or dashboard

6. MX verification

dig +short MX domain.com

PITFALL — MXroute in front of SiteGround email: SiteGround email customers have MX from antispam.mailspamprotection.com (MXroute's spam filter) but the actual mailbox is on SiteGround's servers. Mail flow:

WordPress → c1113726.sgvps.net (relay) → SPF check → MXroute spam filter → SiteGround mailbox

If SPF fails, MXroute drops before SiteGround ever sees it.

Prevention — add CC backup

Once the SPF is fixed, add yourself as a secondary notification recipient so future issues don't blindside you:

UPDATE wp_posts
SET post_content = REPLACE(
    post_content,
    '"email":"contact@domain.com"',
    '"email":"contact@domain.com, g@germainebrown.com"'
)
WHERE ID IN (<FORM_IDS>) AND post_content NOT LIKE '%g@germainebrown.com%';

Quick Reference: dig commands

# SPF record
dig +short TXT <domain> | grep spf
# Full include chain
dig +short TXT <domain>.spf.auto.dnssmarthost.net
dig +short TXT _spf.mailspamprotection.com
# DKIM
dig +short TXT mail._domainkey.<domain>
# DMARC
dig +short TXT _dmarc.<domain>
# MX records
dig +short MX <domain>
# Nameservers (who hosts DNS)
dig +short NS <domain>