length(body.links) < 10
and length(body.current_thread.text) < 2000
and (
// body detection
// be sure to update the attachment detection regexes too!
(
(
// items and brands
// Guitars
regex.icontains(body.current_thread.text,
'(?:Gibson|Fender|Lowden|Martin|Taylor|Ibanez|Knaggs)\s*[^\r\n]{0,50}\s*guitar',
'guitar\s*[^\r\n]{0,50}\s*(?:Gibson|Fender|Lowden|Martin|Taylor|Ibanez|Knaggs)',
)
// Piano/Keyboards
or regex.icontains(body.current_thread.text,
'(?:Yamaha|Kawai|Baldwin|Roland|Stei?nway(?: (?:&|and) Sons?)?|\d{4})\s*[^\r\n]{0,50}(?:baby.grand|piano|baby.grand.piano|keyboard)',
'(?:baby.grand|piano|baby.grand.piano|keyboard)\s*[^\r\n]{0,50}(?:Yamaha|Kawai|Baldwin|Roland|Stei?nway(?: (?:&|and) Sons?)?|\d{4})',
// strong indicators for generalized instrument
'(?:piano|keyboard)\s*[^\r\n]{0,50}(?:available|sale|rehome|gift)'
)
// Violins & Orchestral
or regex.icontains(body.current_thread.text,
'(?:Stradivarius|Guarneri|Yamaha|Stentor|Eastman|Cremona|Cecilio|Mendini)\s*[^\r\n]{0,50}(violin|viola|cello|celli)',
)
// brass/wind/woodwinds
or regex.icontains(body.current_thread.text,
'(?:Bach|Yamaha|Selmer|Conn|King|Jupiter|Buffet Crampon |Pearl)\s*[^\r\n]{0,50}(trombone|trumpet|saxophone|clarinet|flute)'
)
// generic
or strings.ilike(body.current_thread.text,
'* musical instruments *',
'* instrument as a gift*'
)
)
and (
// often a person is moving
strings.ilike(body.current_thread.text,
'* downsizing *',
'* relocating *',
'* to relocate *',
'* relocation *',
'* moving *'
)
or strings.ilike(body.current_thread.text,
'* give away*',
'* generously offering *',
'*a loving home*',
'*a good home*',
'*find a new home *',
'*rehome these instruments *',
'* free donation*',
'*free*member of the music community*'
)
// generally someone died
or regex.icontains(body.current_thread.text,
'inherited instruments',
'late (?:husband|father|dad|wife|mother|mom)',
'(?:husband|father|dad|wife|mother|mom)[^\r\n]{0,50}estate'
)
// passion/love for the item
or strings.ilike(body.current_thread.text,
'* genuinely cherish*',
'* cherished possessions*',
'* passionate instrument*',
'* music lover*',
'* had a passion for music*',
'* appreciates music*',
"* special piece*",
"* a lot of meaning*",
"* profound sentimental*",
'* will cherish*',
'* passion for music*',
'* treasured items *'
)
)
and (
// it talks about a shipping fee upfront
regex.icontains(body.current_thread.text,
'shipping (?:fee|cost|arrangement)',
'(?:responsible|pay) for shipping',
'no (?:local\s)?pick.?up',
'(?:local\s)?pick.?up.{0,50}not available',
'delivery only',
'moving company'
)
// recipient or someone they know might have an interest
or strings.ilike(body.current_thread.text,
'* if you will take it *',
'* or have someone *',
'* indicate your interest *',
'* to someone you know *',
'* know someone who *',
'* someone you know would *',
'* someone who will *',
'* someone who truly *',
'* anyone you know *',
)
or regex.icontains(body.current_thread.text,
'if you[^\r\n]{0,20}(?:(?:might|will|would) be|are)[^\r\n]{0,20}interested',
'(?:any|some)one[^\r\n]{0,20}(is|will|would|might be)[^\r\n]{0,20}interested',
'who (?:will|would|might) appreciate',
)
or (
// there's an email in the body
any(regex.extract(body.current_thread.text,
"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}"
),
strings.parse_email(.full_match).domain.domain in $free_email_providers
or strings.parse_email(.full_match).domain.root_domain in $free_email_providers
)
// reply-to doesn't match sender
or (
length(headers.reply_to) > 0
and sender.email.email not in map(headers.reply_to, .email.email)
)
// there are no recipients
or length(recipients.to) == 0
// redirects to a phone number
or regex.icontains(body.current_thread.text,
'(?:call|contact|text)[^\r\n]{0,50} at'
)
or regex.icontains(body.current_thread.text,
'(?:private|personal) (?:e-?)?mail'
)
or strings.icontains(body.current_thread.text, ' kindly ')
or strings.icontains(body.current_thread.text, ' (kindly ')
)
)
)
or (
any(filter(attachments, .size < 10000),
(
// items and brands
// Guitars
regex.icontains(file.parse_text(.).text,
'(?:Gibson|Fender|Lowden|Martin|Taylor|Ibanez|Knaggs)\s*[^\r\n]{0,50}\s*guitar',
'guitar\s*[^\r\n]{0,50}\s*(?:Gibson|Fender|Lowden|Martin|Taylor|Ibanez|Knaggs)',
)
// Piano/Keyboards
or regex.icontains(file.parse_text(.).text,
'(?:Yamaha|Kawai|Baldwin|Roland|Stei?nway(?: (?:&|and) Sons?)?)\s*[^\r\n]{0,50}(?:baby.grand|piano|baby.grand.piano|keyboard)',
'(?:baby.grand|piano|baby.grand.piano|keyboard)\s*[^\r\n]{0,50}(?:Yamaha|Kawai|Baldwin|Roland|Stei?nway(?: (?:&|and) Sons?)?|\d{4})',
// strong indicators for generalized instrument
'(?:piano|keyboard)\s*[^\r\n]{0,50}(?:available|sale|rehome|gift)'
)
// Violins & Orchestral
or regex.icontains(file.parse_text(.).text,
'(?:Stradivarius|Guarneri|Yamaha|Stentor|Eastman|Cremona|Cecilio|Mendini)\s*[^\r\n]{0,50}(violin|viola|cello|celli)',
)
// brass/wind/woodwinds
or regex.icontains(file.parse_text(.).text,
'(?:Bach|Yamaha|Selmer|Conn|King|Jupiter|Buffet Crampon |Pearl)\s*[^\r\n]{0,50}(trombone|trumpet|saxophone|clarinet|flute)'
)
// generic
or strings.ilike(file.parse_text(.).text,
'* musical instruments *',
'* instrument as a gift*'
)
)
and (
// often a person is moving
strings.ilike(file.parse_text(.).text,
'* downsizing *',
'* relocating *',
'* to relocate *',
'* relocation *',
)
or strings.ilike(file.parse_text(.).text,
'* give away*',
'* generously offering *',
'*a loving home*',
'*a good home*',
'*find a new home *',
'*rehome these instruments *',
'* free donation*',
'*free*member of the music community*'
)
// generally someone died
or regex.icontains(file.parse_text(.).text,
'inherited instruments',
'late (?:husband|father|dad|wife|mother|mom)',
'(?:husband|father|dad|wife|mother|mom)[^\r\n]{0,50}estate'
)
// passion/love for the item/music
or strings.ilike(file.parse_text(.).text,
'* genuinely cherish*',
'* cherished possessions*',
'* passionate instrument*',
'* music lover*',
'* had a passion for music*',
'* appreciates music*',
"* special piece*",
"* a lot of meaning*",
"* profound sentimental*",
'* will cherish*',
'* passion for music*',
'* treasured items *'
)
)
and (
// it talks about a shipping fee upfront
regex.icontains(file.parse_text(.).text,
'shipping (?:fee|cost|arrangement)',
'(?:responsible|pay) for shipping',
'no (?:local\s)?pick.?up',
'(?:local\s)?pick.?up.{0,50}not available',
'delivery only',
'moving company'
)
or strings.ilike(file.parse_text(.).text,
'* if you will take it *',
'* or have someone *',
'* indicate your interest *',
'* to someone you know *',
'* know someone who *',
'* someone you know would *',
'* someone who will *',
'* anyone you know *',
)
or regex.icontains(file.parse_text(.).text,
'if you[^\r\n]{0,20}(?:(?:might|will|would) be|are)[^\r\n]{0,20}interested',
'(?:any|some)one[^\r\n]{0,20}(is|will|would|might be)[^\r\n]{0,20}interested',
'who (?:will|would|might) appreciate',
)
// there's an email in the body
or any(regex.extract(file.parse_text(.).text,
"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}"
),
strings.parse_email(.full_match).domain.domain in $free_email_providers
or strings.parse_email(.full_match).domain.root_domain in $free_email_providers
)
// reply-to doesn't match sender
or (
length(headers.reply_to) > 0
and sender.email.email not in map(headers.reply_to, .email.email)
)
// there are no recipients
or length(recipients.to) == 0
// redirects to a phone number
or regex.icontains(file.parse_text(.).text,
'(?:call|contact|text)[^\r\n]{0,50} at'
)
or regex.icontains(file.parse_text(.).text,
'(?:private|personal) (?:e-?)?mail'
)
or strings.icontains(file.parse_text(.).text, ' kindly ')
or strings.icontains(file.parse_text(.).text, ' (kindly ')
)
)
)
)
// not high trust sender domains
and not (
sender.email.domain.root_domain in $high_trust_sender_root_domains
and headers.auth_summary.dmarc.pass
)
and not sender.email.domain.root_domain in (
'ridleyacademy.com', // person provides piano lessons and offers to give a Roland baby-grand away
'mountainpiano.com' // legitimate piano moving company in Denver
)
Playground
Test against your own EMLs or sample data.