propgate docs

CLIcheck

check

propgate check <domain> needs no account, no config file, and no network beyond DNS. It resolves against whichever server you point it at, defaulting to the system resolver, using the same engine as the public checker and the API.

propgate — DNS diagnosis from the terminal

  propgate check <domain> [options]

Account and domains (see `propgate signup --help`)
  propgate signup --email <address>
  propgate confirm --email <address> --code <code>
  propgate keys list | create <name> | revoke <prefix>
  propgate domains add <domain> --profile <key> | list

Options
  --selector <name>     A DKIM selector to check. Repeatable.
  --spf-include <name>  An include: token that must authorise this domain.
  --caa-issuer <name>   A certificate authority that must be authorised.
  --receives-mail       This domain should receive mail, so undeliverable
                        mail is a problem. Unstated by default.
  --only <kinds>        Comma-separated: delegation, spf, dkim, dmarc, mx, caa.
  --resolver <addr>     Resolver to query, as address or address:port.
                        Defaults to the system resolver.
  --trace               Print every DNS query behind the answer.
  --json                Machine-readable output.
  --help, --version

Exit codes
  0  nothing to fix
  1  something is wrong
  2  a check could not be completed — which is not the same as a failure

Every flag

FlagWhat it does
--selector <name>A DKIM selector to check. Repeatable: pass it once per selector in use.
--spf-include <name>An include: token that must authorise this domain, after recursive expansion.
--caa-issuer <name>A certificate authority that must be authorised, climbed per RFC 8659.
--receives-mailThis domain should receive mail, so undeliverable mail is a problem. Unstated by default. See "--receives-mail" below.
--only <kinds>Comma-separated subset of delegation, spf, dkim, dmarc, mx, caa. Runs all six when omitted.
--resolver <addr>Resolver to query, as address or address:port. Defaults to the system resolver, and the port is never assumed to be 53.
--tracePrint every DNS query behind the answer: server, name, type, and outcome.
--jsonMachine-readable output. See "--json" below.
--help, --version
npx @propgate/cli check github.com --only spf
github.com

   ! spf
    - Part of this domain's SPF record changes for every connection, so it
      cannot be checked from the published records alone.
      %{i} needs something this check does not have
      found:  exists:%{i}._spf.mta.salesforce.com
      SPF_MACRO_NOT_EVALUATED
    ! This domain's SPF record is close to the ten-lookup limit, so adding one
      more sending service is likely to break it.
      0 of the ten lookups are left, so the next sending service added is
      likely to break SPF outright
      found:  10 lookups
      wanted: at most 7 lookups, to leave room to grow
      SPF_LOOKUP_LIMIT_NEAR

1 thing worth looking at

GitHub's SPF record works today and sits at exactly the ten DNS lookups RFC 7208 allows. The next include: anyone adds breaks mail delivery, with no error at the moment of the edit. Finding that needs recursive include: expansion with the lookup and void-lookup limits actually counted. A regex over a TXT record cannot do it.

Asserting something specific fails loudly when it is missing:

npx @propgate/cli check example.com --only spf --spf-include _spf.google.com
x spf
    x This domain's SPF record does not authorise the sending service being
      set up, so its messages will fail SPF.
      add include:_spf.google.com before the all mechanism; added after it,
      the term never runs
      found:  no include: or redirect= terms at all
      wanted: include:_spf.google.com
      SPF_SOURCE_NOT_AUTHORIZED

1 problem to fix

Exit codes

CodeMeaning
0Nothing to fix. Warnings count as nothing to fix — they describe something that works.
1Something is wrong.
2A check could not be completed.

That third code is the one worth pausing on: it is not a failure. A resolver that timed out, or a lookup that came back SERVFAIL, says nothing about the domain. The resolver kept indeterminate separate from fail all the way down specifically so this exit code could exist. Collapsing it into 1 is how a deployment gate starts blocking releases over someone else's bad second, on a domain that was never actually misconfigured.

npx @propgate/cli check example.com --only spf,dkim --selector app || exit $?

--receives-mail

Whether a null MX is correct depends entirely on what the domain is for, and no amount of looking at DNS reveals that: a sending-only domain and a domain that has forgotten to set up mail publish the identical record. The underlying model has three states: expects mail, does not, and unstated.

The flag itself can only reach two of them. Passing --receives-mail asserts true; leaving it off leaves the check unstated. There is no flag for asserting false, no way from the CLI to say "this domain deliberately sends no mail", because a check that makes no claim already produces the right answer for that domain: mx observes a null MX and reports it as MX_NULL, informational, never a failure, without anyone having to say anything.

Pass the flag and that same null MX becomes MX_MAIL_NOT_ACCEPTED, an error: the check now knows mail was expected and cannot be delivered.

--json

npx @propgate/cli check example.com --only dmarc --json
{
  "checks": [
    {
      "findings": [],
      "kind": "dmarc",
      "lookups": [
        {
          "name": "_dmarc.example.com",
          "purpose": "the domain's own DMARC policy",
          "server": "1.1.1.1:53",
          "status": "answered",
          "type": 16
        }
      ],
      "verdict": "pass"
    }
  ],
  "domain": "example.com",
  "verdict": "pass"
}

Every result carries its derivation, not just the verdict: which lookups happened, against which server, and what each returned. A verdict you cannot audit is a verdict you have to take on faith. --trace prints the same underlying data in human form alongside the findings, rather than as a separate machine-readable document.