type.inbound
// we need at least two threads
and length(body.previous_threads) > 1
and (
// NLU on previous threads
( // oldest thread is invoice/payment related
(
any(ml.nlu_classifier(body.previous_threads[length(body.previous_threads) - 1].text,
subject=body.previous_threads[length(body.previous_threads
) - 1].subject.base
).tags,
.name in ("invoice", "payment") and .confidence != "low"
)
or any(ml.nlu_classifier(body.previous_threads[length(body.previous_threads
) - 1].text,
subject=body.previous_threads[length(body.previous_threads
) - 1].subject.base
).topics,
.name in ("Request to View Invoice", "Payment Information")
and .confidence != "low"
)
)
// second to oldest thread is invoice/payment related
and (
any(ml.nlu_classifier(body.previous_threads[length(body.previous_threads) - 2].text,
subject=body.previous_threads[length(body.previous_threads
) - 2].subject.base
).tags,
.name in ("invoice", "payment") and .confidence != "low"
)
or any(ml.nlu_classifier(body.previous_threads[length(body.previous_threads
) - 2].text,
subject=body.previous_threads[length(body.previous_threads
) - 2].subject.base
).topics,
.name in ("Request to View Invoice", "Payment Information")
and .confidence != "low"
)
)
)
// if we don't get NLU but there is a W9 or Inv attached, we can assume it's invoice related
or any(attachments, strings.istarts_with(.file_name, 'INV', "W-9", 'W9'))
)
// each of the two oldest threads have 1 or less recipients (sometimes the "to" header is missing)
and length(body.previous_threads[length(body.previous_threads) - 1].recipients.to
) <= 1
and length(body.previous_threads[length(body.previous_threads) - 2].recipients.to
) <= 1
// at least one party in the two oldest threads is missing an email
and (
body.previous_threads[length(body.previous_threads) - 1].sender.email.email == ""
or body.previous_threads[length(body.previous_threads) - 1].recipients.to[0].email.email == ""
or body.previous_threads[length(body.previous_threads) - 2].sender.email.email == ""
or body.previous_threads[length(body.previous_threads) - 2].recipients.to[0].email.email == ""
)
// an org vip sent/received messages
and any($org_vips,
(
body.previous_threads[length(body.previous_threads) - 1].recipients.to[0].display_name == .display_name
and body.previous_threads[length(body.previous_threads) - 2].sender.display_name == .display_name
)
or (
body.previous_threads[length(body.previous_threads) - 1].sender.display_name == .display_name
and body.previous_threads[length(body.previous_threads) - 2].recipients.to[0].display_name == .display_name
)
)
// the VIP is no longer in the current message
and not any(flatten([recipients.to, recipients.cc, recipients.bcc]),
any($org_vips,
.email != ""
and strings.icontains(..email.email, .email)
and (
(
body.previous_threads[length(body.previous_threads) - 1].recipients.to[0].display_name == .display_name
and body.previous_threads[length(body.previous_threads) - 2].sender.display_name == .display_name
)
or (
body.previous_threads[length(body.previous_threads) - 1].sender.display_name == .display_name
and body.previous_threads[length(body.previous_threads) - 2].recipients.to[0].display_name == .display_name
)
)
)
)
// not from authorized senders on the org's domain
and not (
sender.email.domain.domain in $org_domains
and coalesce(headers.auth_summary.dmarc.pass, false)
)
Playground
Test against your own EMLs or sample data.