Skip to main content

Sending API

The sending API lets your application send a transactional email through a Bridge with one HTTPS request. It's the alternative to SMTP for code you write yourself, serverless functions, and anything that finds an HTTP request easier than an SMTP connection.

Both methods go through the same Bridge. API messages use the Bridge's pool, follow its tracking switches and count towards its sending stats, exactly like SMTP messages.

Endpoint​

POST https://api.mumara.com/sendEmail
  • HTTPS only. A plain HTTP request is refused with 426.
  • One message, one recipient per request. To send the same email to several people, send one request for each.
  • Content types: application/json, or multipart/form-data when you want to upload attachments as files.

Authentication​

Every request needs the Bridge's One Connect Key as a Bearer token:

Authorization: Bearer YOUR_ONE_CONNECT_KEY

To find the key:

  1. Go to Transactional → Bridges and click the Bridge's name.
  2. In the Method 2: Send via API panel, copy the One Connect Key.

Keep the key secret, like a password. Deleting the Bridge revokes the key. See Bridges.

Call the API from your server only

Anyone who can see the key can send email as you. Never put it in browser JavaScript, mobile apps or public repositories. Keep it in an environment variable or your platform's secrets store.

Not the same as your API key

The One Connect Key only sends email through its Bridge. Keys created under Setup → API Keys are for the Mumara REST API, which manages lists, contacts and campaigns, and they don't work here. See API Keys.

Request fields​

FieldTypeRequiredDescription
fromstringYesThe sender, as orders@example.com or Example Store <orders@example.com>. The domain must be one of your verified sending domains.
tostringYesExactly one recipient, as a plain address such as jane@example.com. Names and lists of addresses aren't accepted.
subjectstringNoThe subject line. Always set one: messages without a subject are far more likely to be filtered.
htmlstringYesThe HTML body. It must contain <body> and </body> tags.
textstringNoA plain-text version of the message, shown by clients that don't display HTML. Recommended.
headersobjectNoExtra headers, as name and value pairs. In a multipart/form-data request, send this field as a JSON string.
attachmentsarrayNoFiles to attach. The format depends on the content type; see Attachments.

The API doesn't have separate fields for CC, BCC or reply-to. To set a reply-to address, add a Reply-To header in headers.

The from address​

The domain in from must be a sending domain you've verified under Setup → Sending Domains, and the match is exact: to send from alerts@mail.example.com, verify mail.example.com as a sending domain of its own. Any Bridge can use any of your verified domains. See Sending Domains.

Headers​

Header names can contain only letters, numbers and hyphens, for example X-Order-Id. Use your own names for your own references. Mumara ONE sets its own Message-ID, return path and DKIM signature on every message, as described in SMTP Settings.

Attachments​

With application/json, send each attachment as an object in the attachments array:

PropertyDescription
filenameThe file name the recipient sees, such as invoice-10025.pdf. The file type is worked out from the extension.
contentThe file's contents, base64-encoded.
encodingOptional. The encoding of content. Defaults to base64.

With multipart/form-data, upload each file as a form part named attachments. Repeat the part to attach several files. Each file can be up to 10 MB.

The whole message, including attachments, can be up to 25 MB. Base64 makes attachments about a third larger than the original files, so leave room for that.

Examples​

JSON​

curl -X POST https://api.mumara.com/sendEmail \
-H "Authorization: Bearer YOUR_ONE_CONNECT_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "Example Store <orders@example.com>",
"to": "jane@example.com",
"subject": "Your order has shipped",
"text": "Good news: your order is on its way.",
"html": "<html><body><p>Good news: your order is on its way.</p></body></html>",
"headers": {
"X-Order-Id": "10025",
"Reply-To": "support@example.com"
},
"attachments": [
{
"filename": "receipt.txt",
"content": "VGhhbmsgeW91IGZvciB5b3VyIG9yZGVyLg==",
"encoding": "base64"
}
]
}'

Multipart form data with a file​

curl -X POST https://api.mumara.com/sendEmail \
-H "Authorization: Bearer YOUR_ONE_CONNECT_KEY" \
--form-string 'from=Example Store <orders@example.com>' \
--form-string 'to=jane@example.com' \
--form-string 'subject=Your invoice' \
--form-string 'text=Your invoice is attached.' \
--form-string 'html=<html><body><p>Your invoice is attached.</p></body></html>' \
--form-string 'headers={"X-Order-Id": "10025"}' \
-F 'attachments=@invoice-10025.pdf'

Use --form-string for text fields. With plain -F, curl treats a value that starts with < or @ as a file to read.

Node.js​

This example uses the built-in fetch in Node.js 18 and later:

async function sendOrderEmail() {
const response = await fetch('https://api.mumara.com/sendEmail', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.MUMARA_ONE_CONNECT_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
from: 'Example Store <orders@example.com>',
to: 'jane@example.com',
subject: 'Your order has shipped',
text: 'Good news: your order is on its way.',
html: '<html><body><p>Good news: your order is on its way.</p></body></html>',
headers: { 'X-Order-Id': '10025' },
}),
});

const result = await response.json();
if (result.status !== 'success') {
throw new Error(`Send failed (${response.status}): ${result.message}`);
}
return result;
}

The Bridge's details page has ready-made samples in cURL, PHP, NodeJS, Python and Bash.

Response​

A successful request returns HTTP 200:

{
"status": "success",
"resCode": 250,
"message": "Email has been sent successfully",
"info": {
"messageId": "<5b0e8c7a-1f2d-4c3b-9a8e-7d6c5b4a3f21@example.com>",
"envelope": {
"from": "orders@example.com",
"to": ["jane@example.com"]
},
"accepted": ["jane@example.com"],
"rejected": [],
"response": "250 ...",
"messageSize": 1834,
"envelopeTime": 38,
"messageTime": 112
}
}
FieldMeaning
statussuccess or error. Check this rather than resCode.
resCode250 when the message was accepted, matching the SMTP code for success.
info.accepted / info.rejectedThe recipient address, in whichever list applies.
info.responseThe relay's final reply.
info.messageSizeThe size of the message, in bytes.
info.envelopeTime / info.messageTimeHow long, in milliseconds, the envelope and the message took to be accepted.

"Accepted" means Mumara ONE has taken the message for delivery, not that it has reached the inbox. Delivery results appear in the Bridge's Sending Stats and in Analytics, and you can receive them in your own systems with webhooks under Actions → Webhooks.

About messageId

The messageId in the response is assigned before the message reaches the relay. Mumara ONE then gives the message its own Message-ID, so the header the recipient receives is different. To match a message to your own records, put your reference in a custom header such as X-Order-Id.

Errors​

Every error returns "status": "error" and a message explaining what went wrong:

{
"status": "error",
"resCode": 400,
"message": "Invalid recipient email address: Jane <jane@example.com>"
}
HTTP statusMessageCause and fix
400Invalid JSON formatThe body isn't valid JSON. The errorDetail field shows where parsing failed.
400Recipient email address is requiredThere's no to field. This also happens when the Content-Type header is missing, because the body isn't read.
400Invalid recipient email address: ...to isn't a single, plain address. Remove any display name and send one request per recipient.
400Invalid headers format: ...In a multipart request, the headers field isn't valid JSON.
401Unauthorized. Missing or invalid API Key.The Authorization header is missing, or doesn't start with Bearer followed by the key.
401Invalid API Key format.The key is incomplete. Copy the whole One Connect Key again from the Bridge's details page.
404Route does not existThe path or method is wrong. Send a POST to /sendEmail. The body of this error has an error field instead of status and message.
426Use HTTPS on port 443The request was sent over plain HTTP. Use https://.
500Failed to send email: HTML content is missingThere's no html field.
500Failed to send email: HTML content is missing <body> tagsWrap the HTML in <html><body> and </body></html>.
500Failed to send email: followed by the relay's replyThe relay refused the message. The reply says why; see below.

When the relay refuses a message, the reply after Failed to send email: gives the reason:

The reply mentionsWhat it means
Invalid login or 535The key is well formed but doesn't match a Bridge: it's mistyped, or the Bridge has been deleted.
is not authorized to relay emailsThe domain in from isn't one of your verified sending domains.
is disabledThe sending domain, or the Bridge, has been disabled.
Insufficient transactional creditsYour transactional sending allowance has run out. See Plan and Usage.
Your account is suspendedContact Mumara support.

The API checks a request in this order: the body, the recipient, the HTML, the key, and then the relay's checks. A request with several problems reports the first one it finds.

Retries, idempotency and rate limits​

  • No idempotency key. Every successful request sends a message. If a request times out, you can't tell whether the message was accepted, and sending it again may deliver it twice. For important messages, record what you've sent and check the delivery logs in Analytics before retrying.
  • Retry 500 relay errors only after fixing the cause. A refusal for an unverified domain, a wrong key or an exhausted allowance fails the same way until you fix it.
  • No rate-limit headers. The API doesn't return rate-limit headers. Every message counts against your plan's transactional sending allowance, as with SMTP.

Test without sending​

To check a request without sending any email, add an x-mode header with the value test:

"headers": { "x-mode": "test" }

Write the header name in lower case, exactly as shown. The API checks the body, the recipient, the HTML and the format of the key, then returns this instead of sending:

{
"status": "success",
"resCode": 250,
"message": "Test mode detected. Skipping the delivery."
}

Test mode doesn't check that the key belongs to a Bridge, that the from domain is verified, or that you have sending allowance left. For a test that goes through all of those checks without delivering, use the X-Mode: mta-discard header described in SMTP Settings. It works in the headers field of an API request too.

Tracking and engagement​

API messages follow the Bridge's Track Opens and Track Clicks switches, the same as SMTP messages:

  • Track Opens adds a tracking image before the closing </body> tag, which every API message has.
  • Track Clicks rewrites the http:// and https:// links in <a href="..."> tags in html.
  • The text part is never changed.
  • Tracking also needs the sending domain in from to have its tracking domain enabled and set up.

See Bridges for the details and for when to leave tracking off.

Results for API messages are recorded against the Bridge, together with its SMTP messages:

  • The Bridge's Sending Stats show totals for sent, delivered, bounced and complaints.
  • Analytics shows opens, clicks, delivery logs, bounces and complaints message by message.
  • Webhooks you set up under Actions → Webhooks push these events to your own systems.