2.4 KiB
Apex WPForms SMTP Serialization Bug
Root cause: WP Mail SMTP stores passwords in PHP serialized format within the wp_options table. The serialized string has a length prefix (e.g., s:13: for 13 characters). If the declared length doesn't match the actual password string length, the plugin cannot deserialize the password and ALL form email delivery fails silently.
Affected configuration: option_name = 'wp_mail_smtp', stored in wp_options table.
The bug: The password apex.track!! is 13 characters. The stored value had s:72 instead of s:13 — likely caused by a pre-save sanitization or paste issue. WP Mail SMTP read s:72 and expected a 72-character string, found fewer characters, and failed with a PHP warning that never surfaced to the UI.
Diagnosis:
- Check the stored password:
SELECT option_value FROM wp_options WHERE option_name = 'wp_mail_smtp' - Search for
smtp.passin the serialized data - Count the actual password length and compare to the serialized
s:Nprefix
Fix (verified Jul 8, 2026):
UPDATE wp_options
SET option_value = REPLACE(
option_value,
's:72:"apex.track!!"',
's:13:"apex.track!!"'
)
WHERE option_name = 'wp_mail_smtp';
Also fix sender_address on forms:
Both Form 270 (NASA Top Speed) and Form 268 (Waiver) had comma-separated email addresses in the sender_address notification field. This produces an invalid From: email header. Set sender_address to a single email address (e.g., contact@apextrackexperience.com).
Verification:
- Send a test email from the WP Mail SMTP settings page
- Check debug events table:
SELECT * FROM wp_wpmailsmtp_debug_events ORDER BY id DESC LIMIT 10 - Submit a test WPForms entry and verify the notification arrives
- Enable the 5-min watchdog script
Resending missed notifications:
After fixing the serialization, previously failed form entries won't auto-resend. Check wp_wpforms_entries for entries with no corresponding email notification. Manually re-send via SMTP Python script.
Watchdog script at /root/.hermes/scripts/apex-mail-watchdog.sh runs every 5 minutes via no_agent cron. It:
- Tests SMTP LOGIN authenticity (no test email sent — just
s.login()thens.quit()) - Queries
wp_wpmailsmtp_debug_eventsfor recent failures - Silent on success, alerts on failure
- CRITICAL:
log()function uses>> "$LOG"nottee -a "$LOG"to prevent every log line from being delivered as a cron message