Checks
Kula runs pre-send checks on campaigns, flow emails and transactional templates: variables, size, images, links. If your users write emails in your own product, call the checks from your editor and show the findings there: they never see the Kula dashboard.
Check an email
POST /v1/checks
Runs the checks on a subject and a content. Nothing is created or sent. Works with a sending access key.
contentFormat: "HTML".MARKDOWN (default) or HTML.data.* variables are allowed, no contacts are counted.curl -X POST https://api.kulamail.com/v1/checks \
-H "Authorization: Bearer ml_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "subject": "New post", "content": "Hi {{ contact.first_name }}, read it on <https://bit.ly/x>", "listId": "5a8e2c1f-0b3d-4e6a-9f7c-2d1e8b4a6c3f" }'
{
"checks": [
{
"code": "missing_variable_data",
"level": "WARNING",
"message": "412 of 3980 recipients have no first name: {{ contact.first_name }} will be empty for them. Add a default, such as {{ contact.first_name | default: \"there\" }}.",
"detail": { "variable": "contact.first_name", "missing": 412, "total": 3980 }
},
{
"code": "link_shortener",
"level": "WARNING",
"message": "This link goes through a public link shortener (bit.ly), which spam filters distrust. Use the full address: https://bit.ly/x",
"detail": { "url": "https://bit.ly/x" }
}
],
"checkedAt": "2026-10-19T09:12:04Z",
"warnings": 2,
"blocked": false,
"linksNotChecked": 0
}
Links are requested to find broken ones (30 at most, results kept an hour), so the call can take a few seconds.
Codes
message is written for a person, in English. To translate, use code and detail.
| Code | Level | detail |
|---|---|---|
missing_variable_data | WARNING | variable, missing, total |
unknown_variable | WARNING | variable |
broken_tag | WARNING | tag |
gmail_clipping | WARNING | bytes, limit |
image_only | WARNING | images, textLength |
missing_alt | WARNING | count, src (first image) |
subject_missing, subject_caps | WARNING | |
subject_long | WARNING | length |
subject_punctuation | WARNING | found |
broken_link | WARNING | url, status (null: the domain doesn't exist) |
link_shortener, ip_link, insecure_link | WARNING | url |
misleading_link | WARNING | url, shown |
blocklisted_link | BLOCK | url, threats |
render_failed | WARNING |
Checks on campaigns and templates
POST /v1/campaigns/{id}/scheduleruns the checks and returns them inchecks. Warnings never stop the campaign.- The campaign and the template objects carry their last report in
checks,nullwhen the content changed since. - Publishing a template runs them on the draft.
A blocklisted_link refuses scheduling and publishing with 409 content_blocked, and the message names the link. A scheduled campaign is checked again when it leaves: if a link turned dangerous meanwhile, the campaign becomes FAILED and the campaign.failed webhook says why.