Running It Safely

Why Do My WordPress Contact Form Emails Go To Spam?

Short answer

Usually because WordPress sends the email from your web server, not your mail server. Your SPF record only vouches for the mail server, so the message fails SPF, carries no DKIM signature and often uses a From address nobody owns. Send it through your real mailbox over authenticated SMTP and all three problems go away.

How Can Correct DNS Records Still Fail?

On my own site every enquiry landed in spam, and the DNS looked perfect: an SPF record for the host’s mail servers, a 2048-bit DKIM key, a DMARC record and MX records. The records were fine. The email just never went near the servers they describe.

WordPress sends mail with wp_mail(), and unless something tells it otherwise that hands the message to PHP’s mail() on the web server. That server’s address is not in your SPF record, so the check fails. A failing SPF record is worse than none at all, because you told receivers exactly who may send for you and this was not one of them.

Two more things go wrong at the same time. DKIM signing happens on the mail server, which the message never touched, so there is no signature. And WordPress sends from wordpress@yourdomain by default, which is usually not a real mailbox, so the From address does not line up with anything.

How Do I Check Which Server Sent It?

Send a test enquiry to a Gmail address, open it, and choose Show original from the three-dot menu. Gmail prints SPF, DKIM and DMARC results at the top. If SPF says FAIL or SOFTFAIL and DKIM is missing, the mail left from the web server. Check the sending path, not just the DNS.

How Do I Fix It?

Route WordPress mail through authenticated SMTP on your own mail server. The message then leaves from an address your SPF record covers and gets DKIM-signed on the way out. You can do it with an SMTP plugin, or with a few lines in your theme or a small plugin:

add_action( 'phpmailer_init', function ( $mailer ) {
    if ( ! defined( 'SMTP_PASS' ) ) {
        return; // keep the old route until the password is set
    }
    $mailer->isSMTP();
    $mailer->Host       = 'smtp.hostinger.com';
    $mailer->SMTPAuth   = true;
    $mailer->Port       = 465;
    $mailer->SMTPSecure = 'ssl';
    $mailer->Username   = 'hello@yourdomain.com';
    $mailer->Password   = SMTP_PASS;
    $mailer->setFrom( 'hello@yourdomain.com', 'Your Business', false );
    $mailer->Sender     = 'hello@yourdomain.com';
} );

Three details matter more than the code:

  • The From address must be the mailbox you log in with. DMARC checks that they match, so SPF and DKIM can both pass and the message can still fail. Put the visitor’s address in Reply-To instead, so pressing reply still reaches them.
  • The password goes in wp-config.php, never in the theme. Theme files get copied into backups and downloads, and a settings page stores it in the database.
  • Guard on the constant, as above, so the form keeps working while you set it up.

The host name and port above are Hostinger’s. Other hosts publish their own, usually on the same help page as the mailbox settings.

When Should I Tighten DMARC?

Leave DMARC at p=none until Show original says PASS for SPF, DKIM and DMARC on a real form submission. Then move to p=quarantine and add a rua= address so you receive reports. Tighten it first and you quarantine your own enquiries.

What Do I Do On Every Build?

Most setup guides stop at the DNS records. In my experience the records are rarely the problem; the sending route is. So every site I hand over sends through its own mailbox, and I test a real submission into Gmail before I call the contact form done.

Want This Done On Your Site?

Tell me what your business does and what is going wrong, and I will tell you what I would fix first.

Start a project See the work