Skip to main content

Mail Rules

Complete guide to configuring Mail Rules for automated email processing.

Mail rules define how inbound email is processed after a Mailbox fetches it. Rules are evaluated in priority order (lower number = higher priority). Each mailbox can have multiple rules; rules can be enabled or disabled without deleting them.

Mail rules list

Matching behaviour: every active valid rule whose when criteria match is evaluated in priority order (lower number first). By default all matching rules run. Set "stop_processing_on_success": true on a rule to halt later rules when that rule’s actions succeed (or partially succeed). Failed / all-skipped rules do not stop the chain.

Simulate mailbox (dry-run)

From the Mail Rules list, select a mailbox in the filter, then Simulate mailbox — this dry-runs all active valid rules for that mailbox (same matching behaviour as live processing).

Simulate mailbox form

From Mail Rules → edit a rule → Simulate mailbox:

  1. Choose the mailbox and a since date (tenant calendar day).
  2. Leave Include already-read messages on to replay mail that another system already marked read.
  3. Run dry-run to see which messages match which rules and what actions would run — without ingesting pictures, sending EDI, notifying, or changing read/move state.
  4. Matched messages are listed first and highlighted. For each planned search_pictures_and_send_edi action, the report includes a gallery preview: picture count that would be sent, destination (after rewrite), terminal names, and case dates — still dry-run (no send). For each planned ingest_images action, the report shows how many attachments would be ingested, the normalize/rescale policy (EXIF + fit ≤1280×760 / ≤760×1280 JPEG), and when bytes can be fetched, per-file original dimensions plus whether each would be downscaled. Video attachments (MP4/MOV/WebM) are listed as video — stored as-is (no rescale probe).
  5. Optionally (editor only) limit evaluation to the current editor JSON only.

Simulate mailbox dry-run results

Use this to verify multi-rule priority setups (e.g. ingest vs EDI vs noreply) against real inbox traffic. Summary chips include Pictures that would send (EDI gallery hits) and Pictures that would ingest (eligible attachments across planned ingest actions).

After a real poll, open the same style of report for a finished run under Processing state → View results.

Playback (re-run processing for real) is not included in this release; remount messages as unread and force-poll if you need live reprocessing.

What are Mail Rules?

When an email matches a rule's conditions, the system executes actions such as:

  • Extracting images from attachments and adding them to your picture database
  • Parsing spreadsheet files (CSV/XLSX) and triggering EDI destinations
  • Searching for pictures by container code and sending them via EDI
  • Sending processing reports via email

Rule structure

Every rule has three main parts:

  1. When — Conditions that must be met for the rule to trigger
  2. Extract (optional) — Variables to extract from the email (e.g. container codes from subject)
  3. Then — Actions to execute when conditions match

Optional top-level flag:

  • stop_processing_on_success — when true, if this rule’s actions succeed (or partially succeed), later matching rules are not executed. Use on a high-priority ingest rule so depot EDI rules do not also run on the same photo email.
{
"version": 1,
"stop_processing_on_success": true,
"when": {
"type": "sender_email",
"value": "operations@example.com"
},
"extract": {
"variables": {
"container_code": {
"from": "subject",
"regex": "([A-Z]{4}[0-9]{7})",
"group": 1
}
}
},
"then": [
{
"action": "ingest_images",
"config": {
"target": {
"container_code": "{container_code}",
"terminal": "MAIN"
}
}
}
]
}

Rule structure (detail)

The minimal shape without the stop flag:## Conditions (When)

Basic conditions

Sender email — Match a specific sender:

{ "type": "sender_email", "value": "operations@example.com" }

Sender domain — Match any address in a domain:

{ "type": "sender_domain", "value": "@example.com" }

Subject contains — Case-insensitive substring:

{ "type": "subject_contains", "value": "Container Report" }

Subject regex — Regular expression on subject:

{ "type": "subject_regex", "regex": "^(BEANR0F|NLRTM08|NLRTM10)$" }

Body contains:

{ "type": "body_contains", "value": "urgent" }

Has attachment type:

{ "type": "has_attachment_type", "value": ["image/jpeg", "image/png"] }

Field comparison — Operators: eq, ne, contains, matches, in, gt, gte, lt, lte:

{ "field": "subject", "op": "contains", "value": "CAIU" }

Combining conditions

All (AND):

{
"all": [
{ "type": "sender_domain", "value": "@example.com" },
{ "type": "subject_contains", "value": "Container" }
]
}

Any (OR):

{
"any": [
{ "type": "subject_contains", "value": "BEANR0F" },
{ "type": "subject_contains", "value": "NLRTM08" }
]
}

Not (negation):

{
"not": { "type": "sender_domain", "value": "@spam.com" }
}

Variable extraction

Extract values from email fields to use in actions:

{
"extract": {
"variables": {
"container_code": {
"from": "subject",
"regex": "([A-Z]{4}[0-9]{7})",
"group": 1,
"required": true
},
"terminal": {
"from": "subject",
"regex": "Terminal: ([A-Z]+)",
"group": 1,
"default": "MAIN"
}
}
}
}
FieldDescription
fromField to extract from (subject, body, sender, etc.)
regexPattern with capture groups
groupCapture group index (1 = first group)
requiredRule fails if variable cannot be extracted
defaultValue if extraction fails

Actions (Then)

1. Ingest images

Extract image and video attachments and add them to the picture database:

{
"action": "ingest_images",
"config": {
"target": {
"container_code": "{container_code}",
"terminal": "MAIN",
"case_date": "{case_date}",
"picture_source": "Mailbox",
"picture_creator": "Mailbox: Operations"
},
"attachment_filter": {
"content_types": ["image/", "video/"],
"max_size_bytes": 10485760
},
"processing": {
"max_resolution": 1280,
"jpeg_quality": 90
}
}
}

Supported media types

The same file-type policy applies everywhere media enters Checker (manual upload, integration API, mailbox ingest):

KindFormatsHandling
PicturesJPEG, PNG, GIFNormalized to JPEG (EXIF orientation + downscale)
VideosMP4, MOV, WebMStored as-is — no rescaling, max 10 MB, never scanned by OCR

Attachments labelled application/octet-stream (common from Outlook) are identified by file content, so a real JPEG or MP4 is still accepted. Any other file type (PDF, WebP, HEIC, office documents, …) is rejected. Video attachments count toward the ingest totals and appear in the dry-run report marked as video — stored as-is.

Container OCR — rule key ocr_enabled

Set ocr_enabled to true on the ingest_images action to enable container OCR when the container number is missing or has an invalid ISO check digit. Default is false (container must come from the rule extract block).

In rule JSON: "ocr_enabled": true (search this help site for Container OCR or ocr enabled — do not paste JSON into the search box).

Use ocr_enabled: true for picture-dropbox rules that accept emails without a container in the subject — OCR Scenario B discovers the container from photo attachments. Use ocr_enabled: false (or omit the key) when the container is always taken from the subject.

Pair with fail_if_no_attachments: true so messages with no eligible photos are marked failed instead of skipped.

Config keyDefaultDescription
ocr_enabledfalseEnable container OCR Scenarios A1/A2/B
fail_if_no_attachmentsfalseWhen true, no eligible attachments → failed (not skipped)
split_case_per_messagefalseWhen true, each email gets its own gallery case card (deterministic upload session id per message). When omitted/false, attachments merge into the terminal/container/day case as before. [CR-20260715]

OCR scan limits (85% minimum confidence, 25 attachments max per message) are fixed in the backend — not configurable in rule JSON.

OCR credentials and endpoint URL are configured on the backend server only (deploy/install env) — not in rule JSON or tenant-admin UI.

ScenarioStated + valid check digitStated + bad digitNo stated
OCR calls0Up to 25 attachmentsUp to 25 attachments
Container usedStatedOCR result (or stated if OCR unavailable)OCR result

See Mailbox ingest FAQ for Scenarios A1/A2/B, photo limits, and ops/sender emails.

Minimal OCR rule fragment (container discovered from photos — Scenario B):

"ocr_enabled": true,
"fail_if_no_attachments": true

Standard rule with OCR + ops reporting:

Configure report_recipients on the Mailbox (not in rule JSON) for branded ops emails with View case link.

{
"extract": {
"variables": {
"container_code": {
"from": "subject",
"regex": "([A-Z]{4}[0-9]{7})",
"group": 1,
"normalize_container_code": true
}
}
},
"then": [
{
"action": "ingest_images",
"config": {
"ocr_enabled": true,
"fail_if_no_attachments": true,
"target": { "container_code": "{container_code}", "terminal": "MAIN" }
}
},
{
"action": "send_notification",
"config": {
"to": "{sender_email}",
"send_when_picture_count": "nonzero"
}
}
]
}

send_notification uses a simple branded template by default (simple_body: true). Set "simple_body": false only if you need a custom subject/body.

2. Parse spreadsheet

Parse CSV or XLSX attachments and process each row via Code mappings:

{
"action": "parse_spreadsheet",
"config": {
"attachment_filter": {
"content_types": ["application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"],
"filename_pattern": "*.xlsx"
},
"parser": {
"type": "xlsx",
"sheet": 0,
"skip_rows": 0,
"max_rows": 0
},
"column_map": {
"customer": "client_name",
"containerno": "container_code"
}
}
}

Key configuration notes:

  • parser.typecsv or xlsx
  • column_map — Maps spreadsheet columns to internal fields
  • use_code_mappings: true (default) — EDI destination and days_back come from each code mapping
  • fallback_enabled — Use tenant fallback destination when no mapping matches
  • use_code_mappings: false — Each row must include days_back (1–365)
  • reporting — Optional summary email with CSV/JSONL attachments after all chunks finish
  • Legacy rule fields days_back and send_when_no_pictures on parse_spreadsheet are ignored — use code mappings instead

Batch report email (rule editor assistant)

When the rule JSON includes a parse_spreadsheet action, the rule editor shows a Batch report email panel above the JSON. Use it to enable a completion email, set To/CC/subject (with {{mailbox_name}}, {{attachment_filename}}, {{rows_ok}}, … placeholders), and choose CSV / JSONL attachments. Changes write back into the rule’s reporting block automatically — you do not need to edit raw JSON for the common fields.

3. Search pictures and send EDI

Search by container code and send via EDI (useful when email has no attachments):

{
"action": "search_pictures_and_send_edi",
"config": {
"container_code": "{container_code}",
"days_back": 30,
"terminals": ["MAIN", "GATE"],
"destination": "EOS"
}
}

When the subject uses a code that is not the EDI DEST_NAME in Tenant Admin, map it with destination_rewrite (alias destination_aliases also accepted):

{
"action": "search_pictures_and_send_edi",
"config": {
"container_code": "{container_code}",
"destination": "{edi_dest}",
"destination_rewrite": {
"BEANR0F": "FLORENS"
},
"days_back": 30,
"lookup_all_terminals": true,
"exclude_terminals": ["POST-REPAIR"]
}
}

Rule validation and runtime both apply the rewrite (case-insensitive keys) before checking/sending to EDI.

4. Send report

Email a processing report:

{
"action": "send_report",
"config": {
"to": "operations@example.com",
"subject": "Processed: {container_code}",
"include_logs": true
}
}

Complete examples

Example 1: Extract images from specific sender

When operations@example.com sends an email whose subject mentions “Container” and includes a container number, Checker saves the attached photos to that container in the gallery.

{
"when": {
"all": [
{ "type": "sender_email", "value": "operations@example.com" },
{ "type": "subject_contains", "value": "Container" }
]
},
"extract": {
"variables": {
"container_code": {
"from": "subject",
"regex": "([A-Z]{4}[0-9]{7})",
"group": 1,
"required": true
}
}
},
"then": [
{
"action": "ingest_images",
"config": {
"target": {
"container_code": "{container_code}",
"terminal": "MAIN",
"case_date": "2026-01-20",
"picture_source": "Mailbox",
"picture_creator": "Mailbox: Operations"
},
"attachment_filter": {
"content_types": ["image/jpeg", "image/png"]
}
}
}
]
}

Example 2: Process spreadsheet from company domain

When anyone at @example.com sends an Excel file (.xlsx), Checker reads each row (customer + container), looks up the customer in your code mappings, and sends the matching pictures to the configured EDI destination — no photos are attached to the email itself.

{
"when": {
"all": [
{ "type": "sender_domain", "value": "@example.com" },
{
"type": "has_attachment_type",
"value": ["application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"]
}
]
},
"then": [
{
"action": "parse_spreadsheet",
"config": {
"parser": { "type": "xlsx", "sheet": 0 },
"column_map": {
"customer": "client_name",
"containerno": "container_code"
}
}
}
]
}

Example 3: EDI for specific subject patterns

When selected depot senders email with a terminal code and container number in the subject (but no photo attachments), Checker finds pictures already stored for that container and sends them to the EOS EDI destination.

{
"when": {
"all": [
{
"any": [
{ "type": "sender_email", "value": "operations@depot1.example.com" },
{ "type": "sender_email", "value": "notifications@depot2.example.com" }
]
},
{ "type": "subject_regex", "regex": "^(BEANR0F|NLRTM08|NLRTM10)$" },
{ "type": "subject_contains", "value": "CAIU" }
]
},
"extract": {
"variables": {
"container_code": {
"from": "subject",
"regex": "([A-Z]{4}[0-9]{7})",
"group": 1,
"required": true
}
}
},
"then": [
{
"action": "search_pictures_and_send_edi",
"config": {
"container_code": "{container_code}",
"days_back": 30,
"terminals": ["*"],
"destination": "EOS"
}
}
]
}

Best practices

  • Use specific conditions — Combine sender and subject checks when possible
  • Validate before saving — Use the Validate button in the Admin UI
  • Set priorities — Specific rules: lower numbers; general rules: higher numbers
  • Use variable extraction — Reuse rules across senders
  • Start simple — Add complexity incrementally
  • Monitor Processing state
  • Use descriptive rule names

Troubleshooting

Rule not triggering?

  • Check the rule is active (is_active: true)
  • Verify conditions match the test email exactly
  • Check rule priority — a higher-priority rule may match first
  • Review Processing state for other rules on the same message

Variable extraction failing?

  • Test regex with an online regex tester
  • Ensure capture group numbering is correct (group: 1 = first parentheses)
  • Set "required": false and provide a "default" for optional variables

Actions not executing?

  • Check Processing state for error messages
  • Verify required fields (container_code, terminal, etc.)
  • Ensure Code mappings exist for parse_spreadsheet
  • Verify EDI destinations are configured for search_pictures_and_send_edi

See also: Mailboxes, Processing state, Code mappings