Domain monitor schedules and alerts
Documentation navigation
Schedule domain checks and route severity-based alerts to email, Slack, Teams or a webhook.
Create a saved domain monitor before adding alerts. Choose a check interval that fits how quickly your team needs to detect a DNS or sender change. Use an immediate run after an intentional configuration change instead of waiting for the next scheduled check.
Enable a schedule
Set schedulingEnabled: true and intervalSeconds when creating or updating the monitor. For example, 86400 requests a daily interval. Turning scheduling off pauses future scheduled checks; an explicit run-now request is still permitted.
/domain-monitor/monitors/{monitorId}
Update domain monitor
Request, parameters, and responses
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
monitorId | string:uuid | Yes |
Request body (required)
| Field | Type | Required | Description |
|---|---|---|---|
name | string | No | Optional display name |
intervalSeconds | integer:int64 | No | Interval in seconds |
enabled | boolean | No | Enable/disable scheduled monitor runs (legacy alias for schedulingEnabled) |
schedulingEnabled | boolean | No | Enable/disable scheduled monitor runs. Direct run-now remains available. |
{
"name": "Example name",
"intervalSeconds": 1,
"enabled": true,
"schedulingEnabled": true
}
Responses
| Status | Schema | Description |
|---|---|---|
200 | DomainMonitorDto | OK |
HTTP examples
HTTP
PUT /domain-monitor/monitors/00000000-0000-4000-8000-000000000000 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.
(
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 PUT \
--url 'https://api.mailslurp.com/domain-monitor/monitors/00000000-0000-4000-8000-000000000000' \
--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.
import { writeFile } from "node:fs/promises";
const body = Buffer.concat([
Buffer.from("{}", "utf8")
]);
const response = await fetch("https://api.mailslurp.com/domain-monitor/monitors/00000000-0000-4000-8000-000000000000", {
method: "PUT",
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.
import http.client
from pathlib import Path
from urllib.parse import urlsplit
url = urlsplit("https://api.mailslurp.com/domain-monitor/monitors/00000000-0000-4000-8000-000000000000")
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("PUT", 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()
Keep one history for the domain when changing its interval. Creating a new monitor for every check makes it harder to compare the same sender over time.
Choose an alert destination
An alert sink belongs to one monitor. It specifies a destination type, target, minimum severity and enabled state.
| Destination | Setup |
|---|---|
| Use an address monitored by the people responsible for the sender. | |
| Webhook | Use an HTTPS receiver in your operations system. |
| Slack or Teams | Configure the destination required by the monitor's alert settings, then select the severity. |
Start with HIGH when only urgent findings should interrupt the team, or MEDIUM when the channel is used for regular sender review. The supported thresholds are LOW, MEDIUM, HIGH and CRITICAL.
// Add an alert sink and get the verification address for observed auth samples.
const alertSink =
await mailslurp.domainMonitorController.createDomainMonitorAlertSink({
monitorId: monitor.id,
createDomainMonitorAlertSinkOptions: {
type: "EMAIL",
target: YOUR_ALERT_EMAIL,
severityThreshold: "MEDIUM",
enabled: true,
},
});
const verification =
await mailslurp.domainMonitorController.createDomainMonitorEmailVerificationAddress({
monitorId: monitor.id,
});
console.log({
alertTarget: alertSink.target,
verificationAddress: verification.emailAddress,
verificationStatus: verification.status,
});
This example uses the mailslurp client and monitor from the setup page. Set YOUR_ALERT_EMAIL to your team address. It creates an email sink and a verification address for receiving authentication samples.
/domain-monitor/monitors/{monitorId}/alert-sinks
Create alert sink for monitor
Request, parameters, and responses
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
monitorId | string:uuid | Yes |
Request body (required)
| Field | Type | Required | Description |
|---|---|---|---|
type | enum: EMAIL | WEBHOOK | SLACK | TEAMS | Yes | Values: EMAIL, WEBHOOK, SLACK, TEAMS |
target | string | Yes | |
severityThreshold | enum: LOW | MEDIUM | HIGH | CRITICAL | No | Values: LOW, MEDIUM, HIGH, CRITICAL |
enabled | boolean | No |
{
"type": "EMAIL",
"target": "value",
"severityThreshold": "LOW",
"enabled": true
}
Responses
| Status | Schema | Description |
|---|---|---|
201 | DomainMonitorAlertSinkDto | Created |
HTTP examples
HTTP
POST /domain-monitor/monitors/00000000-0000-4000-8000-000000000000/alert-sinks HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Content-Type: application/json
Accept: */*
{
"type": "EMAIL",
"target": "value"
}
cURL
Requires cURL 7.76+ and a POSIX shell. Tested with cURL 8.12.1.
(
set -eu
response_file=$(mktemp)
request_body=$(mktemp)
trap 'rm -f "$response_file" "$request_body"' EXIT
{
printf '%b' '{\0012 "type": "EMAIL",\0012 "target": "value"\0012}'
} > "$request_body"
status=$(curl --silent --show-error \
--request POST \
--url 'https://api.mailslurp.com/domain-monitor/monitors/00000000-0000-4000-8000-000000000000/alert-sinks' \
--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.
import { writeFile } from "node:fs/promises";
const body = Buffer.concat([
Buffer.from("{\n \"type\": \"EMAIL\",\n \"target\": \"value\"\n}", "utf8")
]);
const response = await fetch("https://api.mailslurp.com/domain-monitor/monitors/00000000-0000-4000-8000-000000000000/alert-sinks", {
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.
import http.client
from pathlib import Path
from urllib.parse import urlsplit
url = urlsplit("https://api.mailslurp.com/domain-monitor/monitors/00000000-0000-4000-8000-000000000000/alert-sinks")
headers = {
"x-api-key": "YOUR_API_KEY",
"Content-Type": "application/json",
"Accept": "*/*"
}
body = b"".join([
"{\n \"type\": \"EMAIL\",\n \"target\": \"value\"\n}".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()
/domain-monitor/monitors/{monitorId}/alert-sinks
List alert sinks for monitor
Request, parameters, and responses
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
monitorId | string:uuid | Yes |
Responses
| Status | Schema | Description |
|---|---|---|
200 | DomainMonitorAlertSinkDto[] | OK |
HTTP examples
HTTP
GET /domain-monitor/monitors/00000000-0000-4000-8000-000000000000/alert-sinks HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Accept: */*
cURL
Requires cURL 7.76+ and a POSIX shell. Tested with cURL 8.12.1.
(
set -eu
response_file=$(mktemp)
trap 'rm -f "$response_file"' EXIT
status=$(curl --silent --show-error \
--request GET \
--url 'https://api.mailslurp.com/domain-monitor/monitors/00000000-0000-4000-8000-000000000000/alert-sinks' \
--header 'x-api-key: YOUR_API_KEY' \
--header 'Accept: */*' \
--output "$response_file" \
--write-out '%{http_code}')
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.
import { writeFile } from "node:fs/promises";
const response = await fetch("https://api.mailslurp.com/domain-monitor/monitors/00000000-0000-4000-8000-000000000000/alert-sinks", {
method: "GET",
headers: {
"x-api-key": "YOUR_API_KEY",
"Accept": "*/*"
},
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.
import http.client
from pathlib import Path
from urllib.parse import urlsplit
url = urlsplit("https://api.mailslurp.com/domain-monitor/monitors/00000000-0000-4000-8000-000000000000/alert-sinks")
headers = {
"x-api-key": "YOUR_API_KEY",
"Accept": "*/*"
}
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("GET", path, 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()
Investigate a missing alert
Check that the monitor's schedule is enabled, a run has completed, the alert sink is enabled and the finding meets the severity threshold. Inspect the actual run: an unchanged or lower-severity result may not be the event you expected. Confirm the destination configuration before broadening the alert threshold.
Use notification settings for account and device-render notifications. Domain-monitor sinks have their own monitor-specific configuration. Read monitor results to investigate the evidence behind an alert.
Running this code needs an API key. Get one free