What SMTP fixes about mail()
mail() hands your message to the server's local sendmail, unauthenticated, from an IP with no sending reputation. Delivery is a coin flip weighted against you. Moving to SMTP through an authenticated account fixes the identity problem: mail now comes from a real account on real infrastructure.
That is why every PHP framework guide ends at SMTP config: host, port, username, password, encryption, in your config file, in every environment, forever.
What SMTP still doesn't fix
SMTP is a transport, not a platform. You still get no delivery events, no bounce handling, no suppression list, and credentials that rotate through your config are a liability with a copy in every backup.
$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);
One bearer token instead of five config keys, and the answer to "did it arrive" is an event on your webhook instead of a shrug.
While you're fixing transport, fix cadence too. The number one reason people unsubscribe is frequency, and complaint rates spike hardest when a sender jumps from no email to three or four a week. Transport gets you to the inbox. Restraint keeps you there.
And server SMTP is escapable at any size. We ran a migration moving a publisher off server SMTP onto the platform against a hard cutover date. If a publisher's whole stack can leave server SMTP behind on a deadline, your config file can too.
That migration also stress-tested how a platform should handle trouble. When two of the publisher's onboarding flows tripped bounce and complaint thresholds mid-cutover, the account moved into a quarantine cohort that isolated the risk while everything else kept sending. The raw-infrastructure answer, the one SES gives you, is to shut the whole account off. The difference between those two responses is a business continuing to operate.
Full parameters and responses live in the REST API docs and the API reference.
Go deeper
Zoom out from the SMTP config for a second. The real fix for "how do I send mail from PHP" is not a cleaner host, port, username block, it is skipping the block. Describe the email to Claude, Cursor, or Codex and our MCP server sends it on the same account, no credentials file and no cURL call to write.
If you're settling on SMTP anyway, at least skip the hand-rolled socket code: PHPMailer via Composer. The full PHP guide: send email with PHP. The port you pick matters less than the records behind it, so read SMTP ports alongside SPF, DKIM and DMARC authentication.
FAQ
How do I send mail using SMTP in PHP?
Use PHPMailer or your framework's mailer with an authenticated SMTP account: host, port 587, username, password, STARTTLS. It fixes mail()'s authentication problem but still gives you no delivery events or bounce handling.
Is SMTP better than mail() in PHP?
Yes: authenticated identity and real infrastructure instead of the web server's bare IP. An email API is the step after: token auth, delivery events, and no SMTP credentials in config.