Send email with PHP

PHP's mail() function is where deliverability goes to die: no authentication, no feedback, no delivery events. Sending email from PHP properly is one authenticated HTTP request.

Verified By Kam Low, Co-founder · Updated August 19, 2026

Why mail() fails you

mail() looks free. It hands your message to whatever the server's sendmail is, unauthenticated, and reports success the moment it leaves PHP, not when it reaches an inbox. No SPF alignment, no DKIM signature, no bounce handling. Mailbox providers treat that kind of mail accordingly.

The usual next step is PHPMailer over SMTP, which fixes authentication and adds a dependency, credentials in config, and a connection to manage. The step after that is the one worth taking.

Deliverability is the part mail() hides from you completely. A brand-new sending domain has no reputation, and its first sends to Gmail commonly land in spam or get greylisted until warmup settles it. We have watched that exact curve on customer domains in our own support threads. It is also why sending happens from your own verified domain here, verification takes about a minute, rather than through a personal Gmail account. Nick on our team once audited domain verification and found 13 accounts that were not sending from the address they wanted, every one down to missing DNS records. And the sandbox sender is a trial run, not a home: connecting a custom domain is the single change that most improves deliverability and recipient trust. Our email protocols and ports section keeps plain definitions of the moving parts, headers included.

When placement does go wrong, we diagnose it the same way every time: a step-by-step triage across authentication, reputation, content, and the AI-mediated inbox, where Gemini summaries read your mail before humans do and open rate is mostly noise. George, our CEO, maintains that triage publicly in his Email Marketing Bible, built from 908 sources and the experience of running SmartrMail.

Authentication is also no longer a human chore. My own agent writes the SPF, DKIM, and DMARC records on a subdomain and verifies the alignment itself. The part of email PHP developers dread most is now a prompt.

One POST, and the send is handled

PHPPOST /v1/my/messages
$ch = curl_init("https://api.nitrosend.com/v1/my/messages");
curl_setopt_array($ch, [
  CURLOPT_HTTPHEADER => ["Authorization: Bearer $NITROSEND_API_KEY"],
  CURLOPT_POSTFIELDS => json_encode([
    "from" => "[email protected]",
    "to" => "[email protected]",
    "subject" => "Welcome",
    "html" => "<p>You're in.</p>",
  ]),
]);
curl_exec($ch);

cURL ships with PHP, the token lives in your environment, and delivery, authentication, and events are the platform's job. WordPress, Laravel, or plain PHP, the call is the same.

PHP developers are not a side audience for us. WooCommerce has more installs than any other ecommerce platform, and WooCommerce developers ask us more questions about the API than anyone else. This page exists because of them, and the platform slots into a PHP stack as the MAIL_DRIVER, so every transactional, marketing, and automated send lands in one place instead of scattered across plugins.

The API splits testing from sending on purpose. There is nitro_send_test_message for tests and nitro_send_message for the real thing, because offering a test send before any real send is a rule of George's that we build to, not a nicety. The renderer behind them ships against real clients too: no merge goes out until a real Outlook, Gmail app, and Yahoo pass, since local QA cannot exercise Outlook.

You also keep your own HTML. The best ESPs never force a choice between raw HTML and templates, SendGrid takes a content field, Postmark an HtmlBody, Mailgun an html parameter, and neither do we. Raw HTML is for control and drop-in migration, templates are for in-app management. Chong on our team puts the reason bluntly: HTML emails are quite bad, so the platform should absorb that badness for you.

And the pipeline is watched in production, with numbers. Over one recent 14-day window, 755 per-contact failures were correctly muted while 107 SES-suppression failures produced about six false alerts across two accounts, which we fixed by teaching the notifier that a single suppressed recipient is not a domain problem. Traditional email APIs are reliable, but that is where it ends. Built on legacy infrastructure, they lack the flexibility and intelligence this class of problem needs, and that gap is the reason we exist.

Full parameters, responses, and error codes live in the REST API docs and the API reference.

Python Node.js PHP Go Rust +5
send.py requests ยท stdlib-adjacent
import requests

requests.post(
  "https://api.nitrosend.com/v1/messages",
  headers={"Authorization": f"Bearer {KEY}"},
  json={"to": to, "subject": subj,
        "html": body})
202 ACCEPTED
{ "id": "msg_9f2c",
  "status": "accepted" }

And the part no library gives you

The same account exposes an MCP server, so the agent writing your code can also run your email. Point Claude, Cursor, or Codex at api.nitrosend.com/mcp and it composes, previews, and stages sends, with a human approving every one. The API is for your code. The MCP is for your agent. One platform either way.

Every send comes back with a message ID, and delivery events follow on your webhook: delivered, opened, bounced. No dashboard required to know what happened. If you are staying on SMTP, how to set up SMTP is the setup to follow, and SPF, DKIM and DMARC authentication is what stops those sends landing in spam.

Go deeper

First send in thirty seconds.

Simple pricing. Unlimited contacts.

Every plan includes full stack emailing: Flows, Newsletter Campaigns and Transactional Email, plus our NitroWheel LLM and all agent integrations (Claude, ChatGPT, Codex, Cursor and others). Pay for what you send, not who you store.

Plan limits are ceilings, not guaranteed immediate send headroom; only mature, clean volume sent through that exact sender can raise its capacity.

Free
$0
forever
  • Emails 8,000then 500/mo
  • Email types Transactional & Marketing
  • AI actions 20/mo
  • Contacts Free & Unlimited
  • Brands 3
  • Seats 1
  • Commercial recipients / rolling 24h 100
  • Email validation Prepaid only
Start free
Ultra
$100
per month
  • Emails 125,000/month
  • AI actions 5,000/mo
  • Brands 10
  • Seats 10 · Domains 10
  • Frontier AI Included
  • Dedicated IP Available
  • Commercial recipients / rolling 24h 62,500
  • Email validation Prepaid only
Get started
Enterprise
$300
per month
  • AI actions Unlimited
  • Unlimited brands & domains Included
  • SSO / SAML Included
  • 99.9% SLA Included
  • Commercial recipients / rolling 24h Contracted
  • Email validation Prepaid only
Get started

Free forever. No credit card required. See full comparison →