RETENTION
Email domain
The Sending domain object
Your sending domain: sender, DNS records and verification.
ATTRIBUTES
- object enum
- sending_domain
- id string
- domain string
- sender_name string | null
- sender_email string
- sending_host string
- status enum
provisioning: Mailgun is preparing the records (dns_records is empty until then, or provisioning_error says why it could not); pending: records to add; verified: records found and the domain active at Mailgun; failed: records still missing after 7 days.
- provisioning
- pending
- verified
- failed
- provider enum
Who holds the domain: mailgun, or fake outside production (sample records, nothing created).
- mailgun
- fake
Show 8 more attributesHide 8 attributes
- provisioning_error object | null
Why the records could not be prepared yet, with what to do; null otherwise.
- existing_dmarc boolean
A DMARC record already exists: NoChurn does not propose another one.
- fallback_address string
- from_address string
Emails go out from this address now: the sender once verified, the fallback before.
- dns_records array of objects
Schema: SendingDomain
{
"object": "sending_domain",
"id": "sdm_XajGHMam4v9qgRkg",
"domain": "acme.com",
"sender_name": "Acme billing",
"sender_email": "billing@acme.com",
"sending_host": "nc-4hmm.acme.com",
"status": "verified",
"provider": "fake",
"provisioning_error": null,
"verified_at": "2026-11-04T10:00:00Z",
"last_checked_at": "2026-11-04T10:00:00Z",
"existing_dmarc": false,
"fallback_address": "acme@mail.nochurn.sh",
"from_address": "billing@acme.com",
"dns_records": [
{
"type": "TXT",
"host": "nc-4hmm.acme.com",
"value": "v=spf1 include:mailgun.org ~all",
"purpose": "sending (SPF)",
"optional": false,
"status": "verified",
"found": "v=spf1 include:mailgun.org ~all",
"checked_at": "2026-11-04T10:00:00Z"
},
{
"type": "CNAME",
"host": "pdk1._domainkey.nc-4hmm.acme.com",
"value": "pdk1._domainkey.6b66132b30f8f0fe6a014a82.fake-dkim.mailgun.invalid",
"purpose": "signature (DKIM)",
"optional": false,
"status": "verified",
"found": "pdk1._domainkey.6b66132b30f8f0fe6a014a82.fake-dkim.mailgun.invalid",
"checked_at": "2026-11-04T10:00:00Z"
},
{
"type": "CNAME",
"host": "pdk2._domainkey.nc-4hmm.acme.com",
"value": "pdk2._domainkey.6b66132b30f8f0fe6a014a82.fake-dkim.mailgun.invalid",
"purpose": "signature (DKIM)",
"optional": false,
"status": "verified",
"found": "pdk2._domainkey.6b66132b30f8f0fe6a014a82.fake-dkim.mailgun.invalid",
"checked_at": "2026-11-04T10:00:00Z"
},
{
"type": "CNAME",
"host": "email.nc-4hmm.acme.com",
"value": "eu.mailgun.org",
"purpose": "link tracking",
"optional": false,
"status": "verified",
"found": "eu.mailgun.org",
"checked_at": "2026-11-04T10:00:00Z"
},
{
"type": "MX",
"host": "nc-4hmm.acme.com",
"value": "10 mxa.eu.mailgun.org",
"purpose": "replies, bounces",
"optional": false,
"status": "verified",
"found": "10 mxa.eu.mailgun.org",
"checked_at": "2026-11-04T10:00:00Z"
},
{
"type": "MX",
"host": "nc-4hmm.acme.com",
"value": "10 mxb.eu.mailgun.org",
"purpose": "replies, bounces",
"optional": false,
"status": "verified",
"found": "10 mxa.eu.mailgun.org",
"checked_at": "2026-11-04T10:00:00Z"
},
{
"type": "TXT",
"host": "_dmarc.acme.com",
"value": "v=DMARC1; p=none; rua=mailto:dmarc@acme.com",
"purpose": "policy",
"optional": true,
"status": "verified",
"found": "v=DMARC1; p=none; rua=mailto:dmarc@acme.com",
"checked_at": "2026-11-04T10:00:00Z"
}
],
"created_at": "2026-11-04T10:00:00Z"
} Add your sending domain
Emails go out from a random nc-xxxx subdomain, created at Mailgun: your main domain and your team's mailboxes are never touched. The domain starts in provisioning: its DNS records (SPF, DKIM, link tracking, MX) arrive within seconds, once Mailgun answered. Until the records are found and Mailgun confirms them, emails come from <account>@mail.nochurn.sh.
- Secret key (
nc_test_…ornc_live_…). Restricted keys need write access. - AI apps (OAuth): not available.
BODY PARAMETERS
- sender_name string
RETURNS
-
201domain added, records to create — the Sending domain object
ERRORS
-
422invalid_request sender outside the domain
curl https://api.nochurn.sh/v1/sending_domains \
-H "Authorization: Bearer nc_test_…" \
-H "Content-Type: application/json" \
-d '{
"domain": "acme.com",
"sender_email": "billing@acme.com",
"sender_name": "Acme billing"
}'const res = await fetch("https://api.nochurn.sh/v1/sending_domains", {
method: "POST",
headers: {
Authorization: "Bearer nc_test_…",
"Content-Type": "application/json",
},
body: JSON.stringify({
"domain": "acme.com",
"sender_email": "billing@acme.com",
"sender_name": "Acme billing"
}),
});
const sendingDomain = await res.json();import requests
res = requests.post(
"https://api.nochurn.sh/v1/sending_domains",
headers={
"Authorization": "Bearer nc_test_…",
},
json={
"domain": "acme.com",
"sender_email": "billing@acme.com",
"sender_name": "Acme billing"
},
)
sending_domain = res.json()require "net/http"
require "json"
uri = URI("https://api.nochurn.sh/v1/sending_domains")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer nc_test_…"
req["Content-Type"] = "application/json"
req.body = {
"domain" => "acme.com",
"sender_email" => "billing@acme.com",
"sender_name" => "Acme billing"
}.to_json
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
sending_domain = JSON.parse(res.body) {
"object": "sending_domain",
"id": "sdm_R37t9AFsE55k3v9L",
"domain": "acme.com",
"sender_name": "Acme billing",
"sender_email": "billing@acme.com",
"sending_host": "nc-769z.acme.com",
"status": "provisioning",
"provider": "fake",
"provisioning_error": null,
"verified_at": null,
"last_checked_at": null,
"existing_dmarc": false,
"fallback_address": "acme@mail.nochurn.sh",
"from_address": "acme@mail.nochurn.sh",
"dns_records": [],
"created_at": "2026-11-04T10:00:00Z"
} Retrieve the sending domain
- Secret key (
nc_test_…ornc_live_…). Restricted keys need read access. - AI apps (OAuth):
readscope.
PATH PARAMETERS
RETURNS
-
200a domain Mailgun could not prepare, with what to do — the Sending domain object
curl https://api.nochurn.sh/v1/sending_domains/sdm_UWVmvucdELPGdftg \
-H "Authorization: Bearer nc_test_…"const res = await fetch("https://api.nochurn.sh/v1/sending_domains/sdm_UWVmvucdELPGdftg", {
headers: {
Authorization: "Bearer nc_test_…",
},
});
const sendingDomain = await res.json();import requests
res = requests.get(
"https://api.nochurn.sh/v1/sending_domains/sdm_UWVmvucdELPGdftg",
headers={
"Authorization": "Bearer nc_test_…",
},
)
sending_domain = res.json()require "net/http"
require "json"
uri = URI("https://api.nochurn.sh/v1/sending_domains/sdm_UWVmvucdELPGdftg")
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer nc_test_…"
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
sending_domain = JSON.parse(res.body) {
"object": "sending_domain",
"id": "sdm_UWVmvucdELPGdftg",
"domain": "acme.com",
"sender_name": "Acme billing",
"sender_email": "billing@acme.com",
"sending_host": "nc-jtpt.acme.com",
"status": "provisioning",
"provider": "fake",
"provisioning_error": {
"code": "email_domain_provisioning_failed",
"message": "NoChurn could not prepare the DNS records of this domain with its email provider.",
"fix": "Click Regenerate to try with a new subdomain. Until then, emails keep coming from your NoChurn address.",
"docs_url": "https://nochurn.sh/docs/errors#email_domain_provisioning_failed"
},
"verified_at": null,
"last_checked_at": null,
"existing_dmarc": false,
"fallback_address": "acme@mail.nochurn.sh",
"from_address": "acme@mail.nochurn.sh",
"dns_records": [],
"created_at": "2026-11-04T10:00:00Z"
} Change the sender
- Secret key (
nc_test_…ornc_live_…). Restricted keys need write access. - AI apps (OAuth): not available.
PATH PARAMETERS
BODY PARAMETERS
- sender_email string
- sender_name string
RETURNS
-
200sender changed — the Sending domain object
curl https://api.nochurn.sh/v1/sending_domains/sdm_q2CtBG9Bvps85iEa \
-X PATCH \
-H "Authorization: Bearer nc_test_…" \
-H "Content-Type: application/json" \
-d '{
"sender_email": "team@acme.com"
}'const res = await fetch("https://api.nochurn.sh/v1/sending_domains/sdm_q2CtBG9Bvps85iEa", {
method: "PATCH",
headers: {
Authorization: "Bearer nc_test_…",
"Content-Type": "application/json",
},
body: JSON.stringify({
"sender_email": "team@acme.com"
}),
});
const sendingDomain = await res.json();import requests
res = requests.patch(
"https://api.nochurn.sh/v1/sending_domains/sdm_q2CtBG9Bvps85iEa",
headers={
"Authorization": "Bearer nc_test_…",
},
json={
"sender_email": "team@acme.com"
},
)
sending_domain = res.json()require "net/http"
require "json"
uri = URI("https://api.nochurn.sh/v1/sending_domains/sdm_q2CtBG9Bvps85iEa")
req = Net::HTTP::Patch.new(uri)
req["Authorization"] = "Bearer nc_test_…"
req["Content-Type"] = "application/json"
req.body = {
"sender_email" => "team@acme.com"
}.to_json
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
sending_domain = JSON.parse(res.body) {
"object": "sending_domain",
"id": "sdm_q2CtBG9Bvps85iEa",
"domain": "acme.com",
"sender_name": "Acme billing",
"sender_email": "team@acme.com",
"sending_host": "nc-qa62.acme.com",
"status": "pending",
"provider": "fake",
"provisioning_error": null,
"verified_at": null,
"last_checked_at": null,
"existing_dmarc": false,
"fallback_address": "acme@mail.nochurn.sh",
"from_address": "acme@mail.nochurn.sh",
"dns_records": [
{
"type": "TXT",
"host": "nc-qa62.acme.com",
"value": "v=spf1 include:mailgun.org ~all",
"purpose": "sending (SPF)",
"optional": false,
"status": "pending",
"found": null,
"checked_at": null
},
{
"type": "CNAME",
"host": "pdk1._domainkey.nc-qa62.acme.com",
"value": "pdk1._domainkey.a1b412bf3158ea43cca9af10.fake-dkim.mailgun.invalid",
"purpose": "signature (DKIM)",
"optional": false,
"status": "pending",
"found": null,
"checked_at": null
},
{
"type": "CNAME",
"host": "pdk2._domainkey.nc-qa62.acme.com",
"value": "pdk2._domainkey.a1b412bf3158ea43cca9af10.fake-dkim.mailgun.invalid",
"purpose": "signature (DKIM)",
"optional": false,
"status": "pending",
"found": null,
"checked_at": null
},
{
"type": "CNAME",
"host": "email.nc-qa62.acme.com",
"value": "eu.mailgun.org",
"purpose": "link tracking",
"optional": false,
"status": "pending",
"found": null,
"checked_at": null
},
{
"type": "MX",
"host": "nc-qa62.acme.com",
"value": "10 mxa.eu.mailgun.org",
"purpose": "replies, bounces",
"optional": false,
"status": "pending",
"found": null,
"checked_at": null
},
{
"type": "MX",
"host": "nc-qa62.acme.com",
"value": "10 mxb.eu.mailgun.org",
"purpose": "replies, bounces",
"optional": false,
"status": "pending",
"found": null,
"checked_at": null
},
{
"type": "TXT",
"host": "_dmarc.acme.com",
"value": "v=DMARC1; p=none; rua=mailto:dmarc@acme.com",
"purpose": "policy",
"optional": true,
"status": "pending",
"found": null,
"checked_at": null
}
],
"created_at": "2026-11-04T10:00:00Z"
} Remove the domain
- Secret key (
nc_test_…ornc_live_…). Restricted keys need write access. - AI apps (OAuth): not available.
PATH PARAMETERS
RETURNS
-
204removed
ERRORS
-
404not_found another account's domain
curl https://api.nochurn.sh/v1/sending_domains/sdm_ua6hYT8P6PmrVtzo \
-X DELETE \
-H "Authorization: Bearer nc_test_…"const res = await fetch("https://api.nochurn.sh/v1/sending_domains/sdm_ua6hYT8P6PmrVtzo", {
method: "DELETE",
headers: {
Authorization: "Bearer nc_test_…",
},
});
console.log(res.status); // 204import requests
res = requests.delete(
"https://api.nochurn.sh/v1/sending_domains/sdm_ua6hYT8P6PmrVtzo",
headers={
"Authorization": "Bearer nc_test_…",
},
)
print(res.status_code) # 204require "net/http"
require "json"
uri = URI("https://api.nochurn.sh/v1/sending_domains/sdm_ua6hYT8P6PmrVtzo")
req = Net::HTTP::Delete.new(uri)
req["Authorization"] = "Bearer nc_test_…"
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
puts res.code # 204 // No content List sending domains
- Secret key (
nc_test_…ornc_live_…). Restricted keys need read access. - AI apps (OAuth):
readscope.
RETURNS
-
200the account's domain — a list of Sending domain object (SendingDomainList)
curl https://api.nochurn.sh/v1/sending_domains \
-H "Authorization: Bearer nc_test_…"const res = await fetch("https://api.nochurn.sh/v1/sending_domains", {
headers: {
Authorization: "Bearer nc_test_…",
},
});
const page = await res.json();import requests
res = requests.get(
"https://api.nochurn.sh/v1/sending_domains",
headers={
"Authorization": "Bearer nc_test_…",
},
)
page = res.json()require "net/http"
require "json"
uri = URI("https://api.nochurn.sh/v1/sending_domains")
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer nc_test_…"
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
page = JSON.parse(res.body) {
"object": "list",
"data": [
{
"object": "sending_domain",
"id": "sdm_ua6hYT8P6PmrVtzo",
"domain": "acme.com",
"sender_name": "Acme billing",
"sender_email": "billing@acme.com",
"sending_host": "nc-utj7.acme.com",
"status": "pending",
"provider": "fake",
"provisioning_error": null,
"verified_at": null,
"last_checked_at": null,
"existing_dmarc": false,
"fallback_address": "acme@mail.nochurn.sh",
"from_address": "acme@mail.nochurn.sh",
"dns_records": [
{
"type": "TXT",
"host": "nc-utj7.acme.com",
"value": "v=spf1 include:mailgun.org ~all",
"purpose": "sending (SPF)",
"optional": false,
"status": "pending",
"found": null,
"checked_at": null
},
{
"type": "CNAME",
"host": "pdk1._domainkey.nc-utj7.acme.com",
"value": "pdk1._domainkey.0ae1cc2a3899306ae7550445.fake-dkim.mailgun.invalid",
"purpose": "signature (DKIM)",
"optional": false,
"status": "pending",
"found": null,
"checked_at": null
},
{
"type": "CNAME",
"host": "pdk2._domainkey.nc-utj7.acme.com",
"value": "pdk2._domainkey.0ae1cc2a3899306ae7550445.fake-dkim.mailgun.invalid",
"purpose": "signature (DKIM)",
"optional": false,
"status": "pending",
"found": null,
"checked_at": null
},
{
"type": "CNAME",
"host": "email.nc-utj7.acme.com",
"value": "eu.mailgun.org",
"purpose": "link tracking",
"optional": false,
"status": "pending",
"found": null,
"checked_at": null
},
{
"type": "MX",
"host": "nc-utj7.acme.com",
"value": "10 mxa.eu.mailgun.org",
"purpose": "replies, bounces",
"optional": false,
"status": "pending",
"found": null,
"checked_at": null
},
{
"type": "MX",
"host": "nc-utj7.acme.com",
"value": "10 mxb.eu.mailgun.org",
"purpose": "replies, bounces",
"optional": false,
"status": "pending",
"found": null,
"checked_at": null
},
{
"type": "TXT",
"host": "_dmarc.acme.com",
"value": "v=DMARC1; p=none; rua=mailto:dmarc@acme.com",
"purpose": "policy",
"optional": true,
"status": "pending",
"found": null,
"checked_at": null
}
],
"created_at": "2026-11-04T10:00:00Z"
}
],
"has_more": false,
"next_cursor": null
} Check the DNS records
- Secret key (
nc_test_…ornc_live_…). Restricted keys need write access. - AI apps (OAuth): not available.
PATH PARAMETERS
RETURNS
-
200every record found — the Sending domain object
ERRORS
-
409conflict records still being prepared by Mailgun
curl https://api.nochurn.sh/v1/sending_domains/sdm_ua6hYT8P6PmrVtzo/verify \
-X POST \
-H "Authorization: Bearer nc_test_…"const res = await fetch("https://api.nochurn.sh/v1/sending_domains/sdm_ua6hYT8P6PmrVtzo/verify", {
method: "POST",
headers: {
Authorization: "Bearer nc_test_…",
},
});
const sendingDomain = await res.json();import requests
res = requests.post(
"https://api.nochurn.sh/v1/sending_domains/sdm_ua6hYT8P6PmrVtzo/verify",
headers={
"Authorization": "Bearer nc_test_…",
},
)
sending_domain = res.json()require "net/http"
require "json"
uri = URI("https://api.nochurn.sh/v1/sending_domains/sdm_ua6hYT8P6PmrVtzo/verify")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer nc_test_…"
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
sending_domain = JSON.parse(res.body) {
"object": "sending_domain",
"id": "sdm_XajGHMam4v9qgRkg",
"domain": "acme.com",
"sender_name": "Acme billing",
"sender_email": "billing@acme.com",
"sending_host": "nc-4hmm.acme.com",
"status": "verified",
"provider": "fake",
"provisioning_error": null,
"verified_at": "2026-11-04T10:00:00Z",
"last_checked_at": "2026-11-04T10:00:00Z",
"existing_dmarc": false,
"fallback_address": "acme@mail.nochurn.sh",
"from_address": "billing@acme.com",
"dns_records": [
{
"type": "TXT",
"host": "nc-4hmm.acme.com",
"value": "v=spf1 include:mailgun.org ~all",
"purpose": "sending (SPF)",
"optional": false,
"status": "verified",
"found": "v=spf1 include:mailgun.org ~all",
"checked_at": "2026-11-04T10:00:00Z"
},
{
"type": "CNAME",
"host": "pdk1._domainkey.nc-4hmm.acme.com",
"value": "pdk1._domainkey.6b66132b30f8f0fe6a014a82.fake-dkim.mailgun.invalid",
"purpose": "signature (DKIM)",
"optional": false,
"status": "verified",
"found": "pdk1._domainkey.6b66132b30f8f0fe6a014a82.fake-dkim.mailgun.invalid",
"checked_at": "2026-11-04T10:00:00Z"
},
{
"type": "CNAME",
"host": "pdk2._domainkey.nc-4hmm.acme.com",
"value": "pdk2._domainkey.6b66132b30f8f0fe6a014a82.fake-dkim.mailgun.invalid",
"purpose": "signature (DKIM)",
"optional": false,
"status": "verified",
"found": "pdk2._domainkey.6b66132b30f8f0fe6a014a82.fake-dkim.mailgun.invalid",
"checked_at": "2026-11-04T10:00:00Z"
},
{
"type": "CNAME",
"host": "email.nc-4hmm.acme.com",
"value": "eu.mailgun.org",
"purpose": "link tracking",
"optional": false,
"status": "verified",
"found": "eu.mailgun.org",
"checked_at": "2026-11-04T10:00:00Z"
},
{
"type": "MX",
"host": "nc-4hmm.acme.com",
"value": "10 mxa.eu.mailgun.org",
"purpose": "replies, bounces",
"optional": false,
"status": "verified",
"found": "10 mxa.eu.mailgun.org",
"checked_at": "2026-11-04T10:00:00Z"
},
{
"type": "MX",
"host": "nc-4hmm.acme.com",
"value": "10 mxb.eu.mailgun.org",
"purpose": "replies, bounces",
"optional": false,
"status": "verified",
"found": "10 mxa.eu.mailgun.org",
"checked_at": "2026-11-04T10:00:00Z"
},
{
"type": "TXT",
"host": "_dmarc.acme.com",
"value": "v=DMARC1; p=none; rua=mailto:dmarc@acme.com",
"purpose": "policy",
"optional": true,
"status": "verified",
"found": "v=DMARC1; p=none; rua=mailto:dmarc@acme.com",
"checked_at": "2026-11-04T10:00:00Z"
}
],
"created_at": "2026-11-04T10:00:00Z"
} New random subdomain
Only while the domain is not verified: the old nc-xxxx is deleted at Mailgun and the new one prepared (status provisioning, new DNS records).
- Secret key (
nc_test_…ornc_live_…). Restricted keys need write access. - AI apps (OAuth): not available.
PATH PARAMETERS
RETURNS
-
200a new subdomain, being prepared — the Sending domain object
ERRORS
-
409conflict already verified
curl https://api.nochurn.sh/v1/sending_domains/sdm_ua6hYT8P6PmrVtzo/regenerate \
-X POST \
-H "Authorization: Bearer nc_test_…"const res = await fetch("https://api.nochurn.sh/v1/sending_domains/sdm_ua6hYT8P6PmrVtzo/regenerate", {
method: "POST",
headers: {
Authorization: "Bearer nc_test_…",
},
});
const sendingDomain = await res.json();import requests
res = requests.post(
"https://api.nochurn.sh/v1/sending_domains/sdm_ua6hYT8P6PmrVtzo/regenerate",
headers={
"Authorization": "Bearer nc_test_…",
},
)
sending_domain = res.json()require "net/http"
require "json"
uri = URI("https://api.nochurn.sh/v1/sending_domains/sdm_ua6hYT8P6PmrVtzo/regenerate")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer nc_test_…"
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
sending_domain = JSON.parse(res.body) {
"object": "sending_domain",
"id": "sdm_M8nVdo71jUpjJkUt",
"domain": "acme.com",
"sender_name": "Acme billing",
"sender_email": "billing@acme.com",
"sending_host": "nc-aya7.acme.com",
"status": "provisioning",
"provider": "fake",
"provisioning_error": null,
"verified_at": null,
"last_checked_at": null,
"existing_dmarc": false,
"fallback_address": "acme@mail.nochurn.sh",
"from_address": "acme@mail.nochurn.sh",
"dns_records": [],
"created_at": "2026-11-04T10:00:00Z"
}