Back to blog

How to Send WordPress Emails Through an Email API Instead of SMTP

Route WordPress email through a provider's API instead of PHP mail() or SMTP, with the domain authentication that actually keeps messages out of spam.

How to Send WordPress Emails Through an Email API Instead of SMTP

A WordPress site that can't send email is broken in a way nobody notices until it costs something. Password resets vanish. WooCommerce order confirmations never arrive and customers open tickets asking whether their payment went through. Contact form submissions pile up in a provider's spam folder you don't have access to. The site looks fine, so the problem sits there for weeks.

The fix is to stop letting your web server pretend to be a mail server. Sending WordPress email through a transactional email API hands every message to a provider that has spent years building sender reputation, and it does so over an ordinary HTTPS request rather than an SMTP connection your host may not even allow. This guide walks through the whole setup: choosing a provider, authenticating your sending domain, configuring WordPress, and verifying that mail is actually landing.

TL;DR

  • WordPress email fails because wp_mail() defaults to PHP's mail(), which hands your message to the local server with no authentication tied to your domain. Gmail has required SPF or DKIM from every sender since February 1, 2024.
  • An email API and an SMTP plugin both fix the authentication problem. The API route additionally avoids blocked outbound SMTP ports, avoids holding a page load open during an SMTP handshake, and gives you a readable HTTP error when something breaks.
  • The step that actually determines whether mail reaches the inbox is domain verification at the provider (SPF and DKIM), not the plugin you install.
  • Publish a DMARC record at p=none with a reporting address, read the reports for a few weeks, then tighten it.
  • The Magic API Email plugin does this on any host. On MagicWP you can configure the same providers from the dashboard instead, with no plugin on the site.
  • Always confirm delivery by reading the received headers, not by trusting a "test email sent" notice.

Why WordPress email fails so often

WordPress sends mail through wp_mail(), which wraps PHPMailer. Unless something intervenes, PHPMailer is configured to use PHP's mail() function, which hands the message to whatever local mail transfer agent exists on the server and returns.

That creates three separate problems.

Nothing authenticates the message. Your site sets a From: address on your domain, but the message leaves from a host that almost certainly isn't listed in your domain's SPF record and isn't signing anything with DKIM. Receiving servers see a message claiming to be from your domain with no cryptographic or DNS-based proof. Google's requirements for all senders, in force since February 1, 2024, state plainly that every sender must set up SPF or DKIM email authentication for their sending domains, have valid forward and reverse DNS records, use a TLS connection, keep spam rates below 0.3%, and format messages according to RFC 5322. Unauthenticated mail gets rejected with a 5.7.26 error or silently filed as spam.

You inherit somebody else's reputation. On shared infrastructure, the sending IP is shared with every other site on the box. One compromised site sending spam damages deliverability for everyone on that address.

Failures are invisible. wp_mail() returning true only means the message was handed off without throwing an exception. It says nothing about delivery. A site can happily report success for months while every message is being dropped at the receiving end.

Switching to a transactional provider solves all three at once. The provider owns warmed, monitored sending IPs, signs your messages with DKIM using keys tied to your domain, and tells you what happened to each message.

API or SMTP: what actually changes

This is worth being honest about, because a lot of writing on this topic implies SMTP is broken and APIs are magic. They aren't.

If you configure an SMTP plugin to authenticate against a transactional provider, you get the same sending IPs, the same DKIM signing, and the same reputation benefit as the API route. The deliverability win comes from using a real provider and verifying your domain, not from the transport. Anyone who tells you an API delivers better than the same provider's SMTP relay is selling something.

What genuinely differs is operational.

SMTP relay Provider API
Network requirement Outbound TCP on 587 or 465 Outbound HTTPS on 443
Blocked by hosts? Frequently, on shared and some cloud hosts Almost never
Connection cost Multi-step handshake and auth per send Single HTTPS request
Failure information SMTP status codes, often generic HTTP status plus a JSON error body
Timeout behaviour Can hold a page load open for many seconds Bounded by one HTTP timeout
Credential scope Username and password Revocable, often scope-limited API key

The port issue is the one that decides it for many sites. Plenty of hosts block outbound 25 by default and some block 587 too, as an anti-abuse measure. If your host does, no amount of SMTP configuration will work and the symptom is a timeout with no useful message. HTTPS to a provider's API is outbound traffic on 443, which is open everywhere because the site couldn't function otherwise.

The second reason is latency during a page load. An SMTP send opens a TCP connection, negotiates TLS, authenticates, transmits, and closes, all inside the request that triggered it. When a customer places an order, that sequence runs while they're staring at the checkout spinner. A slow or unresponsive SMTP host turns into a slow checkout. A single HTTPS POST is not free either, but it's shorter and it fails faster and more predictably.

The third is debugging. An SMTP failure often surfaces as "SMTP connect() failed" with nothing behind it. An API failure comes back as an HTTP status and a JSON body that tells you the domain isn't verified, or the key is revoked, or the From address isn't permitted.

Worth saying plainly: if you already have SMTP working reliably against a good provider, you do not need to switch. This guide is for sites currently on PHP mail(), or sites where SMTP is failing because of blocked ports or timeouts.

Prerequisites

Before Step 1, have these ready:

  • A WordPress site you can log into as an administrator, running WordPress 6.0 or later on PHP 8.0 or later if you plan to use the Magic API Email plugin. Check the plugin page for the current minimum, since requirements change between versions.
  • DNS access for your domain. This is not optional. You will be adding TXT and CNAME records. If your domain is managed by a client or an agency, get access sorted before you start.
  • A recent backup. Nothing here touches content, but you're changing DNS and site configuration, and the habit is worth keeping. MagicWP takes an on-demand backup before any change from the dashboard; see the backups documentation.
  • An email address on a different domain (a personal Gmail account works well) to receive test messages. Testing delivery to an address on the same domain proves very little.
  • If you're on MagicWP, the site must be live and your account email verified. The email documentation covers the exact requirements.

Set aside an hour. Most of it is waiting for DNS.

Step 1 - Choose an email provider

Magic API Email and the MagicWP dashboard both support the same five providers. As of plugin version 1.1.1 those are Resend, Mailgun, Postmark, Mailtrap, and Plunk. Check the plugin page for the current list before you commit, since providers get added.

Provider Suits Watch out for
Resend Most sites; the default recommendation Nothing specific
Postmark Sites where transactional delivery speed matters Separates transactional and broadcast streams
Mailgun Sites already using Mailgun elsewhere API is scoped to a sending domain, so you need that domain as well as the key
Plunk Developer-oriented setups Smaller ecosystem
Mailtrap Testing, not production Captures mail in a sandbox inbox by default

Two traps here that catch people repeatedly.

Mailtrap is a testing tool first. By default it captures what your site sends into a Mailtrap inbox so you can inspect it, rather than delivering to the real recipient. That is genuinely useful on staging, where you want to see the WooCommerce order email without mailing an actual customer. It is the wrong choice for production unless you have explicitly switched to a sending stream.

Mailgun sandbox domains only deliver to authorized recipients. Every Mailgun account starts with a sandbox domain that will only send to addresses you've manually added in their dashboard. It works perfectly for your own test, then fails for every real customer. Add and verify your own domain before going live.

For most sites, pick Resend or Postmark, verify your real domain, and move on.

Step 2 - Verify your sending domain at the provider

This is the step that determines whether your email reaches inboxes. Everything else is configuration.

Sign into your provider and add your sending domain. The provider will give you DNS records to publish, typically:

  • A TXT record for SPF, or an instruction to add their include to an existing SPF record.
  • One or more CNAME or TXT records for DKIM, which publish the public half of a signing key.
  • Sometimes a CNAME for link tracking or a custom return-path, which improves SPF alignment.

Publish exactly what the provider gives you. Don't retype from memory and don't guess at the values.

Two things people get wrong here.

You can only have one SPF record per domain. If your domain already has an SPF record because you use Google Workspace or Microsoft 365 for your inbox, you merge the new provider's include into it. You do not add a second record. Two SPF TXT records on the same name is a permanent error, and the result is worse than having none.

dns
; Wrong: two records on the same name
example.com.  TXT  "v=spf1 include:_spf.google.com ~all"
example.com.  TXT  "v=spf1 include:provider-spf-host ~all"

; Right: one record, both senders included
example.com.  TXT  "v=spf1 include:_spf.google.com include:provider-spf-host ~all"

Your provider gives you the exact include value. Watch the ten DNS lookup limit on SPF as well; each include costs at least one, and stacking four or five services will break the record.

Decide whether to send from a subdomain. Some setups send from something like mail.example.com rather than the apex domain. The argument for it is reputation isolation: problems with marketing mail don't drag down your transactional reputation. The argument against is that recipients trust a familiar From address, and a subdomain starts with no reputation of its own. For a single WordPress site sending password resets and order confirmations, the apex domain is usually the right call. Split only when you have a real volume of marketing mail to separate.

DKIM keys matter too. Sending to personal Gmail accounts requires a DKIM key of 1024 bits or longer, and Google recommends 2048 bits where the domain provider supports it. Providers handle this for you, but it's worth confirming in their dashboard.

Wait for the provider to show the domain as verified. This usually takes minutes but can take hours depending on your DNS TTLs.

Step 3 - Publish a DMARC record

SPF and DKIM tell receiving servers how to check your mail. DMARC tells them what to do when the check fails, and gives you reports on what's being sent in your name.

Start permissive:

dns
_dmarc.example.com.  TXT  "v=DMARC1; p=none; rua=mailto:[email protected]"

p=none asks receivers to take no action on failures but still send you aggregate reports. Run it for two to four weeks, read what comes back, and confirm that every legitimate sender for your domain is passing. Only then tighten to p=quarantine and eventually p=reject.

Publishing p=reject on day one is a common and expensive mistake. If you have a CRM, a helpdesk, an invoicing tool, or a newsletter platform sending as your domain and you haven't included them, you've just told the entire internet to discard their mail.

DMARC also requires alignment, which is a detail people miss. To pass DMARC authentication, messages must be authenticated by SPF or DKIM, and the authenticating domain must be the same domain that appears in the message's From: header. A message can pass a raw SPF check and still fail DMARC if the domain that passed isn't the one in the From: header. This is exactly why the From address you set in WordPress has to be on the domain you verified at the provider.

If your site sends more than 5,000 messages a day to Gmail addresses, DMARC stops being optional. Bulk senders must set up SPF, DKIM, and DMARC, meet alignment requirements, and support one-click unsubscribe with a clearly visible unsubscribe link in marketing and subscribed messages. Purely transactional mail such as password resets and order confirmations is excluded from the unsubscribe requirement, but the authentication requirements apply to everything.

Step 4 - Create an API key

In the provider's dashboard, create an API key for this site. Some notes:

  • One key per site. If you manage several sites, don't share a key across them. When you need to revoke one, you'll want to do it without breaking the others.
  • Scope it to sending if the provider offers granular permissions. A key that can only send mail is a much smaller problem if it leaks.
  • Copy it now. Most providers show the key exactly once.
  • For Mailgun, also note your sending domain (something like mg.example.com), because Mailgun's API endpoint is scoped to a domain.

Treat the key as a credential with real blast radius. Someone who has it can send mail as your domain, from your reputation, to anyone.

Step 5 - Configure WordPress

There are two routes here depending on where the site is hosted.

Step 5.1 - Using the Magic API Email plugin (any host)

Install and activate Magic API Email from the WordPress plugin directory, then open its settings screen. As of version 1.1.1 the plugin registers under Settings; the exact menu position has moved between versions, so check both the Settings submenu and the top-level sidebar if you don't see it immediately.

Fill in four things:

  • Provider - the one you set up in Step 1.
  • API Key - from Step 4.
  • From Email - an address on the domain you verified in Step 2. This is the field people get wrong. If you verified example.com at the provider but leave the From address as the WordPress default [email protected], the provider will reject the send or the message will fail DMARC alignment.
  • From Name - what recipients see. Use the site or business name, not "WordPress".

The plugin intercepts sending through the pre_wp_mail filter, which short-circuits wp_mail() before PHPMailer is involved. That has a useful property: if no API key is configured, the filter returns null, WordPress carries on with its normal path, and nothing is lost. A misconfigured install degrades to the old behaviour rather than dropping mail on the floor.

Credentials are stored per provider, so switching between two configured providers doesn't wipe the other one's key. That's genuinely handy when you're comparing providers or keeping a Mailtrap configuration around for staging.

One security consideration to be aware of: an API key configured through any plugin lives in the site's database. It's therefore present in every database backup, and readable by anyone with administrator access or database access. That's normal and usually fine, but it should inform how you handle backups and who gets an admin account. If that's not acceptable for your setup, use the dashboard route below instead.

Step 5.2 - Using the MagicWP dashboard (MagicWP sites)

On MagicWP you can configure the same providers without installing anything. Open the site in the dashboard and go to Email, pick a provider, enter the API key, From Email, and From Name, then save. Mailgun additionally asks for your Mailgun domain.

Saved keys are encrypted at rest and shown back to you masked, never in full. The practical consequence, which surprises people: because the key is write-only, changing the From Email or From Name on an already-saved provider requires re-entering the API key when you save. That's not a bug, it's what write-only storage means.

Setting the provider dropdown to Disabled stops routing mail through a provider and falls back to WordPress's default sending, while keeping your saved details for later. The full walkthrough is in the email documentation.

Step 6 - Send a test and read the headers

Both routes give you a test send button. Use it, but don't stop there. A test message arriving proves the API call worked. It doesn't prove the message will pass authentication for a stranger's mail server.

Send a test to a personal Gmail address, open the message, and choose Show original. At the top you'll see three lines:

text
SPF:    PASS with IP ...
DKIM:   'PASS' with domain example.com
DMARC:  'PASS'

All three should say PASS, and the DKIM domain should be your domain, not the provider's. If DKIM shows the provider's domain, your sending domain isn't fully verified and you're relying on their reputation instead of building your own.

If you'd rather test from the command line, WP-CLI over SSH gives you the return value directly:

terminal
wp eval 'var_dump( wp_mail( "[email protected]", "API test", "Sent from WordPress." ) );'

Remember what true means here: the provider accepted the API request. Delivery is a separate question, answered by the provider's dashboard and by the message actually arriving.

Step 7 - Test the emails your site actually sends

The settings-page test uses the plugin's own code path. Real emails come from core, WooCommerce, and your form plugin, and they can differ in ways that matter, particularly around HTML content types and custom From headers.

Work through the list that applies to your site:

  1. Password reset. Log out, click "Lost your password?", and confirm the email arrives with a working link.
  2. New user registration, if registration is open.
  3. A contact form submission. Many form plugins set their own From address, often to the visitor's email address. That will fail domain verification at the provider. Configure the form to send from your domain and put the visitor's address in Reply-To instead. This is one of the most common causes of "it works except for the contact form".
  4. A WooCommerce order. Place a test order and confirm both the customer confirmation and the admin notification arrive. Order emails are HTML, which exercises a different path.
  5. An admin notification, such as a plugin update or a core update notice.

Check the provider's activity log alongside your inbox. It will show you accepted, delivered, bounced, and complained events, which is far more information than WordPress has ever given you.

Step 8 - Set up logging and monitoring (Optional)

Optional, but the difference between finding out about a delivery problem yourself and finding out from an angry customer.

Magic API Email version 1.1.0 added an email log stored in a custom database table, recording recipient, subject, provider, status, and error details, with Logs and Statistics tabs on the settings screen. That gives you a per-site record of what WordPress tried to send and what happened.

API errors are also written to the WordPress debug log with a [Magic API Email] prefix, which requires debug logging to be enabled:

php
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );

Set WP_DEBUG_DISPLAY to false so errors go to the log rather than to visitors' screens. On MagicWP you can set these as per-site environment variables rather than editing wp-config.php directly.

For monitoring beyond the site, two things are worth the setup time:

  • Your provider's dashboard, which shows bounce and complaint rates. A rising hard bounce rate usually means a list quality problem; a rising complaint rate means you're sending things people didn't ask for.
  • Google Postmaster Tools, which reports your domain's spam rate as Gmail sees it. Google's own guidance is to keep the spam rate reported in Postmaster Tools below 0.10% and avoid ever reaching 0.30% or higher. The 0.3% number gets quoted everywhere as the target. It isn't. It's the ceiling.

If you have an email logging table growing on a busy site, prune it periodically. A log table nobody trims is a slow-growing database problem.

Troubleshooting

Symptom Likely cause Fix
Test email never arrives, no error API key wrong, revoked, or from a different account Generate a fresh key and re-enter it
Provider returns a 403 or "domain not verified" Sending domain not verified, or From address on a different domain Complete domain verification; set From to an address on that domain
Mail arrives but lands in spam DKIM or DMARC not passing Check Show original; verify all three lines say PASS
Everything works except the contact form Form plugin overrides From with the visitor's address Send from your domain, put the visitor in Reply-To
Only Mailgun fails Missing or wrong Mailgun sending domain Enter the Mailgun domain alongside the key
Mail sends but recipients never see it Mailtrap sandbox capturing messages, or Mailgun sandbox domain Switch to a delivery stream or a verified custom domain
Worked yesterday, fails today Key revoked, provider account suspended, or trial expired Check the provider dashboard first, not WordPress
Emails duplicated Two mail plugins both hooked into sending Deactivate one; only one should intercept wp_mail()
Saved settings won't update Write-only key storage requires re-entry Re-enter the API key when changing other fields

When you're genuinely stuck, work outward in this order: WordPress log, then provider activity log, then DNS records, then the receiving side's headers. The failure is almost always visible at one of those four points, and people usually skip straight to the last one.

Frequently Asked Questions

Do I still need SPF and DKIM if I'm using an API?

Yes, and this is the most common misunderstanding about API sending. The API is only the transport between WordPress and the provider. Receiving servers still evaluate the message against your domain's DNS records. Without SPF and DKIM published for your sending domain, your mail is unauthenticated regardless of how it got to the provider, and Google has required authentication from all senders since February 2024.

Can I use this plugin on a host other than MagicWP?

Yes. Magic API Email is a standard WordPress plugin published on WordPress.org and works on any host meeting its WordPress and PHP requirements. Nothing in it depends on MagicWP infrastructure. The dashboard route in Step 5.2 is the MagicWP-specific alternative, not a requirement.

Will this fix emails going to spam?

Partly. It fixes the technical half: authentication, sending reputation, and delivery infrastructure. It does not fix content problems, sending to people who didn't opt in, or a domain with existing reputation damage. If your spam rate in Postmaster Tools is already elevated, expect recovery to take weeks of consistent, wanted sending rather than a single configuration change.

What happens if the provider's API is down?

The send fails and the message is lost, the same as any other WordPress email failure. WordPress has no built-in retry queue for wp_mail(). If message loss is unacceptable for your use case, such as high-value order confirmations, look at a plugin or service that queues and retries failed sends rather than firing once during the page request.

Does this slow down my site?

Slightly, and less than SMTP. Any outbound send during a page request adds latency, but a single HTTPS POST is shorter and more predictable than an SMTP handshake, and it fails faster when something is wrong. Sends triggered by admin actions or cron have no visible effect on visitors at all.

Can I use one provider for transactional email and another for newsletters?

Yes, and you generally should. Keep newsletters on a platform built for them, with proper subscription management and one-click unsubscribe, and keep transactional mail on a provider tuned for delivery speed. Just make sure both are included in your SPF record and both sign with DKIM for your domain.

Do I need a separate email hosting service for my inbox?

Yes, these are different things. A transactional provider sends mail on behalf of your site; it does not give you an inbox at [email protected]. You still need Google Workspace, Microsoft 365, or another mailbox provider for receiving. The two coexist fine, as long as both appear in a single merged SPF record.

Conclusion

Setting up a WordPress email API is a short job with a long tail of benefit, but only if you do the part that matters. The plugin configuration takes five minutes. Verifying your sending domain, publishing a correct SPF record, getting DKIM signing with your own domain, and starting DMARC at p=none are what determine whether your password resets and order confirmations reach an inbox. Skip those and you've moved the problem rather than solved it.

Once it's working, check the provider's dashboard occasionally and glance at Postmaster Tools if you send any volume. Deliverability isn't a switch you flip, it's a reputation you maintain, and the reports are the only honest feedback you'll get.

If you're running WordPress on MagicWP, the provider configuration lives in the dashboard under Email, so there's no plugin to keep updated and no API key sitting in your database. For every other host, the plugin does the same job.

Next steps

A
Alex
MagicWP
Writing about WordPress, performance, and the infrastructure that makes sites fast.

Get the best of MagicWP in your inbox.

Monthly engineering notes, product updates, and WordPress performance tips. No spam, unsubscribe anytime.

Join 12,000+ builders. We send one email a month.