MailSlurp logo

Invoke AI transformers with MailSlurp

Documentation navigation
Search documentation

Invoke MailSlurp AI transformers from code to extract structured fields from email, SMS, attachments, images, and documents with prompts and schemas.

You can call AI transformations on emails, attachments, SMS or any content directly from code and tests.

Invocation options

Choose the input type that matches your workflow:

  • Email-centric workflows: invoke on received email content from your inboxes.
  • Attachment-centric workflows: invoke on uploaded files or email attachments.
  • SMS-centric workflows: invoke on inbound SMS where structured extraction is needed.
  • Generic text workflows: invoke on arbitrary content when you already have the payload in your application.
  1. Define your schema and extraction intent in AI transformers.
  2. Validate output fields in output schemas before production use.
  3. Invoke the transformation from your test or application flow.
  4. Route results to dashboard review, API retrieval, or webhooks.
  5. Iterate on prompt/schema design using real examples from failed or partial extractions.

Practical guidance

  • Start with a narrow schema (fewer required fields) and expand once extraction is stable.
  • Prefer deterministic field names and explicit formats for dates, currency, and identifiers.
  • Keep transformer definitions close to the business process that consumes the results.

Next pages

Invoke a saved transformer on an attachment

Create the transform using the invoice example, then pass its ID and the selected attachment ID. This uses the same REST api helper as attachment extraction.

async function invokeInvoiceTransformer(api, transformId, attachmentId) {
  const invocation = await api('/ai/transformer/invoke', {
    method: 'POST',
    body: {
      aiTransformId: transformId,
      entityType: 'ATTACHMENT',
      entityId: attachmentId,
      saveResults: true,
    },
  });

  if (!invocation.conditionsMatch) throw new Error('Transformer conditions did not match');
  if (!invocation.result) throw new Error('Transformer returned no invoice data');
  return invocation;
}

Call invokeInvoiceTransformer(api, transform.id, attachmentId). saveResults: true retains the result for later retrieval. The response contains conditionsMatch, result and tokenCount; it is different from the successful and evidence fields on message-testing AI endpoints.

POST /ai/transformer/invoke

Invoke a transformer

Execute an AI transformer to generate structured content

Request, parameters, and responses

Request body (required)

InvokeTransformerOptions application/json
FieldTypeRequiredDescription
aiTransformIdstring:uuidNo
aiTransformMappingIdstring:uuidNo
rawInputstringNo
entityIdstringNo
entityTypeenum: EMAIL | SMS | ATTACHMENTNoValues: EMAIL, SMS, ATTACHMENT
rawConditionsstring[]No
rawInstructionsstring[]No
rawOutputSchemaStructuredOutputSchemaNo
contentSelectorenum: RAW | BODY | BODY_ATTACHMENTSNoValues: RAW, BODY, BODY_ATTACHMENTS
saveResultsbooleanNo
Request example
{
  "aiTransformId": "00000000-0000-4000-8000-000000000000",
  "aiTransformMappingId": "00000000-0000-4000-8000-000000000000",
  "rawInput": "value",
  "entityId": "00000000-0000-4000-8000-000000000000",
  "entityType": "EMAIL",
  "rawConditions": [
    "value"
  ]
}

Responses

StatusSchemaDescription
200ConditionalStructuredContentResultOK
HTTP examples

HTTP

HTTP
POST /ai/transformer/invoke HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Content-Type: application/json
Accept: */*

{}

cURL

Requires cURL 7.76+ and a POSIX shell. Tested with cURL 8.12.1.

cURL
(
set -eu
response_file=$(mktemp)
request_body=$(mktemp)
trap 'rm -f "$response_file" "$request_body"' EXIT
{
  printf '%b' '{}'
} > "$request_body"
status=$(curl --silent --show-error \
  --request POST \
  --url 'https://api.mailslurp.com/ai/transformer/invoke' \
  --header 'x-api-key: YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --header 'Accept: */*' \
  --output "$response_file" \
  --write-out '%{http_code}' \
  --data-binary "@$request_body")
case "$status" in
  2??) mv "$response_file" 'response.bin' ;;
  *) printf 'HTTP %s\n' "$status" >&2; cat "$response_file" >&2; exit 1 ;;
esac
)

JavaScript (HTTP)

Requires Node.js 22+. Tested with Node.js 22.14.0.

JavaScript (HTTP)
import { writeFile } from "node:fs/promises";

const body = Buffer.concat([
  Buffer.from("{}", "utf8")
]);

const response = await fetch("https://api.mailslurp.com/ai/transformer/invoke", {
  method: "POST",
  headers: {
    "x-api-key": "YOUR_API_KEY",
    "Content-Type": "application/json",
    "Accept": "*/*"
  },
  body,
  redirect: "manual",
  signal: AbortSignal.timeout(60000),
});
const responseBytes = Buffer.from(await response.arrayBuffer());
if (!response.ok) {
  throw new Error(`HTTP ${response.status}: ${responseBytes.toString("utf8")}`);
}
await writeFile("response.bin", responseBytes);

Python (HTTP)

Requires Python 3.9+. Tested with Python 3.9.21.

Python (HTTP)
import http.client
from pathlib import Path
from urllib.parse import urlsplit

url = urlsplit("https://api.mailslurp.com/ai/transformer/invoke")
headers = {
    "x-api-key": "YOUR_API_KEY",
    "Content-Type": "application/json",
    "Accept": "*/*"
}
body = b"".join([
    "{}".encode("utf-8")
])
connection_class = http.client.HTTPSConnection if url.scheme == "https" else http.client.HTTPConnection
connection = connection_class(url.hostname, url.port, timeout=60)
try:
    path = (url.path or "/") + ("?" + url.query if url.query else "")
    connection.request("POST", path, body=body, headers=headers)
    response = connection.getresponse()
    response_bytes = response.read()
    if not 200 <= response.status < 300:
        raise RuntimeError(f"HTTP {response.status}: {response_bytes.decode('utf-8', errors='replace')}")
    Path("response.bin").write_bytes(response_bytes)
finally:
    connection.close()

Choose a source and replay a sample

For a stored message, set entityType to EMAIL or SMS and use its ID as entityId. For an attachment, use ATTACHMENT. For application-owned text, provide rawInput instead of a stored entity. Choose only the source needed for the invocation and follow the request schema for optional selectors.

When changing instructions or a schema, invoke the new transform against the same known samples. Compare expected fields in your tests, including a sample that lacks a required value and a sample that should fail the conditions. Preserve the source IDs and transform version in your own test record.

A replay is another invocation and can create another saved result. Make downstream writes idempotent and send reviewed results onward deliberately; replaying extraction should not silently duplicate a CRM entry or invoice. See results.