Transactional email service
Mailjet logo

Mailjet API + MCP (2026): v3 REST, v3.1 send, read-only MCP

Mailjet runs two API versions side by side and they are not interchangeable: v3 is the REST platform for every non-send resource, v3.1 exists only for the Send API. Authentication is HTTPS Basic Auth with the same key pair that powers the SMTP settings, and Mailjet ships 7 official SDKs plus an EU-resident API host at api.eu.mailjet.com. On MCP it is ahead of the field — a first-party server since September 30, 2025 — but read-only, so an agent can interrogate your account and cannot send from it.

At a glance

v3 + v3.1
Live API versions
REST on /v3/REST/, Send API on /v3.1/send. No /v3.1/REST/ exists.

7
Official SDKs
PHP, Node.js, Python, Ruby, Java, Go and C#/.NET.

Official
MCP server status
Apache-2.0, read-only, EU-aware via MAILJET_API_REGION=eu.

MCP integration in 2026

MCP is how an AI client reaches into a SaaS account without a bespoke plugin. For an ESP the question is not whether a wrapper exists on GitHub, but whether the vendor ships one and what it may do.

Official first-party MCP server, read-only by design

Mailjet published its own MCP server on September 30, 2025, Apache-2.0, with the write-up on October 31, 2025. It speaks stdio, authenticates with MAILJET_API_KEY in api_key:secret_key form, and routes to EU infrastructure when you set MAILJET_API_REGION=eu. The help centre states the constraint plainly — read only, for exploring contacts, campaigns, segments, statistics and workflows.

Available MCP servers

Three of the four below are Mailjet’s own material; the fourth is Zapier’s hosted endpoint, the only route offering write actions.

Why buyers should care

Most ESPs in this bracket still have no first-party MCP server, so this is a real differentiator rather than a checkbox. The read-only boundary is a feature if your risk model says an LLM must never touch production sending, and a blocker if you budgeted for agent-driven campaigns — in which case pair the official server for analysis with a direct Send API path for execution. And MAILJET_API_REGION=eu lets an EU buyer wire an AI client to their account without the request leaving EU infrastructure, the same reason Mailjet wins on residency against SendGrid.

Mailjet API essentials

The version split is the first thing to internalise: everything that is not a send — contacts, lists, campaigns, templates, statistics, senders, DNS, webhooks, parse routes — lives at /v3/REST/ and always will.

Base URL (global)https://api.mailjet.com
Base URL (EU residency)https://api.eu.mailjet.com GDPR
REST resources/v3/REST/{resource}
Send API (current)POST /v3.1/send
Send API (legacy, still live)POST /v3/send
Response formatJSON, with Count, Total and a Data array on REST reads
PaginationOffset-based: Limit (default 10, max 1000), Offset, Sort
Attachment ceiling15 MB per message, v3 and v3.1 alike
WebhooksEvent API, 7 event types, batched arrays

Limit defaults to 10, so a first call to /v3/REST/contact returns ten records and an integrator concludes the account is nearly empty. Raise it to 1000, read Total from the envelope, and increment Offset until you have the lot. There is no cursor pagination, so the client owns the loop. Mailjet publishes no HTTP request timeout, so set your own client-side deadline.

Authentication methods

HTTPS Basic Auth (API Key and Secret Key)

Every Email API endpoint authenticates with HTTPS Basic Auth: username is your API Key (public), password your Secret Key (private), both under Account settings › SMTP and SEND API settings. The relay at in-v3.mailjet.com expects the same pair, so rotating a key breaks both transports at once — plan it with your SMTP settings open. All seven SDKs read it from MJ_APIKEY_PUBLIC and MJ_APIKEY_PRIVATE.

API tokens for the IFrame API

The /v3/REST/apitoken resource issues short-lived tokens for embedding Mailjet UI components in your own product. Scoped to that job — not a replacement for Basic Auth, and not a way to give a partner limited access.

Additional API keys for isolation

Another key from /v3/REST/apikey is how Mailjet does sub-accounts: separating transactional from marketing, or ring-fencing staging. Deactivate with IsActive: false on a PUT rather than deleting; per-key lifetime usage is at /v3/REST/apikeytotals.

Additional API keys are data silos, not permission scopes

Mailjet has no OAuth 2.0 flow and no scoped-token model — a key is all-or-nothing on its account. The only way to narrow access is a second key, and that key brings its own contact database: contacts, lists, segments and templates are not shared between keys, including the main one, and there is no merge afterwards. Decide the topology before you import contacts, and use a MetaSender so a sender validated once is reusable across keys.

Rate limits

Mailjet is unusually sparse here. The honest table has more blanks than most competitors would like; what follows is only what Mailjet publishes.

LimitDocumented valueNotes
Attachment / message size15 MBThe only hard size ceiling in either Send API guide.
Test Mode send rate10 emails/hourNew, unreviewed accounts until they leave Test Mode.
Free plan volume6,000/month, 200/dayPlus a 1,000-contact ceiling since October 6, 2025.
Daily Send Limit per key5x subscription limitPaid accounts; Contract defaults to Unlimited. Settable per key; 0 blocks it.
Pagination page size1000 max, 10 defaultPer request on /v3/REST/ resources.
API requests per minute, steady-state emails/hour, recipients per message, concurrent SMTP connectionsNot publishedNone of these four appear in official documentation. The developer-portal rate-limits page renders client-side and exposes no figure; new customers sit under an unpublished hourly cap.

The workaround is empirical: ramp deliberately, instrument for HTTP 429 and SMTP deferrals, and back off exponentially. Mailjet tells new customers to demonstrate good performance over at least one week before the initial hourly limit lifts, which gives the shape of the ramp if not the number. If you need a published requests-per-second figure, Postmark and MailerSend are more forthcoming.

Official SDKs

Seven wrappers are published under the github.com/mailjet organisation. All share one design: construct a client with the key pair, set the API version at client level, then call resources.

LanguagePackageInstallRepo
Pythonmailjet-restpip install mailjet-restapiv3-python
Node.jsnode-mailjetnpm install node-mailjetapiv3-nodejs
PHPmailjet/mailjet-apiv3-phpcomposer require mailjet/mailjet-apiv3-phpapiv3-php
Rubymailjetgem install mailjetmailjet-gem
Javacom.mailjet:mailjet-clientMaven or Gradle dependencyapiv3-java
Gomailjet-apiv3-gogo get github.com/mailjet/mailjet-apiv3-goapiv3-go
C# / .NETMailjet.Apidotnet add package Mailjet.Apiapiv3-dotnet

Maintenance is uneven across the seven

Python and Node.js show the most recent movement: the Python README documents Python 3.10+ tested to 3.14, and node-mailjet v6.0.11 shipped on October 27, 2025 with TypeScript types. PHP is the transport underneath Mailjet’s WordPress and PrestaShop plugins. Java, Go and .NET remain functional but see less traffic — for a new integration choose Python or Node.js.

Notable community SDKs

Because the API is Basic Auth over JSON with no signing step, the framework ecosystem reaches Mailjet through generic mail transports rather than dedicated third-party SDKs: Symfony and Laravel through their mailer abstractions, Rails through the official gem’s ActionMailer hook. For anything else, write forty lines against the REST endpoints rather than adopting an unofficial wrapper that may be abandoned.

Endpoints reference

The fifteen resources below carry almost all real integration traffic. Full reference: Mailjet’s Email API reference and the open-source api-documentation repo, often easier to read because the portal renders client-side.

ResourceMethodsDescription
Send API v3.1
/v3.1/send
POSTCurrent transactional send. A Messages array of From, To, Subject, TextPart, HTMLPart, TemplateID and Variables. Supports partial success.
Send API v3 (legacy)
/v3/send
POSTOlder flat payload with FromEmail, Text-part, Html-part and either Recipients or To/Cc/Bcc. Source of most version confusion.
Contact
/v3/REST/contact
GET, POST, PUTIndividual contacts. PUT with IsExcludedFromCampaigns toggles the global exclusion list.
Bulk contacts
/contact/managemanycontacts
POSTAsync create or update of many contacts. Returns a job reference to poll.
Contact list
/v3/REST/contactslist
GET, POST, PUT, DELETEMailing lists. Creation needs only a Name.
Add contact to list
/contactslist/{id}/managecontact
POSTAdd, remove or unsubscribe one contact on a list, creating it in the same call.
Contact metadata
/v3/REST/contactmetadata
GET, POST, PUT, DELETECustom property schema; /contactdata/{id} holds per-contact values.
CSV import
/v3/REST/csvimport
GET, POSTBulk import job, and the bulk-exclusion path — which must omit ContactsListID.
Campaign draft
/v3/REST/campaigndraft
GET, POST, PUTCampaign lifecycle: detailcontent, test, send, schedule (ISO 8601), DELETE to cancel.
Template
/v3/REST/template
GET, POST, PUT, DELETEReusable templates; /template/{id}/detailcontent holds the body. Default headers are overridable per send.
Sender and domain
/v3/REST/sender
GET, POST, PUT, DELETERegister an address or whole domain, then activate via /sender/{id}/validate; /metasender reuses it across keys.
DNS check
/v3/REST/dns/{id_or_domain}
GET, POSTGET returns the SPF and DKIM values expected; POST on /check re-validates after DNS propagates.
Event callback URL
/v3/REST/eventcallbackurl
GET, POST, PUT, DELETEEvent API callback endpoints, one per event type, with an isBackup fallback URL.
Parse route
/v3/REST/parseroute
GET, POST, PUT, DELETEInbound routing; only the webhook Url is mandatory. Set Email to receive on your own domain.
Message and history
/v3/REST/message
GETPer-message delivery record; /messagehistory/{id} returns the full event trail.

Reporting sits in a family of resources rather than one endpoint: /v3/REST/statcounters is the general aggregator, while geostatistics, openinformation, clickstatistics, bouncestatistics and statistics/recipient-esp break the data out by country, user agent, click URL and mailbox provider.

Code examples

Sending with the Python SDK

# pip install mailjet-rest
import os
from mailjet_rest import Client

# version='v3.1' selects the current Send API. Omit it and you get the v3
# endpoint, which expects a different payload shape entirely.
mailjet = Client(
    auth=(os.environ['MJ_APIKEY_PUBLIC'], os.environ['MJ_APIKEY_PRIVATE']),
    version='v3.1',
)

data = {'Messages': [{
    'From': {'Email': 'no-reply@yourdomain.com', 'Name': 'Your App'},
    'To': [{'Email': 'customer@example.com', 'Name': 'Customer'}],
    'Subject': 'Your receipt',
    'TextPart': 'Thanks for your order.',
    'HTMLPart': '<h3>Thanks for your order.</h3>',
    'CustomID': 'order-1234',
}]}

result = mailjet.send.create(data=data)
print(result.status_code, result.json())

# EU residency: add api_url='https://api.eu.mailjet.com/' to Client().

Sending with the Node.js SDK

// npm install node-mailjet
const Mailjet = require('node-mailjet');

const mailjet = Mailjet.apiConnect(
  process.env.MJ_APIKEY_PUBLIC,
  process.env.MJ_APIKEY_PRIVATE,
);

// { version: 'v3.1' } is required - the default is v3, whose payload
// uses FromEmail / Html-part, not From / HTMLPart.
mailjet
  .post('send', { version: 'v3.1' })
  .request({
    Messages: [{
      From: { Email: 'no-reply@yourdomain.com', Name: 'Your App' },
      To: [{ Email: 'customer@example.com', Name: 'Customer' }],
      Subject: 'Your receipt',
      TextPart: 'Thanks for your order.',
      HTMLPart: '<h3>Thanks for your order.</h3>',
      CustomID: 'order-1234',
    }],
  })
  .then((result) => console.log(result.body))
  .catch((err) => console.log(err.statusCode, err.message));

Handling batched Event API webhooks

Mailjet groups every event of the last second for one webhook URL into a single POST, so the body is an array of mixed event types. Iterate, always.

app.post('/webhooks/mailjet', express.json(), (req, res) => {
  // ALWAYS an array. A single-object handler passes in testing and
  // breaks the moment batching kicks in under real traffic.
  const events = Array.isArray(req.body) ? req.body : [req.body];

  for (const e of events) {
    // e.event: sent | open | click | bounce | spam | blocked | unsub
    enqueue({
      type: e.event,
      email: e.email,
      at: new Date(e.time * 1000),
      messageId: e.MessageID,
      correlation: e.CustomID,   // set at send time
    });
  }

  // Return 200 fast. A non-200 is retried every 30 seconds for 24 hours.
  res.sendStatus(200);
});

Common gotchas

v3 and v3.1 are both current, and swapping the URL without rewriting the payload silently breaks the send

The single most common Mailjet integration failure. /v3/send takes a flat body with FromEmail, Text-part, Html-part and either Recipients or To/Cc/Bcc; /v3.1/send takes a Messages array using From, To, TextPart and HTMLPart, with Vars renamed Variables. In the SDKs the version is a client-level setting, so forgetting it posts a v3.1-shaped payload to the v3 endpoint and returns a property-validation error rather than a version error. There is a second trap inside v3: recipients in To see every other recipient, while recipients in Recipients each get a private message — pick the wrong key and you leak your whole list.

Event API webhooks arrive as an array of batched events, not one event per request

Mailjet groups all events of the last second for one webhook URL, so your endpoint receives a JSON array mixing sent, open, click, bounce, spam, blocked and unsub. Handlers written against a single object work in low-volume testing, then break the moment real traffic triggers batching. Fail to return 200 and Mailjet retries every 30 seconds, stopping 24 hours after the first failure — a handler that errors under load spends a day duplicating itself. Correlate with CustomID and Payload.

Each API key is a separate contact database — sub-accounts do not share lists

Mailjet’s documentation is explicit that contacts and lists are not shared between API keys, including the main one. Teams that add a second key to split transactional from marketing, or to isolate staging, find afterwards that lists, segments and templates did not follow, and there is no merge — you re-import. Sender validation has the same problem, which is why MetaSender exists.

The exclusion list is global, and the CSV import path rejects a list ID because of it

Exclusion is an account-level status, not a per-list one, and excluded contacts still receive all transactional email — including messages carrying a campaign tag. It is not a suppression list for transactional mail. When bulk-excluding through POST /v3/REST/csvimport the payload must not contain ContactsListID; including it returns MJ08 Property ContactsList is invalid. For one contact, set IsExcludedFromCampaigns via PUT on /v3/REST/contact/{ID_OR_EMAIL}.

Deprecations and changelog

  • September 9, 2026 (forward-dated) — subscription pricing update takes effect, affecting pricing only — no change to plans, packaging or entitlements. Essential 15k moves to $19.00, Premium 15k to $29.00; Starter holds at $9.00.
  • February 3, 2026 — Advanced Automations and AI Segmentation shipped together. Automations trigger journeys from opens, clicks, purchases or sign-ups and allow editing a live workflow without interrupting it; AI Segmentation turns a plain-language description into a segment.
  • November 4, 2025 — Custom Unsubscribe Manager and Preference Center released, replacing all-or-nothing opt-out with branded pages where subscribers pick content types and frequency.
  • October 6, 2025 — free plan changes took effect: free accounts capped at 1,000 contacts, templates no longer downloadable on free accounts.
  • September 30, 2025 — the official Mailjet MCP Server was released, open-source and read-only.

Nothing here is formally deprecated: /v3/send remains live with no published sunset date, but new transactional work belongs on /v3.1/send. Track changes at Mailjet’s official release notes.

Frequently asked questions

What is the difference between the Mailjet API v3 and the v3.1 Send API?

They are not two generations of one API. v3 is the whole REST platform — contacts, lists, campaigns, templates, statistics, senders, DNS, webhooks — and it is not going anywhere. v3.1 exists only for sending: there is no /v3.1/REST/. /v3/send is flat, with FromEmail and Html-part; /v3.1/send wraps everything in a Messages array with From and HTMLPart, renaming Vars to Variables.

How do I authenticate with the Mailjet API?

HTTPS Basic Auth: username is your API Key (public), password your Secret Key (private), both under Account settings › SMTP and SEND API settings. The SDKs read them from MJ_APIKEY_PUBLIC and MJ_APIKEY_PRIVATE. There is no OAuth flow and no scoped token: a key is all-or-nothing, and the only isolation mechanism is a second key with its own contact database. The same pair authenticates the relay at in-v3.mailjet.com — see SMTP settings.

How do I set up Mailjet webhooks to track opens, clicks and bounces?

Register endpoints on /v3/REST/eventcallbackurl, or in the UI under Account settings › Event Tracking, one entry per event type with an optional isBackup URL. Mailjet fires seven event types — sent, open, click, bounce, spam, blocked and unsub — for transactional and marketing mail alike. Events from the last second are batched into one POST, so your handler receives a JSON array. Return HTTP 200, or Mailjet retries every 30 seconds for 24 hours.

Can Mailjet receive inbound email with the Parse API?

Yes, and it is real inbound routing with MIME parsing, not a forwarding hack. Create a route with POST /v3/REST/parseroute; the only mandatory property is the webhook Url. Mailjet allocates an address at parse-in1.mailjet.com, or you receive on your own domain by verifying it, adding an MX record to parse.mailjet.com. and setting the route’s Email. Mail is POSTed as JSON with sender, recipient, subject, headers, both body parts, a SpamAssassinScore and Base64 attachments.

Does Mailjet have an EU API endpoint for GDPR data residency?

Yes for the API: https://api.eu.mailjet.com is declared in Mailjet’s official OpenAPI specification and selected in the official MCP server with MAILJET_API_REGION=eu. In Python pass api_url='https://api.eu.mailjet.com/'; with curl, swap the host. The SMTP relay is different: Mailjet publishes one global hostname, in-v3.mailjet.com, with no EU-specific SMTP endpoint documented. This EU-first posture is Mailjet’s clearest edge over SendGrid, and shared ground with Brevo.

Does Mailjet have an official MCP server for AI agents?

Yes — one of the earlier first-party ESP MCP releases, dated September 30, 2025, Apache-2.0, installable with npx -y @mailjet/mailjet-mcp-server. Two caveats decide whether it fits. It is read-only by design, scoped to contacts, campaigns, segments, statistics and workflows; agentic sending needs the Send API or Zapier MCP. And its tool surface is generated at runtime from Mailjet’s OpenAPI spec, so there is no fixed published tool list — coverage mirrors the /v3/REST/ resources.

Changelog (recent)

  • 2026-09-09 Subscription pricing update takes effect. Pricing only — no change to plans, packaging or feature entitlements. Essential 15k moves to $19.00, Premium 15k to $29.00; Starter holds at $9.00. Monthly subscribers move at their first billing date on or after that day, annual subscribers at renewal.
  • 2026-02-03 Advanced Automations and AI Segmentation shipped together. Automations trigger journeys from opens, clicks, purchases or sign-ups and allow editing a live workflow without interrupting it; AI Segmentation converts a plain-language audience description into a segment.
  • 2025-11-04 Custom Unsubscribe Manager and Preference Center released, replacing all-or-nothing opt-out with branded pages where subscribers choose content types and email frequency across multiple lists.
AAlaa Touil RRabeb How we test →

This review follows our email infrastructure testing methodology. We disclose affiliate relationships in our editorial independence policy.