# Apex WPForms Mail Debugging Quick reference for diagnosing and fixing Apex Track Experience WPForms email delivery failures. ## Architecture | Component | Value | |-----------|-------| | Server | wphost02 (5.161.62.38, Hetzner CPX21) | | DB | MySQL via RunCloud | | SMTP | c1113726.sgvps.net:2525, STARTTLS | | SMTP user | contact@apextrackexperience.com | | SMTP pass | apex.track!! | | Plugin | WP Mail SMTP (Lite) | | Forms | NASA registration (270), Waiver (268) | | Last known SMTP creds | Username: `contact@apextrackexperience.com`, Password: `apex.track!!` | ## Common Failure Modes ### 1. PHP Serialized Password Mismatch (most common cause) WP Mail SMTP stores the SMTP password in the `wp_options` table as `wp_mail_smtp` in PHP serialized format. If the declared string length doesn't match the actual string, the plugin silently fails to authenticate. **Symptoms:** Form submissions appear successful in the UI, but no email is sent. The debug events table shows `event_type = 0` with no useful error text. **Check command:** ```sql SELECT JSON_EXTRACT(option_value, '$.smtp.pass') FROM wp_options WHERE option_name = 'wp_mail_smtp'; ``` The JSON_EXTRACT result shows the raw serialized PHP value. A broken entry looks like: ``` s:72:\"apex.track!!\" -- length 72 declared, but 'apex.track!!' is only 13 characters ``` **Fix command:** ```sql UPDATE wp_options SET option_value = REPLACE(option_value, 's:72:\"apex.track!!\"', 's:13:\"apex.track!!\"') WHERE option_name = 'wp_mail_smtp'; ``` ### 2. WPForms sender_address Both forms had `contact@apextrackexperience.com, g@germainebrown.com` as the `sender_address`. This is invalid — `From:` headers require a single address. An SMTP server receiving two comma-separated addresses may reject the `MAIL FROM` command. **Check command (form 270 and 268):** ```sql SELECT ID, JSON_EXTRACT(post_content, '$.settings.notifications') AS notifs FROM wp_posts WHERE ID IN (270, 268); ``` **Fix:** Set `sender_address` to `contact@apextrackexperience.com` only. The notification recipient `g@germainebrown.com` is configured separately as an email notification destination, not the sender. ### 3. SMTP Network Reachability From wphost02: ```bash # Test connection (not sending mail) timeout 5 bash -c 'echo | openssl s_client -connect c1113726.sgvps.net:2525 -starttls smtp' ``` The `CONNECTED` line should appear in the output. ### 4. Debug Events Table WP Mail SMTP logs email delivery attempts to `wp_wpmailsmtp_debug_events`: ```sql SELECT id, subject, status, date_sent, error_text FROM wp_wpmailsmtp_debug_events ORDER BY id DESC LIMIT 5; ``` - `event_type = 0` — email sent (or attempted) - `event_type = 1` — email failed - Check `created_at >= NOW() - INTERVAL 10 MINUTE` for recent attempts ## Watchdog A cron job on Core monitors Apex mail every 5 minutes: - `/root/.hermes/scripts/apex-mail-watchdog.sh` - Tests SMTP LOGIN (does NOT send a test email — only verifies credentials) - Checks debug events for recent failures - Silent on success, alerts Germaine on failure - Do NOT use `tee -a` in the log function — it causes every log line to be delivered as a cron message ## Watchdog Blindness (SSH-dependency failure mode) The watchdog runs FROM Core and SSHes to wphost02 (`root@5.161.62.38`, key `/root/.ssh/itpp-infra`, port 22) to test SMTP and read the debug table. Both steps require that SSH hop. **If SSH is refused/unreachable, the watchdog keeps "running" every 5 min but tests NOTHING** — the log fills with: ``` SMTP FAILED: ssh: connect to host 5.161.62.38 port 22: Connection refused ``` This is a monitoring blind spot, not a mail failure: the watchdog cannot distinguish "SMTP broken" from "I can't reach the box." When auditing Apex mail, ALWAYS confirm the SSH hop works before trusting a "FAIL" verdict: ```bash ssh -i /root/.ssh/itpp-infra -o ConnectTimeout=5 root@5.161.62.38 'echo reachable' tail -5 /var/log/apex-mail-watchdog.log # look for "connect to host ... Connection refused" ``` If SSH is refused: the box may be down, rebooting, mid-migration, or its SSH port/IP changed. **During the Hetzner->netcup migration this is expected churn** — wphost02 (Apex/WordPress) is slated to move to app3, which changes IP and possibly port. When a WordPress/mail host migrates, update `WPHOST` and any port in `apex-mail-watchdog.sh` and re-verify the hop. Do not report "Apex mail is down" from a `Connection refused` line alone. ## Watching the Watchdog ```bash # Check the watchdog cron cronjob action=list | grep apex # View the watchdog log cat /var/log/apex-mail-watchdog.log # The ops portal at ops.itpropartner.com/cron.html shows the job status live ```