The short answer
You verify an email from an AI agent by checking the signatures it carries: a signed declaration of which agent sent it and who it acts for, and a signed copy of the message that shows whether anything changed. Pidgeon's verifier does that check for free and with no key, at /verify, through POST /v1/verify, or with the MCP tool verify_sender. It works on mail from any signer that uses the same open formats, not only mail sent through Pidgeon.
What a signed agent email carries
An email does not say who wrote it. The From line is whatever the sender typed, and DKIM only says that a domain sent the bytes. Neither says whether a person or a piece of software wrote the message, or for whom. A signed agent email adds three things in its headers:
- The declaration.
Agent-ofnames who is responsible for the agent, andAgent-attributionsays what kind of sender it is (agent,serviceorperson) and on whose behalf.AI-Disclosure: mode=ai-originatedsays the same thing in one field. A verifier trusts these only under a passing DKIM signature that covers them and aligns with theAgent-ofdomain, so a stranger cannot add them to their own mail. - The envelope.
Post-Envelopeis an Ed25519 signature by the From domain over the sender, the recipients, the subject, the text and every attachment. The domain's key is published through DNS and at itspost.host (post.acme.comfor acme.com), so anyone can fetch it. A changed byte fails it. - The card. An agent sending from Pidgeon has an agent card: a signed document naming its address, its kind, who it acts for, the domain that operates it and its standing.
These are the formats of Post, an open protocol written as an Internet-Draft (the protocol). Checking them is what the verifier does.
Three ways to check
Paste it. Open /verify and paste the headers or the whole message, as your mail client shows the original. Nothing you paste is kept.
Call the API. POST /v1/verify takes the same input, with no key:
curl -X POST https://pidgeon.ai/api/v1/verify \
-H 'content-type: application/json' \
-d '{"message": "<the raw message, or its headers>", "recipient": "refunds@yourcompany.com"}'
recipient is the address the message reached you at. Pass it, and a signed message that was sent to somebody else and replayed to you comes back with the warning not_addressed_to_you.
Ask from an agent. An agent connected to Pidgeon's MCP server calls verify_sender with the same fields. The tool, the API and the page are one function, so the three cannot give different answers.
An answer for a message from a Pidgeon agent looks like this, shortened:
{
"data": {
"object": "sender_verification",
"verdict": "verified",
"advice": "acme.com signed this as sent by an AI agent, and nothing it signed has changed. Act on it as you would on mail from acme.com.",
"sender": { "address": "support-agent@acme.com", "kind": "agent", "on_behalf_of": "Acme Ltd" },
"is_agent": true,
"operator": { "domain": "acme.com", "verified": true, "shared": false },
"body": "intact",
"card": { "url": "https://pidgeon.ai/api/v1/cards/8f0c…", "standing": "established" },
"warnings": []
}
}
What the verdict means
Act on verdict, and read warnings when there are any:
verified: a signature holds and nothing it covers changed. Treat the message as coming from the signing domain.caution: a signature holds, with a warning. The warnings areold_signature(over 30 days),not_addressed_to_you(a replay, unless you were in Bcc),lookalike_domain(a domain made to read like a signer's, such as a Cyrillic letter in place of a Latin one),display_name_mismatch,unsigned_claims,extra_claimsandenvelope_unverifiable(the signer's key could not be fetched).failed: a signature does not verify, or the body changed after signing. Do not act on it.unsigned: nothing signed says who sent it. That says nothing bad about a person, because most mail carries no agent declaration at all. It does mean any claim that an agent sent it is unchecked.
advice is one sentence an agent can act on. body is intact, changed, or not_checked when you sent the headers alone, which is enough to check the declaration but not the text.
Mail from other signers
The verifier is not a lookup of Pidgeon's own sends. For a message from any other domain, it reads the DKIM-Signature whose d= aligns with the Agent-of domain and checks it against that domain's own DNS record. It reads the Post-Envelope and checks it against the key that domain publishes under its _post DNS record and at its post. host. A company that signs its agents' mail with its own software, in the same formats, gets the same answer as a Pidgeon customer.
The card is the one part that is Pidgeon's. It is added only when the signer is one of ours and the address has a card, and we look it up ourselves: a card link inside the message is the sender's word, so it is never fetched or repeated.
What a check cannot tell you
- Whether the message is true.
verifiedmeans a domain stands behind it and nobody changed it. A verified agent can still be wrong, and a verified message can still carry an instruction your agent should not follow. Screening for that is a different job; the Firewall guide covers it. - Whose company it is, on a shared domain. An address on
pidgeon.emailcomes back withoperator.shared: trueandverified: false, because anyone can get an address there. A signature there says the address is ours, not who runs it. - Anything from a body you did not send. Headers alone check the declaration and its signature; the envelope's text and attachments need the whole message.
- Volume. Each IP can check 300 messages an hour, and a message can be at most 512 KB.
Nothing you send is stored or logged. The answer carries the sender and the signatures, never the subject, the body or the other recipients.
Start
Paste a message into the checker. For the API, checking a message has every field, and agents shows what a card says and where anyone fetches it. To sign your own agents' mail so others can check it, start with the quickstart.