anything.solutions
Please log in to access this page.

MRS

Receive mail on a domain and deliver it to your own services.

MRS (Mail Receiving Service) accepts inbound email for a domain you control. Point the domain's MX record at AnythingCloud, and MRS resolves each recipient, checks the sender's authentication, scores spam, and sends the message to the destinations you choose. Sending stays on AMS; a domain can send, receive, both, or neither.

Overview

MRS is built into AnythingCloud and uses the same account, verified domains, Workers, queues, and balance as the rest of the platform. The pieces are:

PieceWhat it is
Inbound domainA receiving hostname under a verified root, such as inbox.example.com. It is separate from an AMS sending domain.
Shared receivermx.anything-cloud.com accepts SMTP for every member domain. Members publish one MX record; there is no per-domain server.
RouteAn exact address such as [email protected] or a catch-all such as *@example.com.
DestinationA verified email mailbox, an ANS topic, an AQS queue, a Worker, an HTTPS webhook, or the built-in store.
Verified emailA mailbox confirmed by its owner. One verification works across every receiving domain on the account.
Spam policyA per-domain switch, threshold, and action. Spam is never billed.

MRS does not provide mailboxes, IMAP, or POP3. It receives a message, optionally stores a short-lived copy for debugging, and hands it to the destinations on the matching routes.

Get started

  1. Verify the root domain under Networking. Its status must be Verified. See Custom domains for the TXT record.
  2. Open MRS and choose Add domain. Select the verified root and enter a label. A subdomain such as inbox.example.com is the safe default; using the apex changes the domain's existing MX and needs extra care.
  3. Publish the MX record from the table below. Use the Cloudflare one-button flow if the root is connected there, or add the record manually at your DNS provider.
  4. Choose Verify. When the MX record resolves to mx.anything-cloud.com, the domain becomes active and starts accepting mail.
  5. Add a route for an exact address or a catch-all, and choose its destination. Send a test message to confirm the route and payload.
PurposeTypeNameValuePriority
Inbound MXMX<hostname>mx.anything-cloud.com10
DMARC (optional)TXT_dmarc.<hostname>v=DMARC1; p=none;—

The MX name is the inbound domain itself, not a subdomain of it. Some DNS providers append the zone name automatically; copy the name and value from the console rather than retyping them. No SPF record is needed to receive mail, and MRS does not modify an existing SPF record.

DNS and Cloudflare

The domain page shows both setup paths together: a Cloudflare card for automatic records and a manual card with the exact MX and optional DMARC records to copy into any DNS provider. A Cloudflare API token lets MRS create the records for you. The token is stored encrypted and is never rendered again; the console shows only the connection name.

Connect Cloudflare

Create a scoped API token in the Cloudflare dashboard with exactly these permissions:

  • Zone:Zone:Read — find the zone for the verified root.
  • Zone:DNS:Edit — create or update the MX record and the optional DMARC record.

Paste the token in MRS and connect it. MRS validates it with GET /client/v4/user/tokens/verify and stores the sealed token. When you apply records for a domain, MRS resolves the zone for the verified root using the longest matching zone suffix and caches that mapping. A token that cannot be verified is rejected before it is saved; the root's zone must be visible to the token when you apply the records.

One-button DNS

If no Cloudflare connection exists, paste the token and choose Connect and create records; MRS validates the token and creates the records in one step. If a connection already exists, choose Create DNS records. MRS lists the existing MX records at the hostname before changing anything.

  1. If an MX record that does not point at MRS already exists and replacement is not confirmed, MRS reports the conflict, shows the existing records, and makes no change.
  2. After you explicitly confirm replacement, MRS removes the other MX records at that name and creates or updates the MRS MX record at priority 10.
  3. If the optional DMARC checkbox is on and no _dmarc.<hostname> record exists, MRS creates v=DMARC1; p=none;. An existing DMARC record is left alone.

Existing mail records are never deleted silently. Confirm replacement only when you intend to move all mail for that hostname to MRS.

Apex domains

At the apex, the MX record controls all mail for the root domain. Replacing it can stop delivery to existing mailboxes and forwarding rules. Use a subdomain such as inbox.example.com unless you deliberately want the apex itself to receive through MRS. MRS will not replace an existing MX record until you confirm the replacement.

Routes and destinations

A route matches one address at an inbound domain and names one destination. Each domain can have exact routes and a catch-all.

Resolution order

MRS tries the exact local part first, then *. Every enabled route at the winning specificity receives a copy, so create one route per destination. A message that matches no route is accepted and counted as received, but no destination receives it; its metadata is still dropped after the retention window. Add a catch-all store route when you want to keep mail that would otherwise go unrouted.

Destination kinds

KindWhat happensDurability
ForwardSends a copy to a verified mailbox through AMS. The original sender becomes the Reply-To address.Queued through the AMS delivery pipeline.
ANS topicPublishes an email.received event with source mrs. The email object is the event data.Durable fan-out to the topic's subscriptions.
AQS queuePublishes the email object as a JSON message to the selected queue.Durable. The recommended path when every message must be retained.
WorkerInvokes the Worker's existing event() handler with the email object.Best effort. Use AQS when delivery must not be lost.
WebhookPOSTs the email object to an HTTPS endpoint with X-MRS-Timestamp, X-MRS-Signature, X-MRS-Message-Id, and X-MRS-Route headers.Single attempt. Use ANS for retries and dead letters.
StoreKeeps message metadata and the parsed body for 30 days.Debugging only. It is not a mailbox and does not accept replies.

Destinations are owned by the same account. An ANS topic, AQS queue, or Worker must already exist before it can be selected. Webhook URLs must use HTTPS and a public address; MRS does not follow redirects and gives the endpoint 10 seconds to respond. Webhook requests are signed with HMAC-SHA256 over the timestamp and the request body.

Worker events

A Worker destination calls the Worker's event() handler. MRS posts {"slug": "...", "payload": {"kind": "event", "source": "mrs", "email": {...}}} to the node's /__cloud_event endpoint. The handler receives that payload object, so the email is the request body's payload.email field, exposed as event.email. There is no separate email() entrypoint.

export default {
  async event(event) {
    if (event.source !== "mrs") return;
    const email = event.email;
    console.log(email.subject, email.envelope.to);
  },
};

Worker invocation is a best-effort HTTP call. A failure is recorded on the delivery but does not reject the SMTP message. Use an AQS destination when the Worker must be able to catch up after downtime.

Email payload

Every destination receives the same normalized email object. It contains envelope addresses, the parsed headers, text and HTML bodies, attachment metadata, authentication results, the spam score, and the route that matched.

{
  "id": "mrs_...",
  "type": "mrs.email",
  "received_at": "2026-11-06T12:00:00Z",
  "envelope": {"from": "[email protected]", "to": "[email protected]"},
  "from": {"address": "[email protected]", "name": "Sender"},
  "to": [{"address": "[email protected]", "name": null}],
  "subject": "Hello",
  "message_id": "<...>",
  "date": "...",
  "headers": {"from": "...", "to": "...", "subject": "..."},
  "text": "...",
  "html": "...",
  "raw_size": 12345,
  "truncated": false,
  "attachments": [
    {
      "filename": "a.pdf",
      "content_type": "application/pdf",
      "size": 1234,
      "content": "JVBERi0xLjQK...",
      "content_available": true
    }
  ],
  "auth": {"spf": "pass", "dkim": "pass", "dmarc": "pass"},
  "spam": {"score": 0.0, "reasons": []},
  "route": {"pattern": "support", "destination": "queue"}
}

Attachment content is included as standard base64 in content when it fits the destination. If a destination is too small, the attachment metadata is kept and the entry is marked content_truncated: true. Large bodies are trimmed to fit the ANS topic's max_message_bytes, 900 KB for AQS, or 500 KB for a Worker event; truncated is set on the email object when that happens.

Attachments

Add a store route when you want message bodies and attachments kept for the 30-day retention window. Stored attachments are listed on the message page in Activity with a download link, and the member API returns their metadata and optional base64 content. Messages without a store route still forward attachment content to destinations when it fits, but nothing is retained after delivery.

The receiver forwards up to 20 attachments, 5 MB per file and 10 MB in total. Larger files keep their filename, content type, and size, and are marked as truncated. Sending attachments through AMS uses the same base64 shape; see the AMS sending API.

Idempotency and delivery records

Each message has one id. ANS and AQS publish with an idempotency key built from the message id and route id, so a message routed to two destinations is delivered once per route. A message with two destinations is still one accepted message for billing. The AQS key is mrs:<message_id>:<route_id>.

Every (message, route) pair gets its own delivery record with a status, attempt count, and last error. ANS, AQS, and webhook delivery run during ingest; a destination failure is recorded and does not reject the SMTP message. Deduplicate in your consumer on email.id; the webhook and Worker paths are single attempts, while ANS and AQS provide the durable, at-least-once path.

Forwarding

Forwarding sends a copy of an accepted message to a mailbox you own. Open Verified emails to add a mailbox, then use Forwarding to create the routes. The flow is deliberately small:

  1. Choose Add email and enter the mailbox.
  2. We email a verification link to that mailbox. Open it and choose Verify email address. The link confirms the mailbox, so it works without signing in first.
  3. Open Forwarding and choose Create forwarding route. Pick an address to forward, the receiving domain, and the verified mailbox. Use Add verified email in the same dialog if the mailbox is not listed yet. A route is created immediately.

Verified emails belong to the account, so one verified mailbox can serve every receiving domain. A pending address cannot be selected until it is confirmed, and an address used by a route cannot be removed until those routes are removed. Verification links expire after 24 hours; the resend action sends a fresh one.

Sending identity

Forwarded mail is sent through AMS from the member's own sending domain. Once a receiving domain has an active AMS sending domain, the console creates forward@<sending domain> automatically. If no sending domain is active, the Forwarding page shows a Setup needed card. With a connected Cloudflare account, Set up sending creates the DKIM, Return-Path SPF, Return-Path MX, and optional DMARC records and checks them immediately. Without a DNS connection, copy the listed records into the provider and choose Finish setup.

A receiving domain does not need its own AMS application. Forwarding uses the AMS delivery queue and does not count as an AMS accepted message, so it does not consume the AMS monthly allowance or appear in AMS metrics.

What the recipient sees

The forwarded message keeps the original subject and body. Its From is forward@<sending domain> so DKIM and DMARC align with a domain the account controls, and its Reply-To is the original sender. An Auto-Submitted: auto-forwarded marker and an X-MRS-Forward-Count header make loops detectable. The original sender, date, subject, and recipient are repeated at the top of the forwarded copy. Attachments are included when they fit the AMS send limits; otherwise the copy notes how many were omitted.

Spam filtering still applies first. Spam is quarantined before it can be forwarded unless the domain's spam policy explicitly tags and delivers it. Forwarding also has a hard safety score cap (10.0 by default) that applies even when the domain filter is off, so a receiving domain cannot be used as an unrestricted outbound relay. Allowlisted senders bypass the cap. A message that returns through forwarding is quarantined as a loop and is not billed.

A forwarding delivery row means the copy entered the AMS delivery queue. AMS performs the final SMTP delivery and its own retries; a later remote bounce is not reflected back on the MRS delivery row.

Spam filtering

Spam filtering is enabled per domain by default. Authentication, DNSBL lookups, and conservative structural checks score every message. The score and its reasons are recorded so a decision can be explained. There is no content keyword blocking in this release.

Filtering strength

Choose a preset in the domain's Spam tab, or enter a custom threshold from 0 to 20. Lower values catch more spam; higher values accept more mail.

PresetThresholdBest for
Lenient7.0Domains that must not miss legitimate mail
Balanced5.0The default for most domains
Strict3.0Domains that receive a lot of unwanted mail

What is scored

SignalScore
SPF fail+2.5
SPF softfail+1.0
DKIM fail (a checked, invalid signature)+2.0
DMARC fail+2.0
Sender address does not match the authenticated sender+1.5
DMARC fails and the sender's domain quarantines unauthenticated mail+1.0 additional
DMARC fails and the sender's domain rejects unauthenticated mail+3.0 additional
DNSBL hit (Spamhaus ZEN or SpamCop)+3.0 each, capped at +6
Missing Message-ID+0.5
Missing Date+0.5
Mostly uppercase subject (at least 8 characters)+0.8
More than 10 URLs in the text+1.0
HTML with a form or password input+1.5
Reply-To domain differs from the From domain+0.5
From display name contains an address on another domain+1.0
HTML contains a javascript: or data:text/html link+1.0
HTML has no text and at least one image+0.5
More than 8 Received headers+0.5

A message with no DKIM signature is not treated as a failure. A signature that cannot be checked because of a DNS or temporary lookup problem is also not scored. An unknown DNSBL result never blocks mail. DNS lookups have short timeouts, so a slow resolver does not hold up the SMTP transaction.

MRS also compares the From address with the authenticated sender. A different envelope domain is normal for an email provider when DKIM or DMARC aligns the From identity, so it is left alone. A sender domain that rejects unauthenticated mail adds a strong signal when DMARC fails; a quarantine policy adds a smaller one. The display-name and Reply-To checks stay in place.

Sender rules

Allow or block a specific sender address ([email protected]) or a whole domain (example.com). A domain rule also covers its subdomains. Each domain can have up to 100 rules.

  • Allow: skip the spam decision and route the message normally. The message is billable and its reasons include Sender is allowlisted.
  • Block: always treat the sender as spam, even when the filter is off. Blocked mail is quarantined unless the domain action is Reject; it is never tagged and delivered. It is not billed and its reasons include Sender is blocklisted.

Matching tries the exact address first, then the exact domain, then the longest subdomain suffix. At the same level, a block rule wins over an allow rule.

Threshold and actions

A message at or above the threshold is spam. The domain's action decides what happens next:

  • Quarantine (default): accept at SMTP, store the metadata and score, count the message as spam, do not route it, and do not bill it.
  • Tag: route normally and add X-MRS-Spam: yes and X-MRS-Spam-Score headers for the destination.
  • Reject: return 550 5.7.1 to the sending server and record the rejection.
  • Filter off: route every message and record the score, but treat the message as non-spam. This is an explicit choice and the message is billable. Sender block rules still apply.

Quarantined and rejected spam never counts toward the free allowance or the paid count. Raising the threshold accepts more mail as legitimate; lowering it catches more as spam. Use the tag action first when tuning a domain. The Spam tab and the Metrics page show the most common spam reasons for the selected window.

Spam reporting

This release has no spam-report action or report table. When managed organization inboxes ship, reports will attach to the retained message id, authentication result, and score, and will feed sender reputation. The current message record and per-domain sender rules are the extension point.

Metrics

The MRS Metrics page and each domain's Metrics tab show daily counts for the selected period, with per-domain and per-day breakdowns:

CounterMeaning
receivedMessages evaluated by MRS for the account or domain.
acceptedNon-spam messages. Each message counts once, no matter how many destinations it reaches.
spamMessages classified as spam. Each message counts once.
routedSuccessful destination deliveries. Two destinations count twice.
failedDestination deliveries that did not complete.

SPF, DKIM, and DMARC pass rates are reported beside the message counters. A message counts once in received and once in exactly one of accepted or spam. Message metadata is kept for 30 days; daily metrics are kept for 400 days so a full billing period is always available.

Billing

Email receiving is billed from the Cloud account balance and appears as Email receiving in the monthly service breakdown. The first 10,000 non-spam messages in a calendar month are free. Above that, every non-spam message in that month is billed at $0.09 per 1,000, applied to the whole month, not only the messages over the allowance.

ItemValue
Free allowance10,000 non-spam messages per account per calendar month
Rate above the allowance$0.09 per 1,000 non-spam messages
Charged countAll non-spam messages in the month once the allowance is exceeded
SpamNever counted, never charged
Deposit requirementNone; any active Cloud account can use the allowance

A message counts once when it is accepted as non-spam, regardless of how many routes receive it. Delivery failures do not change the accepted count. Examples for one month:

  • 9,999 non-spam messages: $0.00.
  • 10,001 non-spam messages: 10,001 × $0.00009 = $0.90.
  • 100,000 non-spam messages: 100,000 × $0.00009 = $9.00.
  • 100,000 non-spam plus 50,000 spam: still $9.00.

The console shows the current month's usage on the MRS overview. Rates and the monthly total are also on Billing and metrics and Cloud → Billing.

Limits

LimitValue
Raw message size25 MiB (26,214,400 bytes)
Recipients per message10
Inbound domains10 per account
Routes20 per domain
Sender rules100 per domain
Forwarding addresses20 per account; verification links expire after 24 hours
Forwarded messages2,000 per account in a rolling 24 hours; hard safety cap at spam score 10.0
Forwarding attachmentsThe AMS send limits: 5 files, 400 KB each, 600 KB total
ANS payloadThe selected topic's max_message_bytes; 256 KiB by default
AQS payload900 KB
Worker event payload500 KB
Attachments per message20
Attachment size5 MB each, 10 MB total forwarded or stored
Message metadata30 days
Daily metrics400 days

The receiver enforces the raw size and recipient count before reading the whole message. A message over either limit is rejected at SMTP. Payload limits apply after parsing and trimming; the email object's truncated flag says whether the body was shortened.

Internal API contract

These endpoints are the contract between the MRS SMTP receiver and the control plane. They are not part of the member API and should not be called from applications. The receiver authenticates with a mrs_worker_ bearer token created from Admin → Cloud → Email Receiving Worker, which is available to administrators. Tokens are hashed at rest, limited to 10 active tokens, and revocable.

Method and pathPurpose
GET /internal/mrs/healthPublic health check. Returns {"ok": true}.
POST /internal/mrs/recipientsResolve addresses and return the domain's spam policy. No route details or secrets.
POST /internal/mrs/messagesIngest one normalized message event and return the SMTP decision and delivery results.
POST /internal/mrs/eventsBatch variant for future senders, up to 25 events. The current receiver sends one event per recipient.

Recipient lookup

The receiver sends the envelope recipients before it reads the message, up to 20 addresses per lookup. The response says which addresses are deliverable and carries the domain's spam settings. Results are cached for 30 to 60 seconds, so a route added just after a lookup can take up to a minute to accept mail.

POST /internal/mrs/recipients
Authorization: Bearer mrs_worker_...
Content-Type: application/json

{"addresses": ["[email protected]", "[email protected]"]}

An unknown or inactive domain or route is rejected at SMTP with 550 5.1.1. A paused domain or an account over its limit is rejected with 451 so the sender retries later. If the control plane is unavailable, the receiver writes the event to a bounded local spool and retries with backoff; a full spool returns a temporary 452.

Message ingest

The receiver parses MIME, evaluates SPF, DKIM, DMARC, DNSBL, and the heuristics, then posts one normalized event per recipient. The event uses the same email object shown under Email payload.

{
  "id": "mrs_...",
  "type": "mrs.email",
  "envelope": {"from": "[email protected]", "to": "[email protected]"},
  "from": {"address": "[email protected]", "name": "Sender"},
  "to": [{"address": "[email protected]", "name": null}],
  "subject": "Hello",
  "message_id": "<...>",
  "auth": {"spf": "pass", "dkim": "pass", "dmarc": "pass"},
  "spam": {"score": 0.0, "reasons": []}
}

The response tells the receiver whether to accept, quarantine-accept, or reject the message, and includes the SMTP response for a rejection:

{
  "accept": true,
  "message_id": "mrs_...",
  "status": "routed",
  "deliveries": [
    {"route_id": 12, "destination_kind": "queue", "status": "delivered"}
  ],
  "smtp_code": 250,
  "smtp_message": "2.0.0 Message accepted"
}

Ingest is idempotent on the message id: a repeated post returns the original decision instead of delivering again. A message that is accepted for one recipient does not roll back the other recipients; the receiver splits a multi-recipient message into one event per recipient so each has one owner, one route set, and one billing unit.

Member API

Manage receiving domains, routes, spam settings, sender allow/block rules, Cloudflare connections, messages, and metrics with a personal API key. The full endpoint list is in the API reference.

curl -X POST https://anything.solutions/api/v1/mrs/domains \
  -H "Authorization: Bearer $ANYTHING_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"root_id": 1, "label": "inbox"}'

Add a route with destination_kind and destination_config:

{
  "pattern": "support",
  "destination_kind": "queue",
  "destination_config": {"queue_id": 12},
  "enabled": true,
  "priority": 0
}

GET /api/v1/mrs/messages/{id}?include_body=1 returns the stored text, HTML, and base64 attachment content when available. GET /api/v1/mrs/messages/{id}/attachments/{attachment_id} downloads one file.

Roadmap

  • Managed organization inbox. A later destination adapter will add a hosted inbox on the same route and message model.
  • Multi-region. The control-plane contract is region-neutral. The first release runs one receiver on the existing inbound host.