Skip to content

Domains ​

Manage domains in your organization.

Report ingest addresses ​

Every domain has its own report mailbox. Publish it in your DMARC rua/ruf tags and your TLS-RPT rua tag so reports reach MailShield.

The address is returned as a reporting object on every domain response (create, list, get and update), so a scripted onboarding can publish DNS in the same pass that creates the domain:

json
"reporting": {
  "ruaAddress": "mailto:942d71ef@reports.mailshield.app",
  "rufAddress": "mailto:942d71ef@reports.mailshield.app",
  "tlsRptAddress": "mailto:942d71ef@reports.mailshield.app"
}

All three currently resolve to the same mailbox. They are named separately so your integration binds to a per-report-type contract rather than to that fact.

WARNING

Use the address exactly as returned. A rua pointing at the wrong mailbox fails silently: reports are simply never delivered, with no error anywhere.

Customer ​

Every domain response shows the customer the domain is assigned to as customerId and customerName, both null when it has none. Assign or remove the customer with Update Domain, and list one customer's domains with the customerId filter.

List Domains ​

Returns a paginated list of all domains, newest first.

GET /api/v1/domains

Query Parameters ​

ParameterTypeDefaultDescription
pageinteger1Page number
limitinteger20Items per page, 1 to 100. Larger values return 100
customerIdstringOnly the domains assigned to this customer, or none for the domains without a customer

page and limit must be whole numbers; anything else returns 400. Keep requesting the next page while meta.pagination.hasMore is true.

A customerId that isn't one of your customers returns 404, and a value that's neither a customer ID nor none returns 400.

Response ​

json
{
  "data": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "domain": "example.com",
      "verified": true,
      "usageType": "sends-and-receives",
      "testEmailLocalPart": "admin",
      "customerId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
      "customerName": "Acme Corp",
      "reporting": {
        "ruaAddress": "mailto:942d71ef@reports.mailshield.app",
        "rufAddress": "mailto:942d71ef@reports.mailshield.app",
        "tlsRptAddress": "mailto:942d71ef@reports.mailshield.app"
      },
      "lastCheckedAt": "2024-01-15T10:30:00Z",
      "createdAt": "2024-01-01T00:00:00Z",
      "updatedAt": "2024-01-15T10:30:00Z"
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "limit": 20,
      "hasMore": false
    }
  }
}

Example ​

bash
curl -H "Authorization: Bearer ms_your_token" \
  "https://app.mailshield.app/api/v1/domains?limit=10"

The domains of one customer:

bash
curl -H "Authorization: Bearer ms_your_token" \
  "https://app.mailshield.app/api/v1/domains?customerId=7c9e6679-7425-40de-944b-e07fc1f90ae7"

Create Domain ​

Add a new domain to your organization.

POST /api/v1/domains

Request Body ​

FieldTypeRequiredDescription
domainstringYesDomain name (e.g., "example.com"). Internationalized names are stored in their ASCII (punycode) form
usageTypestringNoHow the domain is used (default: "sends-and-receives")
testEmailLocalPartstringConditionalThe part before the @ of an address at the domain that accepts mail, such as postmaster. Required for domains that receive email
customerIdstringNoThe ID of a customer in your organization to assign the domain to. Another ID returns 400

Usage Types:

  • sends-and-receives - Domain sends and receives email
  • receives-only - Domain only receives email
  • sends-only - Domain only sends email
  • parked - Domain is parked (no email)

Response (201 Created) ​

json
{
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "domain": "example.com",
    "verified": false,
    "usageType": "sends-and-receives",
    "testEmailLocalPart": "admin",
    "customerId": null,
    "customerName": null,
    "lastCheckedAt": null,
    "createdAt": "2024-01-15T10:30:00Z",
    "updatedAt": "2024-01-15T10:30:00Z",
    "reporting": {
      "ruaAddress": "mailto:942d71ef@reports.mailshield.app",
      "rufAddress": "mailto:942d71ef@reports.mailshield.app",
      "tlsRptAddress": "mailto:942d71ef@reports.mailshield.app"
    },
    "verificationToken": "abc123xyz",
    "verificationRecord": {
      "hostname": "_mailshield.example.com",
      "type": "TXT",
      "value": "mailshield-verify=abc123xyz"
    }
  }
}

Publish verificationRecord in your DNS, then call Verify Domain. A new domain has no customer; assign one with Update Domain.

Example ​

bash
curl -X POST \
  -H "Authorization: Bearer ms_your_token" \
  -H "Content-Type: application/json" \
  -d '{"domain": "example.com", "testEmailLocalPart": "admin"}' \
  https://app.mailshield.app/api/v1/domains

Errors ​

  • 400 - Invalid domain name, missing required fields, or a body that isn't valid JSON
  • 403 - Domain limit reached (upgrade required), a payment is overdue, or the token is read-only
  • 409 - The domain is already in your organization. Other organizations can monitor the same domain; that never causes an error.

Get Domain ​

Returns domain details with the latest DNS check results.

GET /api/v1/domains/{id}

Path Parameters ​

ParameterTypeDescription
iduuidDomain ID. An ID that isn't a UUID returns 404

Response ​

json
{
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "domain": "example.com",
    "verified": true,
    "usageType": "sends-and-receives",
    "testEmailLocalPart": "admin",
    "customerId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
    "customerName": "Acme Corp",
    "reporting": {
      "ruaAddress": "mailto:942d71ef@reports.mailshield.app",
      "rufAddress": "mailto:942d71ef@reports.mailshield.app",
      "tlsRptAddress": "mailto:942d71ef@reports.mailshield.app"
    },
    "lastCheckedAt": "2024-01-15T10:30:00Z",
    "createdAt": "2024-01-01T00:00:00Z",
    "updatedAt": "2024-01-15T10:30:00Z",
    "checks": {
      "mx": { /* MX check results */ },
      "spf": { /* SPF check results */ },
      "dkim": [ /* DKIM check results */ ],
      "dmarc": { /* DMARC check results */ },
      "mtaSts": { /* MTA-STS check results */ },
      "tlsRpt": { /* TLS-RPT check results */ },
      "bimi": { /* BIMI check results */ },
      "dnssec": { /* DNSSEC check results */ }
    }
  }
}

Each check is the latest stored result, or null if that check hasn't run yet. dkim has the latest result for each known selector. See DNS Checks for the fields of each check.

Example ​

bash
curl -H "Authorization: Bearer ms_your_token" \
  https://app.mailshield.app/api/v1/domains/550e8400-e29b-41d4-a716-446655440000

Update Domain ​

Update domain settings, and assign the domain to a customer. Only the fields you send change.

PATCH /api/v1/domains/{id}

Path Parameters ​

ParameterTypeDescription
iduuidDomain ID

Request Body ​

FieldTypeDescription
usageTypestringHow the domain is used
testEmailLocalPartstring or nullThe part before the @ of an address at the domain that accepts mail. Can't be empty while the domain receives email
customerIduuid or nullAssigns the domain to this customer in your organization. null removes it from its customer

Response ​

json
{
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "domain": "example.com",
    "verified": true,
    "usageType": "sends-only",
    "testEmailLocalPart": null,
    "customerId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
    "customerName": "Acme Corp",
    "reporting": {
      "ruaAddress": "mailto:942d71ef@reports.mailshield.app",
      "rufAddress": "mailto:942d71ef@reports.mailshield.app",
      "tlsRptAddress": "mailto:942d71ef@reports.mailshield.app"
    },
    "lastCheckedAt": "2024-01-15T10:30:00Z",
    "createdAt": "2024-01-01T00:00:00Z",
    "updatedAt": "2024-01-15T12:00:00Z"
  }
}

Example ​

bash
curl -X PATCH \
  -H "Authorization: Bearer ms_your_token" \
  -H "Content-Type: application/json" \
  -d '{"usageType": "sends-only"}' \
  https://app.mailshield.app/api/v1/domains/550e8400-e29b-41d4-a716-446655440000

Assign the domain to a customer:

bash
curl -X PATCH \
  -H "Authorization: Bearer ms_your_token" \
  -H "Content-Type: application/json" \
  -d '{"customerId": "7c9e6679-7425-40de-944b-e07fc1f90ae7"}' \
  https://app.mailshield.app/api/v1/domains/550e8400-e29b-41d4-a716-446655440000

Errors ​

  • 400 - Invalid fields, a change of usageType or testEmailLocalPart that leaves a domain that receives email without testEmailLocalPart, or a customerId that isn't one of your customers
  • 404 - Domain not found
  • 409 - The domain is on passive monitoring, which is only for parked domains. Turn off passive monitoring in the domain's settings before changing its usage type

Delete Domain ​

Remove a domain and all associated data.

DELETE /api/v1/domains/{id}

Path Parameters ​

ParameterTypeDescription
iduuidDomain ID

Response ​

json
{
  "data": {
    "deleted": true
  }
}

Example ​

bash
curl -X DELETE \
  -H "Authorization: Bearer ms_your_token" \
  https://app.mailshield.app/api/v1/domains/550e8400-e29b-41d4-a716-446655440000

WARNING

This action cannot be undone. All DNS checks, reports, and alerts for this domain will be permanently deleted.


Verify Domain ​

Check or perform domain ownership verification.

Get Verification Status ​

GET /api/v1/domains/{id}/verify

Returns the verification status and the required DNS record.

json
{
  "data": {
    "verified": false,
    "verificationRecord": {
      "hostname": "_mailshield.example.com",
      "type": "TXT",
      "value": "mailshield-verify=abc123xyz"
    }
  }
}

Verify Domain ​

POST /api/v1/domains/{id}/verify

Attempts to verify the domain by checking for the DNS TXT record.

json
{
  "data": {
    "verified": true,
    "message": "Domain verified successfully"
  }
}

If verification fails, the response is still a 200, with verified: false and a message that says why:

json
{
  "data": {
    "verified": false,
    "message": "No TXT record found at _mailshield.example.com. Publish the record in \"expected\", then try again. New records can take a few minutes to appear.",
    "expected": {
      "hostname": "_mailshield.example.com",
      "type": "TXT",
      "value": "mailshield-verify=abc123xyz"
    }
  }
}

When a record exists but doesn't match, found has its value. When the DNS lookup itself failed, the response has lookupFailed: true: the record couldn't be checked, so try again in a minute rather than changing DNS.

Monitor and secure your email domains.