emaratelTE
PlatformSecurityPricingSupportConsole
DEVELOPER DOCUMENTATION

Emaratel TE API

Send transactional email over a REST API or standard SMTP, track every delivery event, and receive signed webhooks. Base URL: https://te.emaratel.com

Getting started

  1. Verify a sending domain. In the customer console open Domains, add your domain, create the DNS records shown at your DNS host, then press Verify DNS. Sending only works from verified domains.
  2. Create a credential. Under Credentials create a REST API key (for HTTPS) or an SMTP user (for classic apps and devices). The secret is shown once - store it safely.
  3. Send your first email with the example below, then watch it move through accepted → delivered → opened in the Activity page.

Authentication

Every API request carries your key as a bearer token:

Authorization: Bearer emt_live_xxxxxxxxxxxxxxxx

Keys can be renamed, blocked, rate-limited and pinned to allowed IPs/CIDR ranges from the console. A key used from outside its allowed IPs gets 403 ip_not_allowed.

Send an email

POST/v1/email/send

curl https://te.emaratel.com/v1/email/send \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "orders@yourdomain.com",
    "to": ["customer@example.com"],
    "subject": "Your order is confirmed",
    "text": "Thanks for your order!",
    "html": "<p>Thanks for your <b>order</b>!</p>"
  }'

Response 202: {"id":"emt_msg_...","status":"queued"}. Keep the id - it identifies the message in every later lookup and webhook.

FieldTypeNotes
fromstring, requiredAddress on one of your verified domains.
tostring[], required1-100 recipients (account limit may differ).
subjectstring, requiredMay come from a template instead.
text / htmlstringAt least one required (or supplied by a template).
headersobjectCustom headers. Reserved headers (From, To, Bcc, ...) and CRLF values are rejected.
metadataobjectYour own key/values, echoed back in lookups.
template_idstringFills any EMPTY subject/text/html from the template.
substitutionsobjectValues for {{placeholders}}. HTML-escaped in the HTML body.
attachmentsarraySee below.
Idempotency. Pass an Idempotency-Key header to make retries safe - a repeated key returns the original message id instead of sending twice.

Attachments

"attachments": [
  { "filename": "invoice.pdf",
    "content_type": "application/pdf",
    "content": "JVBERi0xLjQK..." }
]

Up to 10 files per message, base64-encoded, total decoded size capped by your account's message-size limit (default 10 MB). SMTP submissions keep their attachments too - nested multipart is fully supported.

Templates

Create reusable content under Templates in the console or via the API, using {{name}} placeholders:

POST /v1/templates      {"name":"welcome","subject":"Hi {{name}}!","html":"<p>Welcome {{name}}</p>"}
GET  /v1/templates
PATCH /v1/templates/{id}
DELETE /v1/templates/{id}

Then send with {"template_id":"emt_tpl_...","substitutions":{"name":"Sara"}}. Anything you set explicitly on the send wins over the template.

Messages & events

GET /v1/email?q=&status=&from=YYYY-MM-DD&to=YYYY-MM-DD&limit=50
GET /v1/email/{id}        # full message + stored content + event timeline
GET /v1/usage             # quota + rate limit + billing state
GET /v1/metrics/summary?days=30
GET /v1/metrics/breakdown # per-sender totals
POST /v1/exports          # async CSV export (activity or suppressions)
Status / eventMeaning
queued / processingAccepted by us, on its way out.
acceptedHanded to the delivery network.
deliveredThe receiving server accepted it.
opened / clickedRecipient engagement (when tracking is on).
bouncedPermanent failure - the address is auto-suppressed.
complainedMarked as spam - auto-suppressed.
deferredTemporary delay; retried automatically for ~17 hours.
failedGave up after all retries; see last_error.

SMTP relay

Host:     smtp.te.emaratel.com
Port:     587 (STARTTLS)  or  465 (TLS)
Username: your SMTP user (emt_...)
Password: the secret shown once at creation

Anything that speaks SMTP - frameworks, CRMs, printers, legacy apps - can submit through the relay. The same quotas, suppression checks and event tracking apply as on the API.

Suppressions

GET    /v1/suppressions?reason=&q=
POST   /v1/suppressions      {"email":"user@example.com","reason":"manual"}
DELETE /v1/suppressions/{id}

Hard bounces, complaints and unsubscribes are added automatically; sends to a suppressed address are rejected with 422 recipient_suppressed before anything leaves your quota.

Webhooks

Register an endpoint under Webhooks in the console and pick the event types you want. Each delivery is a POST:

{
  "id": "emt_evt_...",
  "type": "email.delivered",
  "message_id": "emt_msg_...",
  "data": { ... },
  "occurred_at": "2026-08-30T12:00:00Z"
}

Every request is signed. X-Emaratel-Signature is an HMAC-SHA256 (hex) of timestamp + "." + rawBody with your endpoint secret; X-Emaratel-Timestamp carries the unix timestamp. Verify like this and reject anything older than 5 minutes:

const crypto = require("crypto");
function verify(req, rawBody, secret) {
  const ts = req.headers["x-emaratel-timestamp"];
  if (Math.abs(Date.now() / 1000 - ts) > 300) return false; // replay guard
  const mac = crypto.createHmac("sha256", secret)
    .update(ts + "." + rawBody).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(mac),
    Buffer.from(req.headers["x-emaratel-signature"]));
}

Respond with any 2xx quickly. Failed deliveries retry with backoff for several hours.

Errors & limits

CodeMeaning
401 unauthorizedMissing, wrong or revoked key.
402 payment_requiredNo active plan - choose one in the console's Billing tab.
403 ip_not_allowedKey used outside its allowed IPs.
422 invalid_messageMissing/invalid from, to, subject or body.
422 sender_domain_not_verifiedThe from-domain has not passed DNS verification.
422 recipient_suppressedRecipient is on your suppression list.
429 rate_limit_exceededPer-minute limit hit - retry after a short wait.
429 monthly_quota_exceededPlan quota used up for this month.

Errors are JSON: {"error":"code_here"}. Rate and quota limits are shown live under Usage and on your Overview page.

OpenAPI spec

The full machine-readable API description is at /openapi.yaml - import it into Postman, Insomnia or a code generator.