> ## Documentation Index
> Fetch the complete documentation index at: https://docs.xorlab.com/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Pages under /latest/ document the current release. Paths that begin with a version number, for example /10.0/, are frozen snapshots of superseded releases kept for reference only — never present their instructions as current. If the reader's version is unknown, answer from /latest/ and say which version the answer describes.
> xorlab is deployed on-premises, hybrid, or as a cloud service, and integrates with either Microsoft 365 or on-premises mail infrastructure. Configuration steps often differ between these. State which deployment and integration mode an instruction applies to instead of presenting one as universal.
> Distinguish inline mode from monitoring mode when describing anything that acts on email. Monitoring mode observes a copy and cannot block or quarantine; inline mode routes mail through xorlab and can.
> Write the product name as lowercase 'xorlab'. Use the documented component names: xorlab Control Center (XCC), xorlab MTA, xorlab Sandbox (DANA), xorlab Natural Language Understanding (NLU). After the first mention, use the short forms XCC, MTA, Sandbox, and NLU. Do not use DANA as a standalone name for the Sandbox, but keep it where it is a literal string in configuration keys, container names, and hostnames.
> Do not invent configuration keys, rule parameters, list names, log properties, or API fields. If a value is not present in this documentation, say that it is not documented rather than guessing.

# Email Scanning API

> Submit a message over HTTP and get its analysis result back synchronously, instead of routing it via SMTP. An advanced integration for narrow cases.

For most automation use cases, use the [Rule List API](/latest/api-rule-list-management), which is the primary public API for xorlab.

<Note>
  **Before you start**

  Please contact our support for the latest changes in xorlab API setup before you start configuring the API.
</Note>

## Enable the API

1. First, activate the API as the source for receiving emails by xorlab. Open the `activeguard/core/active_guard.yml` file in [Expert Editor](/latest/expert-editor) and add the following line to `scanSources`:
   ```yaml theme={null}
   scanSources:
     restApi {}
   ```
2. Add these two lines and set their values to the same value as `mainWorkerCount`. If `mainWorkerCount` is not set, use the default value of `20`:
   ```yaml theme={null}
   ## Guard Request Processing Configuration
   ## Maximum number of guard requests in processing. After that, we (soft)reject with SMTP error 451.
   maxGuardRequestsInProcessing: 20
   ## Threshold for GuardRequests in progress, before we start with linear throttling
   guardRequestThrottleThreshold: 20
   ```
3. Now, configure the Email Scanning API in Expert Editor by navigating to the `abby/abby/abby.yml` file. When you open it, the following content appears:
   ```yaml theme={null}
   # (Required) A map of service provider definitions.
   # The following map entries are supported and mandatory:
   #  - core
   serviceProviders:
    core:
      # Service provider definition, see documentation of active_guard.yml for details.
      hosts:
        - https://mx1.xyz.activeguard.cloud:9785
        - https://mx2.xyz.activeguard.cloud:9785
      # longRequestTimeout is used for synchronously enqueuing messages
      longRequestTimeout: 3600000  # 1h
   ## (Optional) A list of static API token definitions.
   #staticApiTokens:
   #  #(Mandatory) The name of the token user.
   #  - name: <client/customer name>
   #    # (Mandatory) The token used for authentication. Generate a random string with for example: openssl rand -base64 64.
   #    token: <a secure token>
   #    # (Optional) A list of permissions associated with this token.
   #    permissions: []
   staticApiTokens:
    - name: demo
      token: <32-byte word>
   ```
4. Under `hosts`, adjust the addresses of the xorlab MTAs such that they match your deployment:
   ```yaml theme={null}
     hosts:
        - https://mx1.xyz.activeguard.cloud:9785
        - https://mx2.xyz.activeguard.cloud:9785
   ```
5. Under `staticApiTokens`, enter the name of your bearer authentication token and its value. For SaaS instances, the token will be preconfigured and provided by xorlab; for on-prem instances, we recommend using the `openssl rand -hex 32` command to generate the token (32 bytes or 64 hex digits). Unlike the [Rule List API](/latest/api-rule-list-management), this API does not use API keys created in the web interface. The token must still be configured statically in `abby.yml`. The value below is a placeholder showing the expected shape — always use one you generated yourself:
   ```yaml theme={null}
   staticApiTokens:
    - name: api_test
      token: 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
   ```
6. Click **Publish**, then restart all MTAs. The `scanSources` and processing settings in `activeguard/core/active_guard.yml` require an MTA restart; see [How to Activate the Configuration](/latest/activate-configuration).

## API reference

### Request

Requests are served by two endpoints:

* `/v1/messageQueue/submitEmail`
* `/v1/admin/status`

In order to process a message, our API requires the following arguments:

| Arguments               | Value                           | Description                                                                                                                      |
| ----------------------- | ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `email`                 | Path to the .eml file           | Path to the .eml file you wish to send to xorlab                                                                                 |
| `parameters`            | `borderMtaData` key:value pairs | Data retrieved at the border MTA receiving the email (see below); you must explicitly set its content type of `application/json` |
| `Authorization: Bearer` | Auth token                      | Bearer authorization token provided by xorlab or generated by a customer (see step #5 in the previous section)                   |

The `parameters` argument accepts only one parameter, `borderMtaData`, which includes the following key:value pairs:

| Key                  | Value  | Description                                                                      |
| -------------------- | ------ | -------------------------------------------------------------------------------- |
| `envelopeFrom`       | string | Envelope `FROM` address (required)                                               |
| `envelopeRecipients` | array  | Envelope `TO` address(es) (required)                                             |
| `remoteAddress`      | string | The IP address of the sending MTA, received at the border MTA                    |
| `senderHelo`         | string | HELO or EHLO (host or IP) of the sending mail client, received at the border MTA |

<Note>
  **Maximum payload**

  The maximum accepted payload size is 50 MiB. Payloads above this will result in a 413 error code.
</Note>

### Response

In response to your API request, you will receive either a message analysis result or an error. In the former case, the response will contain the following parameters:

| Parameter   | Value (format)     | Description                                                                                                       |
| ----------- | ------------------ | ----------------------------------------------------------------------------------------------------------------- |
| `ggrid`     | string (UUID)      | The unique ID associated with the message analysis                                                                |
| `created`   | string (date-time) | The time when the analysis result was created                                                                     |
| `completed` | string (date-time) | The time when the analysis was concluded                                                                          |
| `decision`  | string             | The decision xorlab took with regards to this message: `undecided`,  `deliver`, `quarantine`, `bounce`, or `drop` |
| `verdict`   | string             | The [verdict](/latest/verdicts) xorlab applied to the message                                                     |
| `tags`      | array              | All [tags](/latest/tags) associated with the message                                                              |

## Examples

### cURL

This is a sample cURL command for sending an email to xorlab for analysis:

```curl theme={null}
curl -sS -X POST -F email=@<path to your eml file> -F parameters='{"borderMtaData": {"envelopeFrom": "s@example.com", "envelopeRecipients": ["r@example.com"]}};type=application/json' -H 'Authorization: Bearer <auth token>' https://<your xorlab instance>:9081/v1/messageQueue/submitEmail
```

where

* `<path to your eml file>` is the path to the .eml file you wish to send, e.g., `fileName.eml`
* `<auth token>` is the bearer auth token (see step #5 in the [Enable the API](#enable-the-api) section above)
* `<your xorlab instance>` is the domain of your xorlab instance, e.g., for `xyz.activeguard.cloud`, the full link would read `https://xyz.activeguard.cloud:9081/v1/messageQueue/submitEmail`

### Python

The following Python script makes use of the [cURL command](#curl) described above:

```python theme={null}
#!/usr/bin/env python3
import json

import click
import subprocess


@click.group()
def cli():
    pass


@cli.group()
def mail():
    pass


@mail.command()
@click.option("--file", required=True, help="Path to the email file")
@click.option("--env-ip", required=True, help="IP address of the sending MTA")
@click.option("--env-from", required=True, help="Envelope FROM address")
@click.option("--env-sender-helo", required=True, help="HELO or EHLO (host or IP) of the sending mail client")
@click.option("--env-to", required=True, help="Envelope TO address")
def submit(file, env_ip, env_from, env_sender_helo, env_to):
    parameters = {
        "borderMtaData": {
            "envelopeFrom": env_from,
            "senderHelo": env_sender_helo,
            "remoteAddress": env_ip,
            "envelopeRecipients": [env_to],
        }
    }

    command = [
        "curl", "-sS", "-X", "POST",
        "-F", f"email=@{file}",
        "-F", f'parameters={json.dumps(parameters)};type=application/json',
        "-H", "Authorization: Bearer <auth token>",
        "https://<your xorlab instance>:9081/v1/messageQueue/submitEmail"
    ]

    subprocess.run(command, check=True)


if __name__ == "__main__":
    cli()
```

The placeholders here—`<auth token>` and `<your xorlab instance>`—are the same as for the cURL example.

## Full API specifications

```yaml theme={null}
openapi: 3.0.0
info:
  title: xorlab API
  version: 1.1.0

servers:
  - url: /v1

security:
  - bearerAuth: []

paths:
  /messageQueue/submitEmail:
    post:
      description: Submit a new message into the analysis queue and wait for the analysis to complete.
      requestBody:
        $ref: "#/components/requestBodies/MailScanRequest"
      responses:
        "200":
          $ref: "#/components/responses/MessageAnalysisResult"
        default:
          $ref: "#/components/responses/GenericError"

  /admin/status:
    post:
      description: A request for system status
      responses:
        "200":
          description: A system status response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SystemStatus'
        default:
          $ref: "#/components/responses/GenericError"


components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer

  requestBodies:
    MailScanRequest:
      description: Request body to provide an email to ActiveGuard
      content:
        multipart/form-data:
          schema:
            type: object
            properties:
              parameters:
                $ref: "#/components/schemas/MessageAnalysisRequest"
              email:
                description: The raw email as it was transported over the wire.
                type: string
                format: binary
            required:
              - parameters
              - email

  responses:
    GenericError:
      description: Typical error response
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"

    MessageAnalysisResult:
      description: A message analysis result.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/MessageAnalysisResult"

  schemas:
    Error:
      description: A common error.
      type: object
      properties:
        error:
          description: Machine readable error description
          type: string
        message:
          description: Human readable error description
          type: string
      required:
        - error

    SystemStatus:
      description: System status.
      type: object
      properties:
        messageQueueStatus:
          description: Flag which indicates the status of the message queue.
          type: string
          enum:
            - GREEN
            - YELLOW
            - RED
      required:
        - messageQueueStatus

    MessageAnalysisRequest:
      description: A request to process a message
      type: object
      properties:
        borderMtaData:
          description: Data retrieved at border MTA receiving the email.
          type: object
          properties:
            envelopeFrom:
              type: string
            envelopeRecipients:
              type: array
              items:
                type: string
              minItems: 1
            remoteAddress:
              description: The IP address of the sending MTA, received at the border MTA
              type: string
            senderHelo:
              description: HELO or EHLO (host or IP) of the sending mail client, received at the border MTA.
              type: string
          required:
            - envelopeFrom
            - envelopeRecipients
        tenantUid:
          description: The tenant to which the resulting GuardRequest will be assigned
          type: string
          format: uuid
      required:
        - borderMtaData

    MessageAnalysisResult:
      description: A result of a message analysis.
      type: object
      properties:
        ggrid:
          description: The unique ID associated with the message analysis.
          type: string
          format: uuid
        created:
          description: The time when the analysis result was created.
          type: string
          format: date-time
        completed:
          description: The time when the analysis was concluded.
          type: string
          format: date-time
        decision:
          description: The decision ActiveGuard took with regards to this message.
          type: string
          enum:
            - undecided
            - deliver
            - quarantine
            - bounce
            - drop
        verdict:
          description: The verdict ActiveGuard applied to the message. https://docs.xorlab.com/latest/verdicts
          type: string
        tags:
          description: All tags associaceted with the message. See https://docs.xorlab.com/latest/tags.
          type: array
          items:
            type: string
```
