ScanMyPassKhatdocs
HomeSign in

Get started

  • Setup
  • DNS records

Reference

  • Sending mail
  • Receiving mail
  • Delivery & webhooks
  • Errors & limits
  • Security

For agents

  • llms.txt

Reference

Receiving mail

Off by default. Turn it on for a domain, publish one MX record, and replies arrive in an inbox you can read — or as a webhook, if you would rather your application handled them.

Turning it on#

On the domain's page, Receiving tab, switch it on. You then get one record to publish:

dns
inbox.example.com.   3600   IN   MX   10 mail.scanmypass.com.

Every address at that host works — anything@inbox.example.com. There are no mailboxes to create.

Why the default is a subdomain

An MX record at your domain itself replaces wherever that domain currently receives mail. If you have a mailbox on Google Workspace, Microsoft 365 or your host, pointing the apex here diverts it and that mail stops arriving.

So the default is inbox, on a subdomain, which leaves your existing mail untouched. You can choose the apex, and the dashboard says exactly what that will do before you do it.

Accepting only some addresses#

By default every address is accepted. Name the ones you want and only those get through:

http
PATCH /v1/domains/{id}
{ "addresses": ["info", "support"] }

Now info@ and support@ arrive and everything else is refused with a 550 at the door, so the sender gets a bounce. That is deliberate — accepting a message and then discarding it because the address does not exist tells the sender it was delivered when it was not.

An empty list goes back to accepting everything.

Reading what arrived#

GET/v1/inboundAPI key

Newest first. ?unread=true, ?search=, ?domainId=, ?cursor=, ?limit=.

GET/v1/inbound/{id}API key

The full message, with headers, bodies and its attachment list. Opening it marks it read.

GET/v1/inbound/{id}/attachments/{attachmentId}API key

The file itself, served as a download.

GET/v1/inbound/{id}/rawAPI key

The original bytes as message/rfc822. A parser is only ever an interpretation, so the message as it actually arrived is kept too.

DELETE/v1/inbound/{id}API key

Deletes the message and its attachments.

Trusting the sender#

Each message carries what the receiving path observed, and an authenticated flag that is true only when all three pass:

json
{
  "fromAddress": "someone@example.org",
  "spfResult": "pass",
  "dkimResult": "pass",
  "dmarcResult": "pass",
  "authenticated": true
}

Mail that fails is still delivered to you. Refusing it at the SMTP layer would drop legitimate mail from badly configured senders, so the verdict is recorded and the judgement left to you. A null means the check did not run — not that it failed.

An unauthenticated sender is an unverified one

Anyone can put any address in a From header. Only a passing DMARC check makes it mean anything. If you act on inbound mail automatically, gate that on authenticated.

Handling the HTML safely#

The html field is returned exactly as it arrived — script tags and all. It is a stranger's markup, and sanitising it server-side would be a claim about your rendering context that we cannot make.

  • Render it in an iframe with sandbox="" and srcDoc, which is what the dashboard does — nothing executes and it cannot reach your origin.
  • Or show the text field instead.
  • Never render an inbound attachment inline in your own origin. They are served with Content-Disposition: attachment and nosniff for that reason.

How much you can keep#

Received mail is kept whole and indefinitely — bodies, attachments, and the original message — so it counts against a storage allowance. Sending consumes none of it. The allowance is pooled across your whole account rather than split per mailbox, so two addresses draw on one figure.

GET/v1/inbound/storageAPI key

What you are using, and against what.

json
{
  "usedBytes": 18357,
  "limitBytes": 2147483648,
  "fraction": 0.0000085,
  "messages": 4,
  "full": false
}

What is counted is each message as it arrived plus its attachments — the size your mail client would show you, not what encryption adds on top.

Running out defers mail, it does not lose it

When you are out of space, new mail is refused with a temporary error rather than accepted and dropped. The sending server keeps retrying for several days, so delete what you do not need — or move up a tier — and the held messages arrive. If you are still full when the sender gives up, they get a bounce telling them so. What does not happen is a message vanishing after its sender was told it was delivered.

Or have it pushed to you#

Subscribe to email.received and you get told rather than having to poll:

json
{
  "event": "email.received",
  "timestamp": "2026-08-17T12:00:00.000Z",
  "inboundId": "in_r971lneel2vy4hj24vasvfmn",
  "from": "someone@example.org",
  "to": "support@inbox.example.com",
  "subject": "Re: your invoice",
  "attachments": 1,
  "authenticated": true
}

The payload is a summary — fetch the message by inboundId for its bodies and attachments.

NextDelivery & webhooksStatuses, bounces, suppression and signed webhooks.