Mail Rule Reference
Private beta
Email Security is in private beta. It is not generally available, and
access is enabled per organization — if the ext-email-security extension
is not in your catalog, this product is not turned on for you yet.
While it is in beta, expect the surface described here to move: commands,
fields and event shapes may change between releases, and they may change in
ways that are not backwards compatible. Pin a CLI version if you script
against it, and re-read this page after upgrading.
Talk to us before relying on it in production.
Use this reference with Mail Rules. It describes
dr-mail rules and the Message Data Model (MDM) they read. Platform D&R rules on
EMAIL_* events and cloud posture rules
have different wrappers and validation rules.
Paths and phases
| Context |
Example path |
dr-mail, either phase |
sender/email/domain/root |
dr-mail, post_verdict only |
verdict/verdict |
dr-general on EMAIL_MESSAGE |
event/sender/email/domain/root |
dr-general on EMAIL_VERDICT |
event/revision/verdict |
Inside scope with path: links |
href_url/domain/root |
The MDM is the root of a mail rule. Do not add mdm/ or event/. The Hive
rejects mdm/ paths and pre-verdict reads of verdict. Use scope to iterate
arrays of objects; dr-mail paths containing ? or * are rejected.
Operators
The complete dr-mail operator allowlist is:
and, or, scope, exists, is, contains, starts with, ends with,
matches, is greater than, is lower than, is older than, cidr,
string distance, lookup.
Use not: true on a condition to negate it; is not is not an operator.
and and or take rules; scope takes a single rule. See the platform's
Detection Operators for operand syntax;
only the operators listed above are available in dr-mail.
lookup accepts only hive://lookup/<name> and reads the organization's lookup
Hive. Sensor-variable values ([[name]]) and template values ({{ … }}) are
rejected inside detect. Response templates are separate: the
post-verdict example
uses {{ .msg_uuid }} to bind an action to its message.
Limits
| Per-rule limit |
Maximum |
| Record name (no prefix is reserved) |
64 bytes |
Human-readable name |
256 bytes |
Serialized detect JSON |
8 KiB |
| Detection nesting |
32 levels |
scope operators |
2; nesting a scope inside another is rejected |
lookup operators |
4 |
| Compiled regex instructions, one expression |
1,000 |
| Compiled regex instructions, all expressions |
5,000 |
respond actions |
16 |
Serialized respond JSON |
8 KiB |
Regex limits measure compiled instructions, not pattern characters. Validate
rules after changing regexes. Both name and fp_notes must be non-empty.
Scoring classes require weight from 1 to 100; graymail records must omit it.
Choosing fields
| Question |
Field or array scope |
| Who sent it? |
sender/email/local, sender/email/domain/root, sender/display_name |
| Where would a reply go? |
headers/reply_to (array of addresses), sender/reply_to_mismatch |
| Did authentication fail? |
auth/spf/result, auth/dmarc/result; scope auth/dkim for individual signatures |
| What does the newest reply say? |
body/current_thread/text or body/current_thread/visible_text |
| Does one link disguise its destination? |
Scope links; compare href_url/domain/root and mismatched |
| Is a link's domain new or suspicious? |
Scope enrichments/link_features; read domain, domain_age_days, popularity_bucket |
| Does an attachment match an IOC? |
Scope attachments; read sha256 or another hash |
| What did attachment analysis actually inspect? |
Scope attachments; inspect explode/scanners before interpreting scanner-specific results |
| Is this a known sender? |
enrichments/sender_profile/prevalence (none, new, rare, common) |
| Is the sender impersonating an organization? |
enrichments/lookalike/org_domain_distance, enrichments/lookalike/vip_hit |
| What happened after a link was fetched? |
enrichments/detonation; see Link detonation |
| Was parsing or analysis incomplete? |
_meta/truncations, _meta/errors, _meta/explode_timeout, body/truncated |
scope processes objects, not scalar strings. A scalar equality test on a whole
string array is not a membership test. For wildcard traversal of string arrays,
use a platform D&R rule on the emitted event, such as
event/headers/domains/?; that wildcard path is not accepted in dr-mail.
An email address is decomposed into local and domain; sender/email is an
object, not a string containing user@example.com. A domain's raw is the full
host, while root is its registrable domain. Use an exact comparison on root
for an ownership test; a substring search can also match example.com.evil.test.
An IP literal has no registrable root domain.
links and enrichments/link_features are separate arrays. A scope on one does
not bind an element of the other. Match related features in a single
link_features scope using its own domain field.
Presence and missing evidence
Optional fields are omitted when empty; pointer fields are omitted when unset.
A pointer to a number can preserve zero, such as domain age zero or an exact
lookalike distance of zero. Many boolean fields omit false, so op: is with
value: false is not a general test for a negative result. A missing enrichment
can mean that the work never ran or could not finish.
For example, this condition requires a measured sender-domain age:
op: and
rules:
- op: exists
path: enrichments/sender_domain/age_days
- op: is lower than
path: enrichments/sender_domain/age_days
value: 7
A presence check distinguishes missing data from a measured zero. It does not
turn an omitted boolean into proof of a negative result. Use the parent result
and its scanner or completion indicators when that distinction matters.
Profiles and external enrichments are available only when the pipeline stamps
them. Detonation arrives after the first verdict. A rule referencing it will not
match during the initial pass. The backtest
does not reconstruct the original enrichment stamps.
Message fields
The tables below describe the JSON objects reachable from an MDM. Each field
name is relative to the object in that table, not a complete detection path.
Follow the linked object types to build a path; use scope for arrays of objects.
For example, MDM → sender → email → domain → root becomes
sender/email/domain/root.
Presence describes JSON serialization, not whether collection succeeded:
- Always: emitted whenever its containing object exists; may still be empty.
- Non-empty: omitted for an empty string/list, zero number, or false boolean.
- When set: optional object or pointer; a set numeric pointer can contain zero.
Timestamps are RFC 3339 strings. direction is inbound, outbound, or
internal; provider is m365 or gworkspace. The verdict object is available
only after scoring. Recursive attachment children and attached messages remain
subject to parser and analysis depth limits.
MDM
Mailbox
| Field |
Type |
Presence |
id |
string |
Non-empty |
address |
string |
Always |
display_name |
string |
Non-empty |
External
| Field |
Type |
Presence |
provider_message_id |
string |
Always |
thread_id |
string |
Non-empty |
folder |
string |
Non-empty |
spam_folder |
boolean |
Non-empty |
Timestamps
| Field |
Type |
Presence |
sent |
timestamp |
When set |
received |
timestamp |
Always |
ingested |
timestamp |
Always |
| Field |
Type |
Presence |
from |
Address |
Always |
reply_to |
array of Address |
Non-empty |
return_path |
Address |
When set |
null_return_path |
boolean |
Non-empty |
message_id |
string |
Non-empty |
in_reply_to |
string |
Non-empty |
references |
array of string |
Non-empty |
mailer |
string |
Non-empty |
delivered_to |
string |
Non-empty |
x_originating_ip |
string |
Non-empty |
all |
array of Header |
Non-empty |
domains |
array of string |
Non-empty |
ips |
array of string |
Non-empty |
Address
| Field |
Type |
Presence |
display_name |
string |
Non-empty |
email |
EmailAddress |
Always |
EmailAddress
| Field |
Type |
Presence |
local |
string |
Non-empty |
domain |
DomainInfo |
Always |
DomainInfo
| Field |
Type |
Presence |
raw |
string |
Non-empty |
root |
string |
Non-empty |
sld |
string |
Non-empty |
tld |
string |
Non-empty |
subdomain |
string |
Non-empty |
punycode |
string |
Non-empty |
is_idn |
boolean |
Non-empty |
| Field |
Type |
Presence |
name |
string |
Always |
value |
string |
Always |
Sender
| Field |
Type |
Presence |
display_name |
string |
Non-empty |
email |
EmailAddress |
When set |
reply_to_mismatch |
boolean |
Non-empty |
display_name_email |
string |
Non-empty |
free_mail |
boolean |
Non-empty |
disposable |
boolean |
Non-empty |
Recipients
| Field |
Type |
Presence |
to |
array of Address |
Non-empty |
cc |
array of Address |
Non-empty |
bcc |
array of Address |
Non-empty |
count |
integer |
Non-empty |
undisclosed |
boolean |
Non-empty |
Body
| Field |
Type |
Presence |
html |
HTMLBody |
When set |
plain |
PlainBody |
When set |
current_thread |
ThreadSegment |
When set |
previous_threads |
array of PreviousThread |
Non-empty |
ips |
array of string |
Non-empty |
has_remote_images |
boolean |
Non-empty |
hidden_text_present |
boolean |
Non-empty |
language |
string |
Non-empty |
truncated |
boolean |
Non-empty |
HTMLBody
| Field |
Type |
Presence |
raw |
string |
Non-empty |
inner_text |
string |
Non-empty |
display_text |
string |
Non-empty |
charset |
string |
Non-empty |
PlainBody
| Field |
Type |
Presence |
raw |
string |
Non-empty |
ThreadSegment
| Field |
Type |
Presence |
text |
string |
Non-empty |
renderings |
array of ThreadRendering |
Non-empty |
visible_text |
string |
Non-empty |
links |
array of Link object |
Non-empty |
ThreadRendering
| Field |
Type |
Presence |
kind |
string |
Always |
text |
string |
Non-empty |
links |
array of Link object |
Non-empty |
Link
| Field |
Type |
Presence |
href_url |
URLInfo |
Always |
display_text |
string |
Non-empty |
display_url |
string |
Non-empty |
mismatched |
boolean |
Non-empty |
visible |
boolean |
Non-empty |
source |
string |
Non-empty |
from_form |
boolean |
Non-empty |
form_password_input |
boolean |
Non-empty |
rewritten_by |
string |
Non-empty |
rewritten_url |
string |
Non-empty |
redirects_resolved |
array of string |
Non-empty |
URLInfo
| Field |
Type |
Presence |
raw |
string |
Non-empty |
scheme |
string |
Non-empty |
domain |
DomainInfo |
Always |
path |
string |
Non-empty |
query |
string |
Non-empty |
fragment |
string |
Non-empty |
is_ip |
boolean |
Non-empty |
port |
integer |
Non-empty |
PreviousThread
| Field |
Type |
Presence |
sender |
string |
Non-empty |
ts |
timestamp |
When set |
text_excerpt |
string |
Non-empty |
Attachment
| Field |
Type |
Presence |
file_name |
string |
Non-empty |
file_extension |
string |
Non-empty |
content_type |
string |
Non-empty |
content_disposition |
string |
Non-empty |
content_id |
string |
Non-empty |
size |
integer |
Non-empty |
md5 |
string |
Non-empty |
sha1 |
string |
Non-empty |
sha256 |
string |
Non-empty |
tlsh |
string |
Non-empty |
magic_type |
string |
Non-empty |
is_inline |
boolean |
Non-empty |
explode |
Explode |
When set |
Explode
| Field |
Type |
Presence |
depth |
integer |
Non-empty |
children |
array of Attachment |
Non-empty |
message |
MDM |
When set |
vba |
VBAInfo |
When set |
qr |
array of QRCode |
Non-empty |
ocr_excerpt |
string |
Non-empty |
yara_matches |
array of string |
Non-empty |
archive |
ArchiveInfo |
When set |
flavors |
array of string |
Non-empty |
scanners |
array of string |
Non-empty |
file_count |
integer |
Non-empty |
truncated |
boolean |
Non-empty |
truncation_reasons |
array of string |
Non-empty |
VBAInfo
| Field |
Type |
Presence |
auto_exec |
array of string |
Non-empty |
suspicious |
array of string |
Non-empty |
hex_strings |
array of string |
Non-empty |
QRCode
| Field |
Type |
Presence |
url |
string |
Non-empty |
ArchiveInfo
| Field |
Type |
Presence |
encrypted |
boolean |
Non-empty |
file_count |
integer |
Non-empty |
max_depth_hit |
boolean |
Non-empty |
Auth
SPFResult
| Field |
Type |
Presence |
result |
string |
Non-empty |
domain |
string |
Non-empty |
DKIMResult
| Field |
Type |
Presence |
result |
string |
Non-empty |
domain |
string |
Non-empty |
selector |
string |
Non-empty |
DMARCResult
| Field |
Type |
Presence |
result |
string |
Non-empty |
policy |
string |
Non-empty |
alignment |
boolean |
Non-empty |
ARCResult
| Field |
Type |
Presence |
result |
string |
Non-empty |
CompAuthResult
| Field |
Type |
Presence |
result |
string |
Non-empty |
reason |
string |
Non-empty |
Hop
| Field |
Type |
Presence |
by |
string |
Non-empty |
from |
string |
Non-empty |
ip |
string |
Non-empty |
protocol |
string |
Non-empty |
ts |
timestamp |
When set |
delay_s |
integer |
Non-empty |
Enrichments
SenderProfile
| Field |
Type |
Presence |
first_seen_ts |
timestamp |
When set |
days_known |
integer |
Non-empty |
msg_count_30d |
integer |
Non-empty |
flagged_count_180d |
integer |
Non-empty |
flagged_count_other_addresses_180d |
integer |
Non-empty |
prevalence |
string |
Non-empty |
profile_key |
string |
Non-empty |
SenderDomain
| Field |
Type |
Presence |
domain |
string |
Non-empty |
age_days |
integer |
When set |
registered_ts |
timestamp |
When set |
LinkFeature
| Field |
Type |
Presence |
domain |
string |
Non-empty |
domain_age_days |
integer |
When set |
popularity_bucket |
string |
Non-empty |
in_urlhaus |
boolean |
Non-empty |
mixed_script |
boolean |
Non-empty |
credentials_in_url |
boolean |
Non-empty |
Lookalike
| Field |
Type |
Presence |
vip_hit |
string |
Non-empty |
org_domain_distance |
integer |
When set |
brand_domain_distance |
integer |
When set |
Detonation
DetonationHop
| Field |
Type |
Presence |
requested_url |
string |
Non-empty |
host |
string |
Non-empty |
resolved_ips |
array of string |
Non-empty |
blocked_ips |
array of DetonationBlockedIP |
Non-empty |
connected_addr |
string |
Non-empty |
status |
integer |
Non-empty |
next_url |
string |
Non-empty |
tls |
DetonationTLS |
When set |
duration_ms |
integer |
Non-empty |
refusal |
DetonationRefusal |
When set |
DetonationBlockedIP
| Field |
Type |
Presence |
ip |
string |
Always |
reason |
string |
Always |
DetonationTLS
| Field |
Type |
Presence |
sni |
string |
Non-empty |
version |
string |
Non-empty |
cipher_suite |
string |
Non-empty |
subject |
string |
Non-empty |
issuer |
string |
Non-empty |
sans |
array of string |
Non-empty |
not_before |
timestamp |
When set |
not_after |
timestamp |
When set |
san_matches_host |
boolean |
Always |
verified |
boolean |
Always |
verify_error |
string |
Non-empty |
DetonationRefusal
| Field |
Type |
Presence |
reason |
string |
Always |
kind |
string |
Non-empty |
DetonationLanding
| Field |
Type |
Presence |
effective_url |
string |
Non-empty |
status |
integer |
Non-empty |
body_sha256 |
string |
Non-empty |
body_bytes |
integer |
Always |
body_complete |
boolean |
Always |
title |
string |
Non-empty |
text_excerpt |
string |
Non-empty |
has_password_input |
boolean |
Non-empty |
form_count |
integer |
Non-empty |
form_action_hosts |
array of string |
Non-empty |
signals_truncated |
boolean |
Non-empty |
VerdictInfo
| Field |
Type |
Presence |
verdict |
string |
Always |
score |
integer |
Always |
top_signals |
array of TopSignal |
Non-empty |
matched_signals |
array of string |
Non-empty |
tags |
array of string |
Non-empty |
engine_version |
string |
Non-empty |
decided_at |
timestamp |
Always |
mode |
string |
Non-empty |
campaign_id |
string |
Non-empty |
TopSignal
| Field |
Type |
Presence |
rule_id |
string |
Always |
name |
string |
Non-empty |
weight |
integer |
Non-empty |
renderings |
array of string |
Non-empty |
| Field |
Type |
Presence |
truncations |
array of string |
Non-empty |
errors |
array of ParseError |
Non-empty |
explode_timeout |
boolean |
Non-empty |
ParseError
| Field |
Type |
Presence |
stage |
string |
Always |
message |
string |
Always |