Use this guide when the domain already exists in Cloudflare, or you prefer to onboard the zone manually in Cloudflare before KaisouMail enables and uses it.
Unlike the project-direct bind flow, this path does not let KaisouMail create the zone for you. You add the domain in Cloudflare first, then return to /domains to enable it.
The API Worker runtime must have:
EMAIL_ROUTING_MANAGEMENT_ENABLED=trueCLOUDFLARE_RUNTIME_API_TOKEN (or the shared CLOUDFLARE_API_TOKEN)EMAIL_WORKER_NAMEIf these runtime variables are incomplete, the app may still boot, but /domains will not have the full Cloudflare domain-management capability.
The same runtime variables are reused by the domain-level Catch All toggle, so enabling Catch All does not require any extra secrets.
Use the runtime token minimum described in Cloudflare Token Permissions.
For the “add in Cloudflare first, enable in KaisouMail later” path, runtime must at least be able to:
If you also plan to use project-direct zone creation or project-side zone deletion later, keep the same full runtime permission set instead of maintaining a second token profile.
After deploy, confirm:
GET /api/meta returns cloudflareDomainLifecycleEnabled=true/domains can load the Cloudflare-backed domain catalogThis only verifies that the project can manage existing zones. It does not require cloudflareDomainBindingEnabled=true, because that flag only gates direct zone creation from the project.
example.com.active in Cloudflare.If you skip nameserver delegation, KaisouMail may still discover the zone later, but Email Routing enablement will usually stop at provisioning_error.
/domains in the control plane.GET /api/domains/catalog to discover the zone.domains record and tries to enable Email Routing on that zone.active.If the zone is still pending on the Cloudflare side, the project will usually keep the local record and show provisioning_error. Once the zone becomes active, return to /domains and click Retry.
Once the domain is active, KaisouMail uses it in these places:
POST /api/mailboxes: when rootDomain is omitted, the server randomly chooses one active domainPOST /api/mailboxes/ensure: segmented mailbox creation can omit rootDomain as wellGET /api/meta: only returns active domains, not the full Cloudflare catalogThe Web control plane mailbox form can also target that domain directly. As long as it stays active, new mailboxes can continue using that root domain.
If an admin later enables Catch All from /domains, unregistered addresses on
that domain can also receive mail and will appear in the project as long-lived
Catch All mailboxes.
/domainsCheck these items first:
EMAIL_ROUTING_MANAGEMENT_ENABLED is trueGET /api/meta already reports cloudflareDomainLifecycleEnabled=trueIf the catalog is still empty, re-check Cloudflare Token Permissions and Deployment & Environment.
/domains, but enablement failsThe most common cause is that the token can read the zone but cannot write the Email Routing settings required for enablement.
Verify:
Zone: Zone: ReadZone: Email Routing Rules: EditZone: Zone Settings: EditIf the error is Authentication error or forbidden, the problem is usually here.
provisioning_error after enablementThis usually means the project created the local record, but the Cloudflare side is not ready yet:
pendingactive/domains and click RetryThis means the project already has a local record for the same root domain:
activeprovisioning_errorInspect the existing row in the domain catalog first, then decide whether to enable, retry, or clean up the old record instead of creating it again.