All posts
Fix WordPress email deliverability: replace PHP mail() with MailKite SMTP
Gabe 4 min read

Fix WordPress email deliverability: replace PHP mail() with MailKite SMTP

WordPress uses PHP mail() by default — and most of it goes straight to spam. This tutorial shows how to route WordPress email through MailKite's SMTP relay in 10 minutes: password resets, contact form notifications, WooCommerce order emails, all DKIM-signed from your own domain.

WordPress sends email through PHP’s mail() function. That function talks to whatever MTA is installed on your server — usually Postfix or Sendmail, misconfigured, with no DKIM signing, no SPF alignment, and a shared IP that’s probably on a blocklist. The result: password resets vanish, contact form submissions land in Gmail’s spam tab, and WooCommerce order confirmations never arrive.

The fix is simple: point WordPress at a proper SMTP relay. MailKite gives you one — smtp.mailkite.dev — with DKIM signing, SPF alignment, and per-domain reputation on every message. Your From address stays on your own domain. No third-party email service, no monthly send limits, no vendor lock-in.

Here’s how bad the default is, and how fast you can fix it.

Why PHP mail() fails

PHP’s mail() is a function, not a delivery system. It hands a message to the local MTA and hopes for the best. Three things go wrong:

  1. No DKIM signing. Gmail, Yahoo, and Outlook all check DKIM. A message without it gets a failing score, even if the content is fine.

  2. No SPF alignment. The From address says yourdomain.com, but the sending IP is your hosting provider’s shared server. The SPF record for yourdomain.com doesn’t include that IP. Hard fail.

  3. Shared reputation. Your server shares an IP with hundreds of other sites. If one of them sends spam, your deliverability tanks.

MailKite handles all three. You publish MX + SPF + DKIM records for your domain (one-time setup, documented here), and every message you send through MailKite is signed and aligned automatically. No code changes, no server configuration.

The 10-minute fix

1. Add your domain to MailKite

In the dashboard, add your domain. MailKite returns four DNS records:

MX    yourdomain.com           mx.mailkite.dev    (priority 10)
TXT   yourdomain.com           v=spf1 include:mailkite.dev ~all
TXT   mailkite._domainkey.yourdomain.com   v=DKIM1; k=rsa; p=…
TXT   _dmarc.yourdomain.com    v=DMARC1; p=none;

Add them to your DNS. The MX propagates in under 5 minutes for most registrars.

2. Install WP Mail SMTP

WP Mail SMTP is the most installed SMTP plugin on WordPress (4M+ sites). Install and activate it.

3. Configure the connection

Go to WP Mail SMTP → Settings and fill in:

SettingValue
From Emailhello@yourdomain.com (must be on your verified domain)
From NameYour site name
MailerOther SMTP
SMTP Hostsmtp.mailkite.dev
EncryptionTLS
SMTP Port587
Usernamemailkite
PasswordYour API key (mk_live_…)

That’s it. Every wp_mail() call on your site — password resets, contact form notifications, plugin alerts — now routes through MailKite.

4. Test it

WP Mail SMTP has a built-in Email Test tab. Or use WP-CLI:

wp eval 'mail("you@yourdomain.com", "Test from MailKite", "It works!");'

Check your inbox. The message should arrive with a passing DKIM signature (look at the original/headers in Gmail — dkim=pass).

What changes

Before: WordPress calls wp_mail(), PHP hands it to the local MTA, the MTA sends from a shared IP with no authentication. Half your emails land in spam.

After: WordPress calls wp_mail(), WP Mail SMTP intercepts it, connects to smtp.mailkite.dev over TLS, authenticates with your API key, and MailKite sends from your domain — DKIM-signed, SPF-aligned, from a clean IP with dedicated reputation.

The difference shows up in your delivery rates. WordPress sites that switch from php mail() to a proper SMTP relay typically see a 30–50% improvement in inbox placement, measured by opens and bounces.

For developers: hook PHPMailer directly

If you’d rather not use a plugin, hook PHPMailer in functions.php:

add_action('phpmailer_init', function ($phpmailer) {
    $phpmailer->isSMTP();
    $phpmailer->Host       = 'smtp.mailkite.dev';
    $phpmailer->Port       = '587';
    $phpmailer->SMTPSecure = 'tls';
    $phpmailer->Username   = 'mailkite';
    $phpmailer->Password   = getenv('MK_API_KEY');
    $phpmailer->setFrom('hello@yourdomain.com', 'Your Site');
});

Store your API key as an environment variable (MK_API_KEY) rather than hardcoding it. Works with any hosting that supports .env files or environment configuration.

Receiving inbound email

MailKite also receives email at any address on your domain and POSTs it to a webhook as clean JSON. If you want WordPress to process inbound email — create posts from email, power a support inbox, or route messages to a custom post type — create a webhook endpoint in your theme or a custom plugin:

// webhook.php — receives MailKite inbound webhook
$payload = json_decode(file_get_contents('php://input'), true);
$sig     = $_SERVER['HTTP_X_MAILKITE_SIGNATURE'] ?? '';
$secret  = getenv('MK_WEBHOOK_SECRET');
$computed = hash_hmac('sha256', json_encode($payload), $secret);

if (!hash_equals($computed, $sig)) {
    http_response_code(401);
    exit;
}

// Process: create a post, log to database, or trigger a WooCommerce action
error_log("Inbound email from {$payload['from']}: {$payload['subject']}");

Set your domain’s webhook URL in the MailKite dashboard and inbound email arrives as structured JSON — body, headers, attachments, SPF/DKIM results — ready for WordPress to act on.

How it compares

PHP mail()WP Mail SMTP + MailKite
DKIM signingNoneAutomatic, per-domain
SPF alignmentFails (shared IP)Passes (your domain)
Inbox placement~40–60%~95%+
Delivery logsServer mail.log onlyMailKite dashboard + API
Inbound emailNot supportedWebhook → your endpoint
Cost”Free” (lost deliverability)Free tier included

FAQ

Will this break my contact form plugin? No. Contact Form 7, WPForms, Gravity Forms, and others all use wp_mail(). WP Mail SMTP intercepts that function, so they automatically route through MailKite.

What about WooCommerce emails? Same story — WooCommerce uses wp_mail() for order confirmations, shipping notifications, and password resets. WP Mail SMTP catches all of them. See the WooCommerce + MailKite guide for store-specific setup.

Can I use this with a transactional email service like SendGrid or Mailgun? Yes — WP Mail SMTP supports many SMTP providers. MailKite gives you the same SMTP interface with inbound webhooks included, no separate parse product needed. If you already use SendGrid or Mailgun for sending, you can still use MailKite for receiving inbound email alongside them.

What’s the difference between this and a dedicated WordPress SMTP hosting setup? A self-hosted SMTP relay (Postfix, Haraka) gives you full control but requires server management, IP warming, DNS configuration, and monitoring. MailKite handles all of that — you publish four DNS records and you’re sending. No server to maintain, no reputation to warm.


Point your domain’s MX at MailKite, swap two settings in WP Mail SMTP, and your WordPress email stops going to spam. Start free — unlimited domains, no credit card.

Related: Send over SMTP — the full connection reference · Receive email as a webhook in Python — if you’re building custom WordPress integrations · What is programmable email? — the category MailKite belongs to

Discuss this post: Hacker News Share on X Share on LinkedIn

Related posts