Sender.net exposes one versioned REST API at https://api.sender.net/v2/, authenticated with a Bearer token, covering eleven resource families from subscribers and groups through campaigns, workflows and transactional sends. First-party transactional SDKs ship for PHP and Node.js/TypeScript plus a hosted browser JavaScript SDK, no official Python, Go or Ruby client. The 2026 headline is a genuine first-party remote MCP server at https://mcp.sender.net/mcp with roughly 40 OAuth-scoped tools, putting Sender ahead of MailerLite and EmailOctopus on agent tooling.
MCP is how an AI client. Claude, ChatGPT, Cursor, gets structured, permissioned access to a SaaS account instead of scraping a dashboard or holding a raw API key. For an ESP the practical questions are whether the vendor runs its own server, what the tool surface reaches, and what stops a model from mailing a real list by accident.
The endpoint is https://mcp.sender.net/mcp-Streamable HTTP with JSON-RPC 2.0 and OAuth 2 bearer auth on scope mcp:use, discovered through RFC 9728 metadata at /.well-known/oauth-protected-resource. Roughly 40 tools span account discovery, subscribers and groups, segments, campaigns, workflows and the image library. It is documented as a standard feature, not a beta: no waitlist, no separate SKU, no key in a config file.
The guardrails are stricter than most vendor MCP servers. Campaigns created through MCP stay drafts; workflows stay inactive until an explicit activate_workflow call that only succeeds after validate_workflow passes; destructive actions require an acknowledgment flag; and the server inherits your plan and permission limits. One deliberate omission: no transactional send tool is exposed over MCP. Mail still leaves through the REST API or the smtp.sender.net relay-an agent that drafts a campaign but cannot fire it is a materially different risk profile.
Three MCP surfaces reach Sender in 2026, two of Sender’s own, plus a third-party wrapper through Zapier.
Hosted remote server at https://mcp.sender.net/mcp. Streamable HTTP, JSON-RPC 2.0, OAuth 2 browser consent, revocable at any time. Roughly 40 tools across account discovery, subscribers, groups, segments, campaigns, workflows and images.
Spec page for the same server inside the API reference: transport, OAuth discovery flow and the full tools/list inventory. Read it before wiring a non-Claude client.
Exposes Sender’s Zapier actions, add or update subscriber, add to group, create campaign, send campaign, unsubscribe. Third-party wrapper, not a Sender product, and narrower than the native server.
MCP is a real differentiator at the low end of the ESP market. If your team already works inside Claude or Cursor, a native server means list hygiene, segment building and campaign drafting happen without a script or a CSV export. Brevo and Moosend publish no equivalent first-party server, so agent workflows there fall back to wrappers or Zapier. Weigh that against Sender’s smaller endpoint surface: a native MCP server on a narrower API is still narrower.
The API is a conventional JSON REST surface. Every request goes over HTTPS, plain HTTP is not supported and does not fall back, and every authenticated call carries an Authorization: Bearer header. There is one live version, v2, with no published v1 sunset or v3 roadmap.
| Base URL | https://api.sender.net/v2/ |
| Version | v2, pinned in the path HTTPS ONLY |
| Response format | JSON, with Accept: application/json recommended on every call |
| Pagination | Query string: ?page, ?limit, ?order, ?direction (asc or desc, defaults to desc) |
| Paginated payload | Four top-level keys: data, links, meta, has_more_resources |
| Resource families | 11-subscribers, groups, segments, fields, campaigns, statistics, transactional campaigns and send, workflows, custom events, webhooks |
| Rate-limit signalling | X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset on every response |
Sender returns has_more_resources as a boolean alongside meta.last_page, which makes a while-loop safe without arithmetic on page counts. A documented call reads https://api.sender.net/v2/campaigns?page=5&limit=20&order=modified&direction=desc. The order parameter takes a field key on the listed resource, not a fixed enum. Neither the default nor the maximum limit is published, read meta.per_page back from the first response rather than hard-coding one.
Sender runs three separate credential systems and none is interchangeable with the others. Confusing them is the most common failure mode on new accounts.
Create a token under Account settings → API access tokens and send it as Authorization: Bearer {API_ACCESS_TOKEN}. Tokens are account-scoped, not per-resource, so any token reaches any endpoint your plan permits. All tokens on an account share one rate-limit window, issuing separate tokens buys revocation granularity, not extra throughput.
The relay at smtp.sender.net authenticates with SMTP AUTH PLAIN or LOGIN over TLS, using a pair created under Transactional emails → Setup instructions → SMTP → Add SMTP user. You pick a base name and Sender appends a random suffix, producing handles such as Gabrielle_e736w1. It is never your account email, and never the literal string apikey. See the SMTP settings tab for the port and TLS matrix.
The MCP server does not accept the REST Bearer token. It runs a full OAuth 2 flow with browser consent on scope mcp:use, advertised via RFC 9728 metadata at /.well-known/oauth-protected-resource. In practice: add https://mcp.sender.net/mcp as a custom connector in Claude, enable developer mode in ChatGPT, or drop an mcpServers entry into a Cursor config, then approve the consent screen. Access is revocable from the dashboard without rotating your API token.
Pasting a Bearer access token into the password field of a WordPress SMTP plugin fails authentication, and an SMTP password sent to api.sender.net returns 401. The one-time SMTP password is displayed exactly once at creation and cannot be recovered, the documented recovery path is to delete the SMTP user and create a new one, then update every application still holding the old credential.
Sender deliberately publishes no fixed numeric rate limits. Limits are enforced per minute and tracked per account, every token on the account shares one window, and the value in force for your account is returned on every response.
| Limit | Value | Notes |
|---|---|---|
| API requests per minute | Not published | Returned per account in the X-RateLimit-Limit response header on every call |
| Window | Per minute, per account | All API tokens on one account share the same window |
| Over-limit response | HTTP 429 | Carries Retry-After in seconds; also read X-RateLimit-Reset |
| Attachment size | 25 MB per file | Per individual attachment; total MIME message size is not published |
| Free plan volume | 15,000 emails/month | Up to 2,500 subscribers, the real ceiling is the monthly allowance, not a throttle |
| Transactional log retention | 1 / 5 / 30 days | 1 day Free and Standard, 5 days Professional, 30 days Enterprise |
Treat the headers as the contract. Read X-RateLimit-Limit at startup to size your worker pool, decrement against X-RateLimit-Remaining in-process, and on a 429 sleep for exactly the Retry-After value rather than a generic exponential backoff, the server is telling you the precise reset. Because the window is per account, a batch import running beside a live transactional stream starves it: schedule bulk subscriber work outside your send windows. For hard throughput guarantees, pair Sender with a dedicated transactional provider.
Sender maintains two server-side packages, both transactional-only. Neither wraps the campaign, subscriber, group or workflow endpoints, those take plain HTTP calls. A narrower SDK story than Brevo offers, and the reason most Sender integrations end up as thin hand-rolled clients.
| Language | Package | Install | Repo |
|---|---|---|---|
| PHP | sendernet/sender-transactional-php | composer require sendernet/sender-transactional-php | GitHub |
| Node.js / TypeScript | @sendernet/sender-transactional-nodejs | npm install @sendernet/sender-transactional-nodejs | GitHub |
| JavaScript (browser) | Sender JavaScript SDK | Hosted tracking snippet, deployable via Google Tag Manager | Docs |
The PHP package (last updated December 9, 2025) ships a fluent EmailParams builder, typed exceptions and a first-class Laravel mail transport, that transport is the strongest reason to prefer it over raw cURL. The Node package (June 8, 2026) is TypeScript-first with a chainable SenderClient().email() builder. The browser SDK is a hosted script, not an npm package, covering custom event tracking and signup-form rendering.
On any stack other than PHP or Node you write the HTTP layer yourself. That is not hard, a flat JSON surface with one header, but budget for pagination, the 429 path and error parsing in your own code.
Sender curates no community SDK list, and no third-party client for Python, Go or Ruby has emerged with meaningful download volume as of August 2026. The practical substitutes are the official Zapier app, the WordPress and WooCommerce plugins, and the PrestaShop module in the sendernet GitHub organisation, last updated August 4, 2026. Anything else is hand-written, no OpenAPI spec is published.
The table maps what the v2 API reaches. Read it as a map rather than copy-pasteable routes: only a handful of paths are confirmed verbatim, and Sender’s docs render resource pages dynamically. Verify any sub-path you depend on against the official API reference before shipping.
| Resource | Methods | Description |
|---|---|---|
| Transactional send /v2/message/send | POST | One-off send. Requires from, to, subject, html. Liquid variables; attachments by public HTTPS URL. |
| Transactional campaign send /v2/transactional_campaigns/send-campaign/ | POST | Send from a stored template with substitution data. |
| Transactional campaigns /v2/transactional_campaigns | GET, POST, PATCH, DELETE | CRUD on transactional campaign templates. |
| Subscribers /v2/subscribers | GET, POST, PATCH, DELETE | List, create, fetch, update, delete subscribers. |
| Group membership /v2/subscribers/groups | POST, DELETE | Add or remove a subscriber from a group; a companion call removes a phone number. |
| Groups /v2/groups | GET, POST, PATCH, DELETE | Create, list, inspect, rename, delete groups. |
| Group subscribers /v2/groups/{id}/subscribers | GET | List every subscriber in a group, paginated. |
| Segments /v2/segments/ | GET, DELETE | List segments with conditions and counts, get one, delete. |
| Segment subscribers /v2/segments/{id}/subscribers | GET | Subscribers currently matching a segment. Confirmed verbatim. |
| Custom fields /v2/fields | GET, POST, PATCH, DELETE | Custom subscriber fields for personalisation and segmentation. |
| Campaigns /v2/campaigns | GET, POST, PATCH, DELETE | Create, list, get details or errors, copy, schedule, send, cancel, delete. |
| Statistics /v2/campaigns/{id}/stats/ | GET | Sends, opens, clicks, unsubscribes, bounces, spam reports; per-group on Professional. |
| Workflows /v2/workflows | GET, POST | List workflows, get details, steps and statistics, start one for a subscriber. |
| Custom events /v2/custom-events | POST | Fire a custom event to trigger automations. Also fireable from the JavaScript SDK. |
| Account webhooks /v2/account-webhooks | GET, POST, PATCH, DELETE | Paid plans only. CRUD on account webhooks for subscriber and delivery events. |
No official Python SDK exists, so this hits /v2/message/send with requests. The from address must sit on a domain already verified with SPF, DKIM and DMARC green, or the call is rejected.
import requests
url = "https://api.sender.net/v2/message/send"
headers = {
"Authorization": "Bearer YOUR_API_TOKEN",
"Content-Type": "application/json",
"Accept": "application/json",
}
payload = {
"from": "hello@yourverifieddomain.com",
"to": "user@example.com",
"subject": "Welcome to Acme",
"html": "<h1>Hi {{name}}</h1><p>Thanks for signing up.</p>",
"variables": {"name": "Alaa"},
}
response = requests.post(url, headers=headers, json=payload)
print(response.status_code)
print(response.json())
# Rate limiting: read X-RateLimit-Limit / X-RateLimit-Remaining / X-RateLimit-Reset.
# On HTTP 429, back off for the number of seconds in the Retry-After header.The TypeScript client wraps the same endpoint with a chainable builder. The commented block underneath is the equivalent plain fetch call, what you write on any stack without an official package.
import { SenderClient } from '@sendernet/sender-transactional-nodejs';
const client = new SenderClient({ apiKey: process.env.SENDER_API_TOKEN });
const response = await client.email()
.from('hello@yourverifieddomain.com', 'Acme')
.to({ email: 'user@example.com', name: 'Alaa Touil' })
.subject('Welcome {{name}}!')
.text('Thank you for signing up, {{name}}!')
.variables({ name: 'Alaa Touil' })
.send();
console.log('Email sent:', response.messageId);
// Plain fetch equivalent, no SDK:
// await fetch('https://api.sender.net/v2/message/send', {
// method: 'POST',
// headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
// body: JSON.stringify({ from, to, subject, html }),
// });No key goes in the config. The first tool call triggers the OAuth consent flow in the browser; the token is then held by the client and revocable from the Sender dashboard.
{
"mcpServers": {
"sender": {
"url": "https://mcp.sender.net/mcp"
}
}
}In Claude, add the same URL as a custom connector under Customize → Connectors; in ChatGPT, enable developer mode and add it as a remote MCP connector. Any client supporting remote MCP with OAuth 2 works.
The REST API uses a Bearer token from Account settings → API access tokens; the relay uses a generated username plus a one-time password from Transactional emails → Setup instructions → SMTP. An API token in an SMTP password field fails auth, and an SMTP password against api.sender.net returns 401. This trips almost everyone arriving from a platform that uses apikey as the SMTP username.
Sender gates transactional sending on domain verification, not just signup. Account settings → Domains must show three green checkmarks. SPF TXT with include:sendersrv.com, CNAME sender._domainkey to dkim.sendersrv.com, and a TXT _dmarc record, and the from address must be on that domain or the API rejects the request. Requiring DMARC at verification time is stricter than most competitors, and free mailbox domains such as gmail.com cannot be used at all.
Retention is 1 day on Free and Standard, 5 days on Professional, 30 on Enterprise. Debug a failure two days later on Standard and the log line is already gone. Free caps you at 1 event webhook and Standard at 5, so you cannot fully compensate by streaming events elsewhere without upgrading. Stand up the webhook sink before you need the forensics.
The roughly 40 MCP tools cover account discovery, subscribers, groups, segments, campaigns, workflows and images, but no transactional send. Campaigns stay drafts, workflows stay inactive until an explicit activate call after a successful validation, and destructive actions demand an acknowledgment flag. If you wanted an agent to fire transactional mail, that path runs through the REST API or SMTP with your own guardrails.
Sender publishes no dated release-notes feed for the API. The timeline below is assembled from Product Update posts on Sender’s blog and public repository activity in the sendernet GitHub organisation.
sendernet/senderautomatedemails) received its most recent public update.@sendernet/sender-transactional-nodejs last published: a TypeScript-first builder API wrapping /v2/message/send.sendernet/sender-transactional-php last updated, adding a fluent EmailParams builder, typed exceptions and a native Laravel mail transport.No v2 endpoint has been announced as deprecated and no v1 sunset date exists publicly. Watch the official API reference and the help center-neither carries an RSS feed or a versioned changelog.
The base URL is https://api.sender.net/v2/ and the current version is v2, pinned in the path rather than negotiated by header. All traffic must be HTTPS. Responses are JSON, and paginated endpoints return data, links, meta and has_more_resources as top-level keys.
Create an access token under Account settings → API access tokens and send it as Authorization: Bearer {token}. Tokens are account-scoped, so any token reaches any endpoint your plan allows, and all tokens share one rate-limit window. This token is not the SMTP credential and not the MCP credential.
Sender publishes no numeric figure. Limits are per minute and per account, and the value applying to your account comes back in X-RateLimit-Limit on every response, alongside X-RateLimit-Remaining and X-RateLimit-Reset. Exceeding it returns HTTP 429 with Retry-After. The practical volume ceiling is your plan’s monthly allowance-15,000 emails and 2,500 subscribers on Free Forever.
POST to /v2/message/send with from, to, subject and html. Liquid-style variables come through a variables object, and attachments are referenced by public HTTPS URL rather than uploaded inline. The from address must be on a domain verified under Account settings → Domains with SPF, DKIM and DMARC green, or the request is rejected.
PHP and Node.js yes, Python no. sendernet/sender-transactional-php ships a fluent builder and a Laravel mail transport; @sendernet/sender-transactional-nodejs is a TypeScript-first chainable client. Both are transactional-only and do not wrap campaigns, subscribers, groups or workflows. No official Python, Go, Ruby, Java or .NET client exists, and no OpenAPI spec is published to generate one from.
Yes, a genuine first-party remote server at https://mcp.sender.net/mcp, not a community wrapper. Streamable HTTP with JSON-RPC 2.0 and OAuth 2 on scope mcp:use, so no key is pasted into a config and access is revocable from the dashboard. Roughly 40 tools cover account discovery, subscribers and groups, segments, campaigns, workflows and images. Campaigns stay drafts, workflows stay inactive until explicitly activated, and there is deliberately no transactional send tool.
This review follows our email infrastructure testing methodology. We disclose affiliate relationships in our editorial independence policy.