What it means to send email programmatically
Your application sends the email. A signup fires a confirmation, a payment fires a receipt, a failure fires an alert. No inbox, no compose window, no human in the middle. The code makes an authenticated request and delivery is handled.
There are two ways to do it, and one of them is why this page exists.
SMTP vs the API path
The old path is SMTP: smtplib in Python, Nodemailer in Node, JavaMail in Java. You configure a host, pick port 587 or 465, generate an app password for Gmail, and hold a connection open. Every language has its own library and every library has its own way of failing.
The API path is one HTTP POST. No SMTP library, no ports, no app passwords, no connection management. You get a message ID back, and delivery events after that.
I've been doing email for a decade and my companies have sent over 6 billion emails. Almost none of the pain in that decade came from the send itself. It came from everything wrapped around it. The API path deletes most of the wrapping.
And the wrapping is where the speed lives now. In one week we shipped a rebuilt visual email builder that Claude and Codex can prompt, five provider integrations, OAuth agent connect, and thirty-plus fixes from live user sessions. A protocol from 1982 was never going to keep that pace.
One call, any language
import requests requests.post( "https://api.nitrosend.com/v1/my/messages", headers={"Authorization": "Bearer $NITROSEND_API_KEY"}, json={ "from": "[email protected]", "to": "[email protected]", "subject": "Welcome", "html": "<p>You're in.</p>", }, )
Swap requests for fetch, curl_init, Net::HTTP, HttpClient, or reqwest and the call is the same. Bearer token, JSON body, message ID back. That is the whole contract, in every language we cover.
One field note from running the receiving end: Cloudflare's WAF blocks the default Python-urllib user agent, so a bare urllib script gets a cryptic 403 with error code 1010 while the identical call through requests sails through. Set a real User-Agent and move on. We learned to watch for this the interesting way: an audit of our own traffic turned up 3,228 tool calls with a blank user agent, almost all of them OAuth requests from Codex, which sends no User-Agent at all.
My take: the language guides are where most providers hide their worst docs. Ours are the first thing agents read, so they have to be exact.