Inbound Rules

Filter, route, and block inbound emails with conditional rules.

Inbound rules let you automatically filter, route, and process incoming emails based on sender, subject, headers, and authentication results. They evaluate after Postscale resolves an active alias or accepts a recipient through domain catch-all.

How Rules Work

When an email arrives at a routed recipient, Postscale evaluates rules in priority order:

  1. Alias-specific rules run first (rules tied to the receiving alias)
  2. Domain-wide rules run next (rules with no alias specified)
  3. Matching rules apply in priority order; stop_processing: true ends evaluation
  4. The last effective matching rule's action runs
  5. If no rule matches, the alias default action runs. A direct domain catch-all recipient is stored by default.

Rules with stop_processing: false can match and allow later rules to continue evaluating. When multiple non-stopping rules match, the last matching rule's action wins.

Non-destructive

Domain-wide rules apply to all active accepting aliases and directly to arbitrary recipients when domain catch-all is enabled. Without either route, Postscale rejects creation of an active domain-wide rule.

Creating a Rule

curl -X POST "https://api.postscale.io/v1/domains/{domain_id}/rules" \
  -H "Authorization: Bearer ps_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Block spam domain",
    "conditions": [
      {"field": "sender_domain", "comparator": "equals", "value": "spam.com"}
    ],
    "action": "drop",
    "priority": 10
  }'

Condition Fields

Each condition matches against a part of the incoming email:

FieldWhat it matchesExample
senderFull sender addressspam@bad.com
sender_domainDomain part of sendermarketing.com
subjectSubject lineURGENT, Invoice
headerAny email header (specify header_name)X-Mailer: BulkMailer
spfSPF authentication resultpass, fail, softfail, none
dkimDKIM authentication resultpass, fail, none

Comparators

All comparators are case-insensitive except matches.

ComparatorDescription
equalsExact match
not_equalsNot equal
containsSubstring present
not_containsSubstring absent
starts_withBegins with value
ends_withEnds with value
matchesRegular expression

Actions

ActionWhat happens
dropAccept SMTP, then discard without storing body, headers, raw MIME, or attachments; no forwarding or webhooks
storeStore in DB without forwarding or webhooks
mark_spamFlag as spam, then continue to alias default action
forwardForward to specific addresses (overrides alias)
webhookDeliver to a specific webhook (overrides alias)

Drop rules keep only a minimal routing/audit event and the rule match counter. Use alias-level reject when you want the SMTP transaction to fail instead.

Combining Conditions

Rules support AND/OR logic via the condition_match field:

  • "all" (default): every condition must match (AND)
  • "any": at least one condition must match (OR)

You can add up to 10 conditions per rule.


Examples

Block a Spam Domain

Drop all emails from a known spam domain:

curl -X POST "https://api.postscale.io/v1/domains/{domain_id}/rules" \
  -H "Authorization: Bearer ps_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Block spam.com",
    "conditions": [
      {"field": "sender_domain", "comparator": "equals", "value": "spam.com"}
    ],
    "action": "drop",
    "priority": 10
  }'

Block Emails Failing SPF and DKIM

Drop emails that fail both SPF and DKIM authentication:

curl -X POST "https://api.postscale.io/v1/domains/{domain_id}/rules" \
  -H "Authorization: Bearer ps_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Block unauthenticated senders",
    "conditions": [
      {"field": "spf", "comparator": "not_equals", "value": "pass"},
      {"field": "dkim", "comparator": "not_equals", "value": "pass"}
    ],
    "condition_match": "all",
    "action": "drop",
    "priority": 20
  }'

Route Marketing Emails to a Webhook

Forward emails from a marketing domain to a specific webhook for processing:

curl -X POST "https://api.postscale.io/v1/domains/{domain_id}/rules" \
  -H "Authorization: Bearer ps_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Marketing emails to webhook",
    "conditions": [
      {"field": "sender_domain", "comparator": "equals", "value": "marketing.example.com"}
    ],
    "action": "webhook",
    "action_config": {
      "webhook_id": "your-webhook-uuid"
    },
    "priority": 30
  }'

Forward Urgent Emails to Multiple Addresses

Catch any email with "urgent" or "critical" in the subject and forward to the on-call team:

curl -X POST "https://api.postscale.io/v1/domains/{domain_id}/rules" \
  -H "Authorization: Bearer ps_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Urgent to on-call",
    "conditions": [
      {"field": "subject", "comparator": "contains", "value": "urgent"},
      {"field": "subject", "comparator": "contains", "value": "critical"}
    ],
    "condition_match": "any",
    "action": "forward",
    "action_config": {
      "forward_to": ["oncall@company.com", "alerts@company.com"]
    },
    "priority": 5
  }'

Block Bulk Mailers by Header

Drop emails sent by known bulk mailing software:

curl -X POST "https://api.postscale.io/v1/domains/{domain_id}/rules" \
  -H "Authorization: Bearer ps_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Block bulk mailer",
    "conditions": [
      {
        "field": "header",
        "comparator": "contains",
        "value": "BulkMailer",
        "header_name": "X-Mailer"
      }
    ],
    "action": "drop",
    "priority": 15
  }'

Block Senders with Regex

Use a regex pattern to block multiple spam domains at once:

curl -X POST "https://api.postscale.io/v1/domains/{domain_id}/rules" \
  -H "Authorization: Bearer ps_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Regex block spam domains",
    "conditions": [
      {
        "field": "sender",
        "comparator": "matches",
        "value": ".*@(spam|junk|promo)\\.com
quot; } ], "action": "drop", "priority": 10 }'

Store Newsletters Without Forwarding

Keep newsletter emails in your Postscale inbox without forwarding them:

curl -X POST "https://api.postscale.io/v1/domains/{domain_id}/rules" \
  -H "Authorization: Bearer ps_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Store newsletters",
    "conditions": [
      {"field": "subject", "comparator": "contains", "value": "newsletter"},
      {"field": "header", "comparator": "contains", "value": "list-unsubscribe", "header_name": "List-Unsubscribe"}
    ],
    "condition_match": "any",
    "action": "store",
    "priority": 50
  }'

Alias-Specific Rule

Attach a rule to a specific alias instead of the whole domain:

curl -X POST "https://api.postscale.io/v1/domains/{domain_id}/rules" \
  -H "Authorization: Bearer ps_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "VIP senders only for support@",
    "alias_id": "your-alias-uuid",
    "conditions": [
      {"field": "sender_domain", "comparator": "not_equals", "value": "bigclient.com"}
    ],
    "action": "drop",
    "priority": 1
  }'

Testing Rules

Before emails start flowing, test your rules against sample data to verify they work as expected. The test endpoint evaluates all rules and shows per-condition match details:

curl -X POST "https://api.postscale.io/v1/domains/{domain_id}/rules/test" \
  -H "Authorization: Bearer ps_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "user@spam.com",
    "to": "support@inbound.example.com",
    "subject": "Buy cheap stuff now!!!",
    "spf": "fail",
    "dkim": "fail"
  }'

Response:

{
  "matched_rules": [
    {
      "rule_id": "...",
      "rule_name": "Block spam.com",
      "priority": 10,
      "action": "drop",
      "stop_processing": true,
      "matched": true,
      "conditions": [
        {
          "field": "sender_domain",
          "comparator": "equals",
          "value": "spam.com",
          "matched": true,
          "actual": "spam.com"
        }
      ]
    }
  ],
  "effective_action": "drop",
  "effective_rule_id": "...",
  "would_fall_through": false,
  "recipient_routable": true,
  "route_type": "domain_catch_all",
  "routing_message": "The recipient is accepted by the domain catch-all and domain-wide rules will run.",
  "fallback_action": "store"
}

The tester resolves to exactly as production does. recipient_routable must be true before effective_action is qualified. If conditions match but the address has no active alias and catch-all is disabled, the condition results remain visible while effective_action stays empty. would_fall_through means the recipient is routable but no rule matched, so fallback_action would run.

Dry run

The test endpoint never affects real emails. Use it to debug complex rule sets before they go live.

Managing Rules

List Rules

curl "https://api.postscale.io/v1/domains/{domain_id}/rules" \
  -H "Authorization: Bearer ps_live_your_api_key"

Update a Rule

Partial updates are supported: only include the fields you want to change:

curl -X PUT "https://api.postscale.io/v1/rules/{rule_id}" \
  -H "Authorization: Bearer ps_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "active": false
  }'

Delete a Rule

curl -X DELETE "https://api.postscale.io/v1/rules/{rule_id}" \
  -H "Authorization: Bearer ps_live_your_api_key"

Reorder Rules

Change the evaluation order by setting new priorities:

curl -X PUT "https://api.postscale.io/v1/domains/{domain_id}/rules/reorder" \
  -H "Authorization: Bearer ps_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "rules": [
      {"id": "rule-1-uuid", "priority": 10},
      {"id": "rule-2-uuid", "priority": 20},
      {"id": "rule-3-uuid", "priority": 30}
    ]
  }'

Priority and Stop Processing

  • Priority controls evaluation order. Lower numbers run first (0-1000, default 100).
  • Stop processing (default true) determines whether to stop evaluating further rules after a match. Set to false to allow multiple rules to match: the last matching rule's action wins.
Rule ordering tip

Put your most specific rules at low priorities (e.g., 1-10) and catch-all rules at higher priorities (e.g., 100+). This ensures specific rules always take precedence.

Plan Limits

PlanMax rules per domain
Free5
Starter25
Plus50
Pro100
Scale500

Match Statistics

Every rule tracks how many emails it has matched and when it last matched. Use this to identify rules that are no longer effective or to monitor rule activity via the list endpoint.