Guides 12 min read ·
WordPress Not Sending Email? Fix It with an Email API
WordPress or contact forms not sending email? Why it happens and how to fix it with an email API (Brevo, Mailgun, Zoho, Gmail), plus SPF, DKIM and DMARC.
When WordPress is not sending email, the cause is usually the server, not WordPress: by default it hands mail to PHP's mail() function, which many hosts switch off, and whatever does get out is often filtered as spam. The fix that works almost everywhere is a mailer plugin such as WP Mail SMTP or FluentSMTP connected to an email service's API over HTTPS, plus SPF, DKIM and DMARC records on your domain. That route works even on hosts that block SMTP, including HostEthical.
The short version:
- Sign up with an email sending service (Brevo, Mailgun, Postmark, Zoho ZeptoMail or Google Workspace) and add the DNS records it gives you.
- Install WP Mail SMTP or FluentSMTP and pick that service as the mailer, using an API key or OAuth, not SMTP host and port settings.
- Set the From address to one on your own domain, such as
hello@yourbusiness.in. - Send a test email and check that SPF, DKIM and DMARC pass.
Why WordPress is not sending email
WordPress sends every email through one function, wp_mail(): form notifications, WooCommerce order emails and password resets. Out of the box it uses the PHPMailer library set to PHP's own mail(), with a From address of wordpress@ plus your domain. Three things commonly go wrong:
- The host doesn't let websites send mail. Hacked websites are often used to send spam, so many hosts disable
mail()or block outgoing SMTP ports. On HostEthical hosting, websites cannot send email from the server at all:mail()sends nothing, and outgoing SMTP ports 25, 465, 587 and 2525 are blocked for websites, cron jobs and SSH alike. - The mail leaves but gets filtered. Gmail, Outlook and Zoho check whether the sending server is allowed to send for your domain. Mail from a web server with no SPF or DKIM for your domain often lands in spam.
- The From address is wrong. Forms that put the visitor's Gmail address in the From field look like forgeries; Google's email sender guidelines tell senders not to impersonate Gmail From headers.
Quick test: is WordPress sending at all?
- Trigger a password reset. Log out, click "Lost your password?" and enter your admin username. Check the inbox and spam folder. This tests WordPress without your form plugin.
- Check where notifications go. Under Settings > General, look at the Administration Email Address for typos.
- Test from the command line. Over SSH (HostEthical hosting includes WP-CLI), run this in the site's folder.
bool(false)means WordPress couldn't hand the message over;bool(true)means it was handed over, not that it arrived.wp eval 'var_dump( wp_mail( "you@example.com", "Test", "Hello from WordPress" ) );' - For WooCommerce, open WooCommerce > Status > Logs and filter by the
transactional-emailssource, which records each order email attempt (WooCommerce email troubleshooting).
Nothing arriving means the server isn't sending; mail in spam means an authentication problem. The setup below fixes both.
SMTP vs an email API: why the API route works on more hosts
Older guides say to fill in an SMTP host, port, username and password, such as smtp.gmail.com on port 587. If your host blocks SMTP ports, the plugin times out however correct the settings are.
An email API sends each message to the provider as an HTTPS request on port 443, authenticated with an API key or OAuth. Hosts almost never block it, because websites need outgoing HTTPS for payment gateways and plugin updates. Laravel's mail documentation says API-based drivers "are often simpler and faster than sending mail via SMTP servers".
| SMTP | Email API | |
|---|---|---|
| Port | 25, 465, 587 or 2525 | 443 (HTTPS) |
| Credentials | Username and password, or an SMTP key | API key, or OAuth for Gmail |
| On HostEthical shared hosting | Does not work (ports blocked) | Works |
Which email service to use
You need a transactional email service, which sends your site's one-to-one emails (receipts, resets, form notifications) and authenticates them for your domain. Free allowances from each provider's pricing page, October 2026:
| Service | Free allowance | After that | Free plugin route |
|---|---|---|---|
| Brevo | 300 emails a day (campaigns and transactional combined) once your account is approved | Paid monthly plans | WP Mail SMTP, FluentSMTP |
| Mailgun | 100 emails a day, 1 sending domain | From $15 a month for 10,000 | WP Mail SMTP, FluentSMTP |
| Postmark | 100 emails a month, no expiry | From $15 a month for 10,000 | WP Mail SMTP, FluentSMTP |
| Zoho ZeptoMail | 10,000 emails on sign-up (one free credit, valid 6 months) | Pay-as-you-go credits of 10,000 emails, valid 6 months | Zoho's ZeptoMail plugin |
| Resend | 3,000 a month, at most 100 a day | From $20 a month for 50,000 | WP Mail SMTP |
| Amazon SES | None specific; new AWS customers get Free Tier credits | $0.10 per 1,000 emails | FluentSMTP |
| SendGrid | No free plan since May 2025; one-time 60-day trial, 100 a day | Paid plans | WP Mail SMTP, FluentSMTP |
| Gmail / Google Workspace | 500 a day (personal Gmail), 2,000 (Workspace) | Part of your Google account | WP Mail SMTP, FluentSMTP |
Free tiers change, so check before you sign up. How to choose:
- Most small business sites: Brevo's free 300 a day covers a contact form and a small shop.
- Already on Zoho Mail: ZeptoMail is Zoho's transactional service, with its own free plugin. Zoho has begun renaming it Zoho CPaaS, so you may see either name. Your Zoho Mail mailbox over SMTP won't work where SMTP is blocked, and WP Mail SMTP's Zoho Mail API mailer is a Pro feature.
- Order emails you can't afford to lose: a paid Postmark or Mailgun plan, with detailed delivery logs.
- Gmail or Google Workspace: fine for low-volume notifications, sent from that Google address. Google's limits are 500 a day for personal Gmail and 2,000 for Workspace (500 during a trial).
Step by step: WP Mail SMTP or FluentSMTP with an API mailer
Both plugins take over how wp_mail() sends, so Contact Form 7, WPForms, WooCommerce and other plugins use your service automatically. Run only one mail plugin at a time.
| WP Mail SMTP (Lite) | FluentSMTP | |
|---|---|---|
| Price | Free; paid Pro version | Free, no paid version |
| Free API mailers | Brevo, Mailgun, Postmark, SendGrid, Resend, Mailjet, SparkPost, SMTP2GO, Gmail and others | Amazon SES, Brevo, Mailgun, Postmark, SendGrid, SparkPost, SMTP2GO, Gmail, Microsoft 365 and others |
| Pro only | Amazon SES, Zoho Mail, Microsoft one-click setup, email log | Nothing |
| Email log | Pro | Included, with resend and a fallback connection |
Source: WP Mail SMTP 4.10.2 and FluentSMTP 2.4.1 on WordPress.org, October 2026. FluentSMTP is the better free pick if you want logs; WP Mail SMTP if your service, such as Resend, is only in its list.
Example: Brevo with WP Mail SMTP
- Create a free Brevo account and wait for it to be approved for sending.
- In Brevo, go to Settings > Senders, domains, IPs > Domains and add your domain. Brevo shows the DNS records to add: a Brevo code TXT record, DKIM (one TXT record or two CNAME records) and a DMARC record. Add them, but keep any DMARC record you already have rather than adding a second. Then ask Brevo to authenticate the domain.
- Under Settings > SMTP & API, open the API keys tab and generate a key. Copy it straight away; Brevo shows it only once. It must be an API key, not an SMTP key.
- In WordPress, install WP Mail SMTP and open its Settings. Set the From Email to an address on your verified domain (tick Force From Email so every plugin uses it), choose Brevo as the mailer and paste the key.
- Go to WP Mail SMTP > Tools > Email Test and send a test to a Gmail address. In Gmail, choose "Show original" and check that SPF, DKIM and DMARC say PASS.
Gmail or Google Workspace through the Gmail API
In Google Cloud Console, create a project, enable the Gmail API, fill in the OAuth consent screen, create a "Web application" OAuth client with the redirect URI the plugin gives you, and publish the app. Paste the Client ID and Client Secret into the plugin and authorise your Google account. In WP Mail SMTP the manual setup is free and one-click setup needs Pro (WP Mail SMTP's Gmail guide). Skip guides that use an app password with smtp.gmail.com: that is SMTP.
Zoho ZeptoMail
Install Zoho's free ZeptoMail plugin, choose your hosted region, and enter the From address and the sending token from your ZeptoMail Mail Agent. It sends all wp_mail() traffic through the ZeptoMail API, so you don't need another mail plugin.
Contact forms and WooCommerce: settings to check
Once a mailer is connected, most "contact form not sending email" problems come down to the form's own settings.
- From address on your own domain. Contact Form 7's mail guide says to use a From address that belongs to the same domain as the site.
- The visitor's address in Reply-To. In Contact Form 7, add
Reply-To: [your-email]to Additional headers on the Mail tab, so Reply answers the visitor. Most form plugins have a Reply-To field. - A From address that really exists as a mailbox or forward at your email provider, so replies and bounces don't vanish. HostEthical doesn't host mailboxes; see email on your own domain for options.
- WooCommerce emails switched on. In WooCommerce > Settings > Emails, open each email and check that "Enable this email notification" is ticked and the recipient is right.
Add SPF, DKIM and DMARC so your mail lands in the inbox
These DNS records prove your mail is genuine. Since February 2024, Google requires everyone sending to Gmail to use SPF or DKIM, and senders of more than 5,000 messages a day to Gmail accounts need all three. Set up all three anyway; they cost nothing.
| Record | What it does | Where it goes |
|---|---|---|
| SPF | Lists the services allowed to send for your domain | One TXT record on the domain, starting v=spf1 |
| DKIM | Signs each message; receivers check it against a key in your DNS | TXT or CNAME records from your provider, on names ending ._domainkey |
| DMARC | Tells receivers what to do when checks fail, and where to send reports | One TXT record at _dmarc |
- Only one SPF record. If your domain already has one for Zoho Mail or Google Workspace, add the new service to it rather than creating a second; RFC 7208 treats two SPF records as an error and caps DNS lookups at 10. With placeholder values:
Some services ask only for DKIM and a verification record. Add exactly what their dashboard shows.v=spf1 include:mailbox-provider.example include:sending-service.example ~all - DKIM does the heavy lifting. The service signs your mail with your domain's key, so DMARC can pass even though the message leaves from its servers.
- Start DMARC gently. Google recommends waiting 48 hours after SPF and DKIM, starting with
p=noneand moving to quarantine or reject over time:Name: _dmarc Type: TXT Value: v=DMARC1; p=none; rua=mailto:dmarc@yourbusiness.in
Add the records where your DNS is hosted: the free HostEthical DNS editor if your domain uses ns1 and ns2.hostethical.com, or Cloudflare or another DNS host if your nameservers point there. See DNS records explained and connecting a domain to hosting.
Non-WordPress sites and SMM panels
The same rule applies to any PHP site, Laravel app or SMM panel script: if it only offers SMTP or mail(), sign-up confirmations and password resets fail silently on a host that blocks them.
Laravel
Laravel 13 ships API mail drivers for Cloudflare, Mailgun, Postmark, Resend and Amazon SES. For Postmark, install the transport over SSH and set .env:
composer require symfony/postmark-mailer symfony/http-client
# in .env
MAIL_MAILER=postmark
POSTMARK_API_KEY=your-postmark-server-token
MAIL_FROM_ADDRESS=orders@yourbusiness.in
Older Laravel apps read POSTMARK_TOKEN instead; use the name in your config/services.php. Then run php artisan config:clear. Brevo works through Symfony's Brevo mailer with the brevo+api transport, as Laravel's docs show. Don't leave MAIL_MAILER=smtp.
Plain PHP and SMM panel scripts
Ask the script's developer whether it supports an API mailer; many panel scripts only have SMTP fields. If you're comfortable editing PHP, a few lines of cURL will do. This uses Brevo's transactional email endpoint, with the key in a small PHP file outside public_html that returns it:
<?php
$apiKey = require __DIR__ . '/../private/brevo-key.php';
$payload = [
'sender' => ['name' => 'Your Shop', 'email' => 'orders@yourbusiness.in'],
'to' => [['email' => $customerEmail]],
'replyTo' => ['email' => 'support@yourbusiness.in'],
'subject' => 'Your order is confirmed',
'htmlContent' => '<p>Thanks for your order.</p>',
];
$ch = curl_init('https://api.brevo.com/v3/smtp/email');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['api-key: ' . $apiKey, 'Content-Type: application/json', 'Accept: application/json'],
CURLOPT_POSTFIELDS => json_encode($payload),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 15,
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status < 200 || $status >= 300) {
error_log('Email API error ' . $status . ': ' . $response);
}
Despite /smtp/ in the path, that is an ordinary HTTPS request on port 443. Our comparison of VPS and shared hosting covers when a panel outgrows shared hosting.
Still not working? A troubleshooting checklist
- "Connection timed out" or "Could not connect to SMTP host": the plugin is using SMTP and the port is blocked. Switch to the provider's API mailer.
- "Unauthorized" or "Invalid API key": an SMTP key or password went into the API key field, or the key was deleted. Generate a fresh API key. On Brevo, "unauthorized: not verified" or "IP not authorized" means Brevo blocked your server's IP: approve it from the "Validate your IP address" email or under Settings > Security > Authorized IPs.
- "Sender not verified": the From address must be on the domain you verified, and DNS changes can take 24 to 48 hours to propagate.
- The test works but a form doesn't: check the form's own To, From and Reply-To fields, and that only one mail plugin is active.
- Mail lands in spam: in Gmail's "Show original", a FAIL usually means a missing DKIM record, a second SPF record, or a From address on another domain.
- Some emails send, others don't: you may have hit a daily cap, such as 300 on Brevo's free plan or 100 on Mailgun's. The provider's dashboard shows rejected messages.
- Gmail sending suddenly stopped: changing your Google password or two-step settings can cancel the authorisation. Reconnect it.
- Still stuck: check the error log in your hosting dashboard and the plugin's log (free in FluentSMTP), then contact us with the exact error.
Choosing a host for a new site? Our guide to WordPress hosting in India covers what else to check.
Frequently asked questions
Why is my WordPress contact form not sending emails?
Usually the server can't send mail through PHP mail() or blocks SMTP, or the message is filtered as spam because the domain has no SPF or DKIM or the form puts the visitor's address in the From field. Connect a mailer plugin to an email service's API, use a From address on your own domain, and put the visitor's address in Reply-To.
Is WP Mail SMTP free?
Yes, the Lite version on WordPress.org is free and includes API mailers such as Brevo, Mailgun, Postmark, SendGrid, Resend and Gmail. Amazon SES, Zoho Mail, Microsoft one-click setup and the email log need the paid Pro version. FluentSMTP is a fully free alternative that includes email logs.
Can I use Gmail to send WordPress emails?
Yes. Connect Gmail or Google Workspace through the Gmail API with OAuth in WP Mail SMTP or FluentSMTP, not with an app password over SMTP. Google allows 500 messages a day on a personal Gmail account and 2,000 on Google Workspace, and the mail goes out from your Google address.
Do I need SPF and DKIM records for website emails?
Yes. Google requires everyone sending to Gmail to use SPF or DKIM, and senders of more than 5,000 messages a day need SPF, DKIM and DMARC. Add the records your email service gives you, keep a single SPF record and a single DMARC record for the domain, and start DMARC with p=none.