openapi: 3.1.0
info:
  title: Mumara ONE Sending API
  version: "1.0"
  description: |
    The **Mumara ONE Sending API** sends a transactional email through a **Bridge** with one HTTPS request. It is the HTTP alternative to [SMTP](https://docs.mumara.com/one/transactional/smtp-settings) 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 Dedicated Pool, follow its **Track Opens** and **Track Clicks** switches, and count towards its sending stats, exactly like SMTP messages.

    ---

    ## Getting started

    1. **Verify a sending domain** under **Setup → Sending Domains**. The domain in `from` must be one of your verified sending domains.
    2. **Create a Bridge** under **Transactional → Bridges**.
    3. **Copy the One Connect Key** from the Bridge's details page, in the **Method 2: Send via API** panel.
    4. **Send a request:**

    ```bash
    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",
        "html": "<html><body><p>Your order is on its way.</p></body></html>"
      }'
    ```

    ---

    ## Authentication

    Send the Bridge's **One Connect Key** as a Bearer token on every request:

    ```
    Authorization: Bearer YOUR_ONE_CONNECT_KEY
    ```

    - Write `Bearer` exactly like that, followed by one space and the whole key. Copy the key with the copy button; a partly copied key fails with `Invalid API Key format.`
    - The key only sends email through its own Bridge, and deleting the Bridge revokes it.
    - It is **not** an API key from **Setup → API Keys**. Those are for the [REST API](../v2/) and don't work here, and a One Connect Key doesn't work on the REST API.
    - Call the API from your server. Anyone who has the key can send email as you, so never put it in browser JavaScript, a mobile app or a public repository.

    ---

    ## One message, one recipient

    Each request sends one message to one recipient. `to` takes exactly one plain address; to send the same email to several people, send one request per person. There are no CC, BCC or reply-to fields. To set a reply-to address, add a `Reply-To` header in `headers`.

    ---

    ## Matching events to your records

    Mumara ONE replaces the `Message-ID` of every message it relays, so the `messageId` in the response is **not** the one the recipient receives, and not the `msg_id` in your events.

    To tie events back to your own records, send an **`X-Track`** header with your own reference, such as an order, ticket or message id. Mumara ONE keeps it and returns it as the `track` field on delivery, open and click events. See **Webhook events** in this reference.

    ---

    ## Limits

    | Limit | Value |
    |-------|-------|
    | Recipients per request | 1 |
    | Whole message, including attachments | 25 MB |
    | JSON request body | 50 MB |
    | One file uploaded in a `multipart/form-data` request | 10 MB |
    | One text field in a `multipart/form-data` request | 1 MB |
    | Time to answer | 50 seconds; a slower request is cut off with `504` |
    | Transport | HTTPS only; plain HTTP is refused with `426` |

    Base64 makes attachments about a third larger than the original files, so leave room for that within the 25 MB.

    Every message counts against your plan's transactional sending allowance. When it runs out, sends fail with `Insufficient transactional credits.` until it's topped up. The API doesn't limit the request rate and doesn't return rate-limit headers.

    ---

    ## Errors

    Most errors return JSON with `"status": "error"`, the HTTP status in `resCode` and the reason in `message`. Check the HTTP status and `status`, because a few responses differ:

    - `Invalid JSON format` has no `resCode`, and adds `errorDetail`.
    - `Invalid headers format` returns the status in `errorCode` instead of `resCode`.
    - A wrong path or method returns `{"error": "Route does not exist"}`.
    - Plain HTTP returns `426` as plain text.
    - In a `multipart/form-data` request, a file over 10 MB, a file part with a name other than `attachments`, or a text field over 1 MB returns an HTML `500` page instead of JSON.
    - Send every field with the type shown in this reference. A `to` that isn't a string, or an attachment without `content`, gets no answer, and the request ends with a `504` after 50 seconds.

    Refusals from the mail relay, such as a wrong key, an unverified `from` domain or an exhausted allowance, return `500` with the relay's reply after `Failed to send email:`. See the `500` response of **Send an email** for the list.

    ---

    ## Retries

    - **There is no idempotency key.** Every successful request sends a message. If a request times out, you can't tell whether it was accepted, and sending it again may deliver it twice. For important messages, record what you've sent and check the delivery logs under **Analytics** before retrying.
    - **Retry a `500` only after fixing its cause.** A refusal for an unverified domain, a wrong key or an exhausted allowance fails the same way until you fix it.

    ---

    ## Testing without sending

    Put one of these headers in the `headers` field:

    - **`x-mode: test`** checks the body, the recipient, the attachments, the HTML and the format of the key, then returns `Test mode detected. Skipping the delivery.` without sending. It doesn't check that the key belongs to a Bridge, that the `from` domain is verified, or that you have sending allowance left. Write the name in lower case, exactly as shown: in any other case the header isn't recognised and the message is sent.
    - **`X-Mode: mta-discard`** runs every check, including the key, the sending domain, the Bridge's status and your allowance, then discards the message instead of delivering it. The response is the normal success response. It uses no sending allowance and writes no delivery log.
  contact:
    name: Mumara Support
    url: https://support.mumara.com
    email: support@mumara.com
  license:
    name: Proprietary
    url: https://mumara.com/terms
externalDocs:
  description: Sending API guide
  url: https://docs.mumara.com/one/transactional/sending-api
servers:
  - url: https://api.mumara.com
    description: Mumara ONE Sending API
security:
  - oneConnectKey: []
tags:
  - name: Sending
    description: |
      Send a transactional email through a Bridge. Create Bridges and copy their One Connect Keys under **Transactional → Bridges**.
    externalDocs:
      description: Bridges
      url: https://docs.mumara.com/one/transactional/bridges
  - name: Webhook events
    description: |
      The events Mumara ONE sends to your own URL about the email you send, through webhooks you set up under **Actions → Webhooks**. Each request is a `POST` with one event as a JSON object, signed with your signing secret.

      Your endpoint should use HTTPS, answer within **10 seconds** with any `2xx` status, and not redirect. Failed deliveries are retried up to 8 attempts in all, with the wait doubling each time from about a minute, and a webhook that keeps failing for two days is switched off.

      Payloads carry more fields than are described here, some of them for Mumara ONE's own use, and new fields may be added. Read the fields you need and ignore the rest. Empty values are sent as empty strings.
    externalDocs:
      description: Webhooks guide
      url: https://docs.mumara.com/one/actions/webhooks
paths:
  /sendEmail:
    post:
      tags:
        - Sending
      operationId: sendEmail
      summary: Send an email
      description: |
        Sends one email to one recipient through the Bridge that owns the One Connect Key.

        The body can be `application/json`, or `multipart/form-data` when you want to upload attachments as files. Send the `Content-Type` header: without it, or with any other type, the body isn't read and the request fails with `Recipient email address is required`.

        The API checks a request in this order, and reports the first problem it finds:

        1. The body is valid JSON, and `headers`, if it's a string, is valid JSON.
        2. `to` is present, and is one valid address.
        3. The attachments can be decoded.
        4. `html` is present and has body tags.
        5. The key has the right format.
        6. `x-mode: test`, if present, ends the request here.
        7. The mail relay checks the key, the `from` domain, the Bridge, your account and your sending allowance.

        "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**, under **Analytics**, and in your webhooks.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SendEmailRequest'
            examples:
              basic:
                summary: A simple message
                value:
                  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>'
              trackedWithAttachment:
                summary: With X-Track, Reply-To and an attachment
                value:
                  from: Example Store <orders@example.com>
                  to: jane@example.com
                  subject: Your receipt
                  text: Thank you for your order.
                  html: '<html><body><p>Thank you for your order.</p></body></html>'
                  headers:
                    X-Track: order-10025
                    Reply-To: support@example.com
                  attachments:
                    - filename: receipt.txt
                      content: VGhhbmsgeW91IGZvciB5b3VyIG9yZGVyLg==
                      encoding: base64
              testMode:
                summary: Test mode (nothing is sent)
                value:
                  from: Example Store <orders@example.com>
                  to: jane@example.com
                  subject: Test
                  html: '<html><body><p>Test</p></body></html>'
                  headers:
                    x-mode: test
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/SendEmailMultipartRequest'
            encoding:
              attachments:
                contentType: application/octet-stream
      responses:
        '200':
          description: |
            The message was accepted for delivery. With `x-mode: test`, the request passed the API's own checks and nothing was sent. With `X-Mode: mta-discard`, the response looks exactly like a real send, but the message was discarded.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/SendEmailSuccess'
                  - $ref: '#/components/schemas/TestModeResponse'
              examples:
                sent:
                  summary: Accepted for delivery
                  value:
                    status: success
                    resCode: 250
                    message: Email has been sent successfully
                    info:
                      messageId: '<5b0e8c7a-1f2d4c3b-9a8e7d6c-5b4a3f21-0e9d8c7b@example.com>'
                      envelope:
                        from: orders@example.com
                        to:
                          - jane@example.com
                      accepted:
                        - jane@example.com
                      rejected: []
                      response: 250 Message Queued (8E6C1B2A-4F3D-4E5A-9B7C-1D2E3F4A5B6C.1)
                      messageSize: 1834
                      envelopeTime: 38
                      messageTime: 112
                testMode:
                  summary: x-mode test
                  value:
                    status: success
                    resCode: 250
                    message: Test mode detected. Skipping the delivery.
        '400':
          description: The body, the `headers` field or the recipient is invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                invalidJson:
                  summary: The body isn't valid JSON
                  value:
                    status: error
                    message: Invalid JSON format
                    errorDetail: "Parse error on line 4: ... Expecting 'STRING', got '}'"
                tooLarge:
                  summary: The JSON body is over 50 MB
                  value:
                    status: error
                    message: Invalid JSON format
                    errorDetail: request entity too large
                invalidHeaders:
                  summary: '`headers` is a string that isn''t valid JSON'
                  value:
                    status: error
                    errorCode: 400
                    message: 'Invalid headers format: Unexpected token X in JSON at position 1'
                missingRecipient:
                  summary: No `to` field, or no Content-Type header
                  value:
                    status: error
                    resCode: 400
                    message: Recipient email address is required
                invalidRecipient:
                  summary: '`to` isn''t one plain address'
                  value:
                    status: error
                    resCode: 400
                    message: 'Invalid recipient email address: Jane <jane@example.com>'
        '401':
          description: The `Authorization` header is missing, or the key in it is incomplete. A complete key that doesn't match a Bridge is refused by the relay instead, with a `500`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                missingKey:
                  summary: No Bearer token
                  value:
                    status: error
                    resCode: 401
                    message: Unauthorized. Missing or invalid API Key.
                badFormat:
                  summary: The key is incomplete
                  value:
                    status: error
                    resCode: 401
                    message: Invalid API Key format.
        '404':
          description: The path or method is wrong. Send a `POST` to `/sendEmail`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RouteNotFound'
              example:
                error: Route does not exist
        '426':
          description: The request was sent over plain HTTP. Use `https://`.
          content:
            text/plain:
              schema:
                type: string
              example: Use HTTPS on port 443. Plain HTTP is not supported here.
        '500':
          description: |
            The HTML is missing, or the mail relay refused the message. A relay refusal follows `Failed to send email:` and says why:

            | The message contains | What it means |
            |---|---|
            | `Invalid login: 535` | The key is complete but doesn't match a Bridge: it's mistyped, or the Bridge has been deleted. |
            | `Null sender not allowed` | There's no `from` field. |
            | `is not authorized to relay emails` | The domain in `from` isn't one of your verified sending domains. |
            | `is disabled for userId` | The sending domain in `from` has been disabled. |
            | `The bridge ... is disabled` | The Bridge has been disabled. |
            | `Insufficient transactional credits` | Your transactional sending allowance has run out. |
            | `Your account is suspended` | Contact Mumara support. |
            | `Message too big!` | The message, with its attachments, is over 25 MB. |

            In a `multipart/form-data` request, an upload problem (a file over 10 MB, a file part not named `attachments`, a text field over 1 MB) returns an HTML error page with this status instead of JSON.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                missingHtml:
                  summary: No `html` field
                  value:
                    status: error
                    resCode: 500
                    message: 'Failed to send email: HTML content is missing'
                missingBody:
                  summary: '`html` has no body tags'
                  value:
                    status: error
                    resCode: 500
                    message: 'Failed to send email: HTML content is missing <body> tags'
                wrongKey:
                  summary: The key doesn't match a Bridge
                  value:
                    status: error
                    resCode: 500
                    message: 'Failed to send email: Invalid login: 535 5.7.8 Authentication failed'
                noFrom:
                  summary: No `from` field
                  value:
                    status: error
                    resCode: 500
                    message: 'Failed to send email: Mail command failed: 550 Null sender not allowed'
                unverifiedDomain:
                  summary: The `from` domain isn't verified
                  value:
                    status: error
                    resCode: 500
                    message: 'Failed to send email: Mail command failed: 550 example.org is not authorized to relay emails for userId 1234 (envelope check). If you are using a different domain for return-path, change it to the correct FROM domain.'
                bridgeDisabled:
                  summary: The Bridge is disabled
                  value:
                    status: error
                    resCode: 500
                    message: "Failed to send email: Can't send mail - all recipients were rejected: 550 The bridge YOUR_BRIDGE_USERNAME is disabled."
                noCredits:
                  summary: The sending allowance has run out
                  value:
                    status: error
                    resCode: 500
                    message: "Failed to send email: Can't send mail - all recipients were rejected: 550 Insufficient transactional credits."
                tooBig:
                  summary: The message is over 25 MB
                  value:
                    status: error
                    resCode: 500
                    message: 'Failed to send email: Message failed: 550 Message too big!'
webhooks:
  deliveryEvent:
    post:
      tags:
        - Webhook events
      operationId: deliveryEvent
      summary: Received, Delivered, Bounced or Delayed
      description: |
        Sent when a message is queued (`r`), delivered (`d`), bounces (`b`) or is deferred (`t`). `X-Mumara-Event` and `type` carry the event's code.

        **Received** and **Delivered** fire for every message you send, so select them only if you need them.
      parameters:
        - $ref: '#/components/parameters/WebhookEvent'
        - $ref: '#/components/parameters/WebhookDelivery'
        - $ref: '#/components/parameters/WebhookAttempt'
        - $ref: '#/components/parameters/WebhookSignature'
        - $ref: '#/components/parameters/WebhookUserAgent'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DeliveryEvent'
            examples:
              delivered:
                summary: Delivered, for a message sent through a Bridge
                value:
                  type: d
                  time_logged: 2026-09-22 10:15:04+0000
                  time_queued: 2026-09-22 10:15:01+0000
                  to: jane@example.net
                  status: relayed
                  code: 2.0.0 (success)
                  details: smtp;250 2.0.0 OK
                  recipient_mta: mx.example.net (198.51.100.25)
                  recipient_mta_ip: 198.51.100.25
                  bounce_category: ''
                  bounce_type: ''
                  node_ip: 203.0.113.10
                  node: pool-1234-1
                  node_pool: pool-1234
                  message_size: '4821'
                  subject: Your order has shipped
                  msg_id: '<1234-a1b2c3d4@example.com>'
                  tracking_code: ''
                  from: Example Store <orders@example.com>
                  from_name: Example Store
                  from_email: orders@example.com
                  from_domain: example.com
                  bridge: YOUR_BRIDGE_USERNAME
                  feedtype: api
                  track: order-10025
                  sent_utc_timestamp: '1790072101'
                  sent_utc_date: '2026-09-22 10:15:01'
                  recipient_domain: example.net
                  user_id: 1234
              bounced:
                summary: Bounced (only the fields that differ from Delivered)
                value:
                  type: b
                  status: failed
                  code: 5.1.1 (bad destination mailbox address)
                  details: 'smtp;550 5.1.1 <jane@example.net>: Recipient address rejected: User unknown'
                  bounce_category: bad-mailbox
                  bounce_type: hard
      responses:
        '200':
          description: Any `2xx` status within 10 seconds counts as delivered. Anything else is retried.
  engagementEvent:
    post:
      tags:
        - Webhook events
      operationId: engagementEvent
      summary: Opened or Clicked
      description: |
        Sent when a recipient opens a tracked message or clicks a tracked link. Email sent through a Bridge produces `transactional_open` and `transactional_click`; campaign email produces `campaign_open` and `campaign_click`.

        Opens and clicks are only recorded for tracked email: for a Bridge, its **Track Opens** and **Track Clicks** switches, and a tracking domain enabled on the sending domain in `from`.
      parameters:
        - $ref: '#/components/parameters/WebhookEvent'
        - $ref: '#/components/parameters/WebhookDelivery'
        - $ref: '#/components/parameters/WebhookAttempt'
        - $ref: '#/components/parameters/WebhookSignature'
        - $ref: '#/components/parameters/WebhookUserAgent'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EngagementEvent'
            examples:
              transactionalClick:
                summary: Transactional Clicked
                value:
                  selector: ttc
                  type: transactional_click
                  userId: 1234
                  ipAddress: 198.51.100.77
                  browser: Chrome
                  os: desktop
                  osVersion: '11'
                  agent: Mozilla/5.0
                  isBot: 0
                  destUrl: https://example.com/track-order
                  messageId: '<1234-a1b2c3d4@example.com>'
                  track: order-10025
                  queuedTimestamp: '1790072101'
                  emailFrom: orders@example.com
                  emailTo: jane@example.net
                  subject: Your order has shipped
                  datetime: '2026-09-22 10:21:40'
                  queuedDate: '2026-09-22 10:15:01'
      responses:
        '200':
          description: Any `2xx` status within 10 seconds counts as delivered. Anything else is retried.
  complaintEvent:
    post:
      tags:
        - Webhook events
      operationId: complaintEvent
      summary: Spam complaint
      description: |
        Sent when a recipient reports a message as spam and their mailbox provider sends the complaint back to Mumara ONE (`type` `c`). Not every provider reports complaints.

        The event carries the delivery fields of the original message when Mumara ONE can match the complaint to it, plus the complaint fields below.
      parameters:
        - $ref: '#/components/parameters/WebhookEvent'
        - $ref: '#/components/parameters/WebhookDelivery'
        - $ref: '#/components/parameters/WebhookAttempt'
        - $ref: '#/components/parameters/WebhookSignature'
        - $ref: '#/components/parameters/WebhookUserAgent'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ComplaintEvent'
            example:
              type: c
              to: jane@example.net
              from_email: orders@example.com
              from_name: Example Store
              from_domain: example.com
              recipient_domain: example.net
              subject: Your order has shipped
              msg_id: '<1234-a1b2c3d4@example.com>'
              sent_utc_timestamp: '1790072101'
              feedtype: api
              complaint_date: '2026-09-23 08:02:11'
              feedback_type: abuse
              fbl_source: example.net
              fbl_email: jane@example.net
      responses:
        '200':
          description: Any `2xx` status within 10 seconds counts as delivered. Anything else is retried.
components:
  securitySchemes:
    oneConnectKey:
      type: http
      scheme: bearer
      bearerFormat: One Connect Key
      description: |
        The Bridge's **One Connect Key**, from the Bridge's details page under **Transactional → Bridges** (panel **Method 2: Send via API**):
        ```
        Authorization: Bearer YOUR_ONE_CONNECT_KEY
        ```
        API keys from **Setup → API Keys** don't work here.
  parameters:
    WebhookEvent:
      name: X-Mumara-Event
      in: header
      required: true
      description: 'The event: `r`, `d`, `b`, `t`, `c`, `campaign_open`, `campaign_click`, `transactional_open` or `transactional_click`. The same value as `type` in the body.'
      schema:
        type: string
        enum: [r, d, b, t, c, campaign_open, campaign_click, transactional_open, transactional_click]
    WebhookDelivery:
      name: X-Mumara-Delivery
      in: header
      required: true
      description: A unique ID for this event and this webhook. It stays the same on every retry, so use it to ignore an event you've already handled.
      schema:
        type: string
    WebhookAttempt:
      name: X-Mumara-Attempt
      in: header
      required: true
      description: '`1` for the first attempt, `2` for the first retry, and so on, up to `8`.'
      schema:
        type: integer
        minimum: 1
        maximum: 8
    WebhookSignature:
      name: X-Mumara-Signature
      in: header
      required: true
      description: '`t=<timestamp>,v1=<signature>`: an HMAC-SHA256 of the timestamp and the raw body, made with your signing secret. See [Webhook signatures](https://docs.mumara.com/one/developers/webhook-signatures).'
      schema:
        type: string
        example: t=1790072105,v1=5f2b0c3e9d8a7b6c5d4e3f2a1b0c9d8e7f6a5b4c3d2e1f0a9b8c7d6e5f4a3b2c
    WebhookUserAgent:
      name: User-Agent
      in: header
      required: true
      schema:
        type: string
        example: Mumara-Webhooks/1.0
  schemas:
    SendEmailRequest:
      type: object
      required:
        - from
        - to
        - html
      properties:
        from:
          type: string
          description: The sender, as `orders@example.com` or `Example Store <orders@example.com>`. It is used for both the `From` header and the envelope sender. The domain must be one of your verified sending domains, and the match is exact; a subdomain such as `mail.example.com` needs its own sending domain.
          examples:
            - Example Store <orders@example.com>
        to:
          type: string
          format: email
          maxLength: 254
          description: Exactly one recipient, as a plain address. Display names and lists of addresses aren't accepted, and the value must be a string, not an array.
          examples:
            - jane@example.com
        subject:
          type: string
          description: The subject line. Always set one; messages without a subject are far more likely to be filtered.
        html:
          type: string
          description: |
            The HTML body. It must contain `<body>` and `</body>` tags, so every message has an HTML part.

            With the Bridge's **Track Opens** switch on, a tracking image is added before `</body>`; with **Track Clicks** on, `http://` and `https://` links in `<a href="...">` tags are rewritten. Write those tags in lower case: tracking doesn't find `</BODY>` or `<A HREF>`.
        text:
          type: string
          description: A plain-text version, shown by clients that don't display HTML. Recommended. It is never changed by tracking.
        headers:
          $ref: '#/components/schemas/CustomHeaders'
        attachments:
          type: array
          description: Files to attach. There is no limit per file in a JSON body, but the whole message must stay within 25 MB. Inline (CID) images aren't supported; link to hosted images instead.
          items:
            $ref: '#/components/schemas/Attachment'
    SendEmailMultipartRequest:
      type: object
      required:
        - from
        - to
        - html
      properties:
        from:
          type: string
          description: As in the JSON body.
        to:
          type: string
          format: email
          description: As in the JSON body. Send the field once.
        subject:
          type: string
        html:
          type: string
          description: As in the JSON body. Up to 1 MB in a multipart request.
        text:
          type: string
        headers:
          type: string
          description: The custom headers as a JSON object in a string, for example `{"X-Track":"order-10025"}`. Invalid JSON returns `400 Invalid headers format`.
        attachments:
          type: array
          description: Upload each file as a part named `attachments`; repeat the part for several files. Each file can be up to 10 MB. The file name the recipient sees is the uploaded file's name.
          items:
            type: string
            format: binary
    CustomHeaders:
      description: |
        Extra headers, as name and value pairs. In any content type you can also send this field as a JSON object in a string.

        - **`X-Track`**: your own reference. It comes back as `track` on delivery, open and click events. Keep it on one line and under 255 characters.
        - **`Reply-To`**: where replies go.
        - **`x-mode: test`** and **`X-Mode: mta-discard`**: test without sending. See the introduction.
        - Your other headers reach the recipient but aren't read back into events or delivery logs.
        - `Message-ID`, `Return-Path` and `DKIM-Signature` are replaced on every message, and `X-Var` is reserved and removed.

        Header names can contain only letters, numbers and hyphens. Check your names before sending: a name with any other character, such as a space, an underscore or a colon, isn't rejected with an error. Instead **all** your headers are left off the message and it is sent, even when one of them is `x-mode: test`.
      oneOf:
        - type: object
          additionalProperties:
            type: string
        - type: string
          description: The same object, as a JSON string.
      examples:
        - X-Track: order-10025
          Reply-To: support@example.com
    Attachment:
      type: object
      required:
        - filename
        - content
      properties:
        filename:
          type: string
          description: The file name the recipient sees. The file type is worked out from its extension.
          examples:
            - invoice-10025.pdf
        content:
          type: string
          description: The file's contents, encoded as given by `encoding`.
        encoding:
          type: string
          default: base64
          description: The encoding of `content`. Leave it out for base64.
    SendEmailSuccess:
      type: object
      required:
        - status
        - resCode
        - message
        - info
      properties:
        status:
          type: string
          const: success
          description: Check this rather than `resCode`.
        resCode:
          type: integer
          const: 250
          description: '`250`, the SMTP code for an accepted message.'
        message:
          type: string
          examples:
            - Email has been sent successfully
        info:
          type: object
          properties:
            messageId:
              type: string
              description: Assigned before the message reaches the relay. Mumara ONE gives the message its own `Message-ID`, which is the one in your events and delivery logs, so don't store this value as the key to your records; use `X-Track`.
            envelope:
              type: object
              properties:
                from:
                  type: string
                to:
                  type: array
                  items:
                    type: string
            accepted:
              type: array
              description: The recipient, when the relay accepted it.
              items:
                type: string
            rejected:
              type: array
              description: The recipient, when the relay rejected it.
              items:
                type: string
            response:
              type: string
              description: The relay's final reply, such as `250 Message Queued (...)`.
            messageSize:
              type: integer
              description: The size of the message, in bytes.
            envelopeTime:
              type: integer
              description: How long the envelope took to be accepted, in milliseconds.
            messageTime:
              type: integer
              description: How long the message took to be accepted, in milliseconds.
    TestModeResponse:
      type: object
      description: 'The response to `x-mode: test`. It has no `info`.'
      required:
        - status
        - resCode
        - message
      properties:
        status:
          type: string
          const: success
        resCode:
          type: integer
          const: 250
        message:
          type: string
          const: Test mode detected. Skipping the delivery.
    ErrorResponse:
      type: object
      properties:
        status:
          type: string
          const: error
        resCode:
          type: integer
          description: The HTTP status code. Missing on `Invalid JSON format`, and replaced by `errorCode` on `Invalid headers format`.
        errorCode:
          type: integer
          description: The HTTP status code, on `Invalid headers format` only.
        message:
          type: string
          description: What went wrong.
        errorDetail:
          type: string
          description: On `Invalid JSON format`, where parsing failed, or `request entity too large` for a body over 50 MB.
    RouteNotFound:
      type: object
      properties:
        error:
          type: string
          const: Route does not exist
    DeliveryEvent:
      type: object
      additionalProperties: true
      properties:
        type:
          type: string
          enum: [r, d, b, t]
          description: '`r` Received, `d` Delivered, `b` Bounced, `t` Delayed.'
        to:
          type: string
          description: The recipient's address.
        from:
          type: string
          description: The sender, as in the `From` header.
        from_name:
          type: string
        from_email:
          type: string
        from_domain:
          type: string
        subject:
          type: string
        msg_id:
          type: string
          description: The message's `Message-ID`, with its angle brackets. Mumara ONE generates it; use it to match events for the same message.
        track:
          type: string
          description: Your own `X-Track` header from the message, if you sent one. Empty otherwise.
        tracking_code:
          type: string
          description: Mumara ONE's own reference for the send. For email through a Bridge it's usually empty.
        time_queued:
          type: string
          description: When Mumara ONE accepted the message, in UTC.
        time_logged:
          type: string
          description: When this event happened, in UTC.
        sent_utc_timestamp:
          type: string
          description: When the message was sent, as a Unix timestamp.
        sent_utc_date:
          type: string
          description: When the message was sent, as a UTC date and time.
        status:
          type: string
          description: The delivery outcome, for example `relayed` for a delivery or `failed` for a bounce.
        code:
          type: string
          description: The enhanced status code and its meaning, for example `5.1.1 (bad destination mailbox address)`.
        details:
          type: string
          description: The receiving server's reply, word for word.
        bounce_type:
          type: string
          enum: [hard, soft, '']
          description: For bounces, `hard` (permanent) or `soft` (temporary). Empty for other events.
        bounce_category:
          type: string
          description: For bounces, a category such as `bad-mailbox`.
        recipient_mta:
          type: string
        recipient_mta_ip:
          type: string
        recipient_domain:
          type: string
        node_ip:
          type: string
          description: The IP address the message was sent from.
        node:
          type: string
          description: The pool the message was sent through.
        bridge:
          type: string
          description: For email sent through a Bridge, the Bridge's SMTP username.
        feedtype:
          type: string
          description: '`newsletter` for campaign email. For email sent through a Bridge, `api` for the Sending API and `smtp` for SMTP.'
        message_size:
          type: string
          description: The size of the message, in bytes.
        user_id:
          type: integer
    EngagementEvent:
      type: object
      additionalProperties: true
      properties:
        type:
          type: string
          enum: [transactional_open, transactional_click, campaign_open, campaign_click]
        selector:
          type: string
          enum: [tto, ttc, cto, ctc]
          description: The short form of the event.
        emailTo:
          type: string
        emailFrom:
          type: string
        nameFrom:
          type: string
          description: The sender's name, for campaign email.
        subject:
          type: string
        messageId:
          type: string
          description: The message's `Message-ID`, the same value as `msg_id` in its delivery events.
        track:
          type: string
          description: On transactional opens and clicks, your own `X-Track` header from the message, if you sent one.
        datetime:
          type: string
          description: When the open or click happened.
        queuedTimestamp:
          type: string
        queuedDate:
          type: string
        destUrl:
          type: string
          description: For clicks, the link that was clicked.
        ipAddress:
          type: string
        agent:
          type: string
        browser:
          type: string
        os:
          type: string
        osVersion:
          type: string
        isBot:
          type: integer
          enum: [0, 1]
          description: '`1` when the open or click looks automated, for example a security scanner following links.'
        geoip:
          type: object
          description: The opener's location from their IP address, in MaxMind GeoIP2 format, when available.
        delivery_log:
          type: object
          description: The delivery record of the original message, when available.
    ComplaintEvent:
      type: object
      additionalProperties: true
      properties:
        type:
          type: string
          const: c
        to:
          type: string
        from_email:
          type: string
        from_name:
          type: string
        from_domain:
          type: string
        recipient_domain:
          type: string
        subject:
          type: string
        msg_id:
          type: string
        sent_utc_timestamp:
          type: string
        feedtype:
          type: string
        complaint_date:
          type: string
          description: When the recipient complained.
        feedback_type:
          type: string
          description: The type of report, usually `abuse`.
        fbl_source:
          type: string
          description: The mailbox provider that reported the complaint.
        fbl_email:
          type: string
          description: The recipient's address as the provider reported it. Some providers redact it.
