# How the DMARC stage ramp works

> How we move a domain's DMARC policy from none to quarantine to reject, and how to hold a stage or change it yourself.

Source: https://docs.coritan.com/mail/dmarc/

In the dashboard:

- /dashboard/mail/…/settings: https://www.coritan.com/dashboard/mail
- /dashboard/mail/…/domains: https://www.coritan.com/dashboard/mail

DMARC tells other mail servers what to do with a message that claims to come from your domain but fails SPF and DKIM. Every domain on a Mail Hosting or SMTP Relay service has a DMARC record. It starts at the gentlest *stage*, and we move it up as reports show that your real mail passes.

## The three stages

`p=none`
: Receivers deliver failing mail as usual, and send reports about it. Every new domain starts here.

`p=quarantine`
: Receivers treat failing mail as suspicious, which often means the spam folder.

`p=reject`
: Receivers refuse failing mail.

The stage is the `p=` value of the record at `_dmarc.example.com`, such as `v=DMARC1; p=quarantine; adkim=r; aspf=r`. The record uses *relaxed alignment* (`adkim=r; aspf=r`): a message passes when its SPF or DKIM domain shares its main domain with the From address, such as `send.example.com` for mail from `alex@example.com`. [Mail DNS records](/mail/dns-records/) lists the full record and how we check it.

## When the stage moves up

Once a day we look at every verified domain that is not held and not yet at `p=reject`. A domain moves up one stage when all of these are true:

- It has been at its current stage for at least 14 days.
- The aggregate reports from receivers over the last 14 days cover at least 100 messages.
- At least 98% of those messages passed.
- No receiver sent a failure report in that time.

The ramp never moves a domain down. Moving down is always your choice, because a weaker policy also makes your domain easier to spoof.

Receivers send their reports to the `rua=mailto:` address in the record, when the record the dashboard shows has one. Keep that part of the record as it is: without reports, the stage stays where it is.

## What changes when the stage moves

When we publish your records into a zone on Coritan DNS, we replace our `_dmarc` record with the new value ourselves.

When your DNS is elsewhere, the **DNS records** card shows the new value, and the domain's **DMARC** check fails with `DMARC publishes p=none, expected p=quarantine` until you update the record at your DNS provider. We send no message about it: the **DMARC** column on the **Domains** tab shows each domain's current stage. DMARC does not count towards verification, so the domain keeps sending while the record catches up.

## Holding a stage or setting one yourself

Two places show a domain's stage and change it:

- The **DMARC policy** card on the domain's page: go to the **Domains** tab and select the domain. It has the **Stage** select and the **Hold this stage** switch, and says since when the domain has been at its stage.
- The **DMARC** card on the **Settings** tab, on Mail Hosting only. It lists every domain with a stage select and a **Hold stage** switch, and says for each whether it is held or ramps automatically.

Choosing a stage applies it at once and holds the domain there, so the ramp stops. Turning the hold off lets the ramp carry on from the stage you chose. Holding a stage without changing it stops the ramp where it is.

A change you make takes effect the same way as one the ramp makes: we update a record we publish, and you update a record you publish yourself.

## When your zone already has a DMARC record

When we publish into your zone on Coritan DNS and the zone already has a DMARC record that we did not add, your record stays and ours is never added. The domain's stage takes your record's `p=` value and is held there, and the ramp does not change it.

To move such a domain, change `p=` in your own record, then select **Verify now** on the domain's page so the stage follows it. Choosing a stage in the dashboard is refused with `The DMARC record for example.com in your DNS was not added by us. Change its p= value in the zone instead.`

## With the API

Set a stage and hold it:

```bash
curl -X PATCH https://api.coritan.com/api/v1/client/mail/4812/domains/311/dmarc \
  -H "Authorization: Bearer $CORITAN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"stage": "quarantine", "pinned": true}'
```

Use `/client/smtp-relay/` in the path for an SMTP Relay service. The body takes two optional fields:

`stage`
: `none`, `quarantine` or `reject`. Leave it out to keep the current stage. Any other value answers `422`.

`pinned`
: `true` holds the stage and `false` lets the ramp move it. Leave it out to keep the current setting. Unlike the dashboard, sending a `stage` alone does not hold it.

The response holds the updated domain, with `dmarc_policy`, `dmarc_pinned` and `dmarc_stage_since`, and its records to publish, in the same shape as [the records endpoint](/mail/dns-records/#with-the-api). A stage change refused because of your own DMARC record answers `409` with the message above, and a domain that is not on the service answers `404` `Domain not found`.

## API

- `PATCH /api/v1/client/mail/{service_id}/domains/{domain_id}/dmarc`: Set DMARC (https://docs.coritan.com/api/reference/client/mail/mail-domains/#op-patch-api-v1-client-mail-service-id-domains-domain-id-dmarc)
- `PATCH /api/v1/client/smtp-relay/{service_id}/domains/{domain_id}/dmarc`: Set DMARC (https://docs.coritan.com/api/reference/client/mail/smtp-relay-domains/#op-patch-api-v1-client-smtp-relay-service-id-domains-domain-id-dmarc)
