Apple Mail - Move If Spam
Summary: Of the selected messages, moves the spam ones to the Junk mailbox.
Requires: SpamSieve, Apple Mail
Install Location: ~/Library/Scripts/Applications/Mail or ~/Library/Application Scripts/com.apple.mail
Last Modified: 2021-07-15
Description
Normally, SpamSieve uses a plug-in and a special rule to move spam messages to the Junk mailbox. This script is an alternative way of using SpamSieve from Apple Mail that is useful in two main circumstances:
-
Sometimes it is not possible to use SpamSieve’s Apple Mail plug-in because of a new OS version, an incompatibility with another plug-in, or because you are trying to troubleshoot a crash in Mail.
To use the script in this way, open the Library folder and install the script in the ~/Library/Application Scripts/com.apple.mail folder. Then create a rule in Apple Mail called Move If Spam (do not put “SpamSieve” in the name of the rule) with conditions Every Message and actions Run AppleScript. Select the Apple Mail - Move If Spam.scpt file as the script.
Normally, to re-apply SpamSieve to a bunch of selected messages, you would use the Message ‣ Apply Rules command. This script is useful when you want to re-apply SpamSieve without applying all the other rules.
To use the script in this way, open the Library folder and install the script in the ~/Library/Scripts/Applications/Mail folder. You can invoke the script via the system’s script menu.
Disadvantages of this script compared to the SpamSieve rule are:
- The script is slower than the SpamSieve rule.
- With the SpamSieve rule, Mail will not apply subsequent rules if the message is spam. With a rule that runs the script, Mail will keep applying the rest of the rules.
Installation Instructions · Download in Compiled Format · Download in Text Format
Script
property
pMarkSpamMessagesRead :
false
property
pChangeJunkStatus :
true
property
pColorSpamMessages :
true
property
pFlagSpamMessages :
false
property
pMoveBlueMessagesToTrash :
false
property
pMoveGrayMessagesToTrash :
false
property
pMovePurpleMessagesToTrash :
false
property
pMoveRedMessagesToTrash :
false
property
pMoveOrangeMessagesToTrash :
false
property
pMoveYellowMessagesToTrash :
false
property
pMoveGoodMessagesToInbox :
false
property
pMarkGoodMessagesUnread :
false
property
pEnableDebugLogging :
false
global
useJunkMailbox
on
run
tell
application
"Mail"
set
_messages
to
the
selection
as
list
my
processMessages(
_messages)
end
tell
end
run
using terms from
application
"Mail"
on
perform mail action with messages
_messages
-- This is executed when Mail runs the rule.
my
processMessages(
_messages)
end
perform mail action with messages
end
using terms from
on
processMessages(
_messages)
try
set
{
useJunkMailbox,
_spamFolderName,
_accountName}
to
my
lookupDefaults({"AppleMailUseJunkMailbox", "AppleMailTrainSpamName", "AppleMailSpamAccountName"}, {
false
, "Spam", ""})
repeat
with
_message
in
_messages
my
processMessage(
_message,
_spamFolderName,
_accountName)
end
repeat
on
error
_errorMessage
my
logToConsole("Error processing message: " &
_errorMessage)
end
try
end
processMessages
on
processMessage(
_message,
_spamFolderName,
_accountName)
tell
application
"Mail"
set
_spamMailbox
to
my
spamMailboxForMessage(
_message,
_spamFolderName,
_accountName)
set
_isSpam
to
my
processMessageIfSpam(
_message,
_spamMailbox)
if
not
_isSpam
then
my
processGoodMessage(
_message)
end
if
end
tell
end
processMessage
on
spamMailboxForMessage(
_message,
_spamFolderName,
_accountName)
tell
application
"Mail"
if
_accountName
is
""
then
return
mailbox
_spamFolderName
end
if
try
set
_account
to
account
_accountName
try
-- Use per-account if possible
set
_account
to
(
account
of
mailbox
of
_message)
if
_account
is
missing value
then
set
_account
to
account
_accountName
end
if
end
try
return
mailbox
_spamFolderName
of
_account
on
error
_error
if
not
(
exists
mailbox
_spamFolderName)
then
make
new
mailbox
with properties
{
name:
_spamFolderName}
end
if
return
mailbox
_spamFolderName
end
try
end
tell
end
spamMailboxForMessage
on
processMessageIfSpam(
_message,
_spamMailbox)
set
_source
to
my
sourceFromMessage(
_message)
tell
application
"SpamSieve"
set
_score
to
score
message
_source
end
tell
tell
application
"Mail"
my
debugLog("Spam score of message is " &
_score & ": " &
_message's
subject)
set
_isSpam
to
_score ≥ 50
if
pChangeJunkStatus
then
set
_message's
junk mail status
to
_isSpam
end
if
if
_isSpam
and
pMarkSpamMessagesRead
then
set
_message's
read status
to
true
end
if
set
_moveToTrash
to
my
colorMessageAndDecideIfShouldMoveToTrash(
_message,
_score)
if
_moveToTrash
then
delete
_message
else
if
_isSpam
then
my
moveMessage(
_message,
_spamMailbox)
end
if
return
_isSpam
end
tell
end
processMessageIfSpam
on
colorMessageAndDecideIfShouldMoveToTrash(
_message,
_score)
tell
application
"Mail"
set
_table
to
{¬
{99,
blue
,
pMoveBlueMessagesToTrash, 6}, ¬
{95,
gray
,
pMoveGrayMessagesToTrash, 5}, ¬
{88,
purple
,
pMovePurpleMessagesToTrash, 4}, ¬
{81,
red
,
pMoveRedMessagesToTrash, 3}, ¬
{75,
orange
,
pMoveOrangeMessagesToTrash, 2}, ¬
{50,
yellow
,
pMoveYellowMessagesToTrash, 1}, ¬
{0,
none
,
false
, -1}}
-- Flag colors chosen so that messages sort by spamminess: gray, purple, blue, green, yellow, orange, none
repeat
with
_row
in
_table
set
{
_threshold,
_color,
_moveToTrash,
_flagColor}
to
_row
if
_score ≥
_threshold
then
if
pColorSpamMessages
then
set
_message's
background color
to
_color
end
if
if
pFlagSpamMessages
then
set
_message's
flag index
to
_flagColor
end
if
return
_moveToTrash
end
if
end
repeat
end
tell
end
colorMessageAndDecideIfShouldMoveToTrash
on
processGoodMessage(
_message)
tell
application
"Mail"
try
set
junk mail status
of
_message
to
false
end
try
if
pMarkGoodMessagesUnread
then
try
set
read status
of
_message
to
true
end
try
end
if
if
pMoveGoodMessagesToInbox
then
set
_message's
mailbox
to
my
inboxForMessage(
_message)
end
if
end
tell
end
processGoodMessage
on
inboxForMessage(
_message)
tell
application
"Mail"
set
_accounts
to
accounts
where
its
enabled
is
true
set
_account
to
my
accountFromMessage(
_message,
_accounts)
set
_mailbox
to
my
inboxFromAccount(
_account)
return
_mailbox
end
tell
end
inboxForMessage
on
accountFromMessage(
_message,
_accounts)
tell
application
"Mail"
try
set
_recipientAddresses
to
my
recipientAddressesFromMessage(
_message)
repeat
with
_account
in
_accounts
set
_accountAddresses
to
my
addressesForAccount(
_account)
repeat
with
_recipientAddress
in
_recipientAddresses
ignoring
case
if
_recipientAddress
is
in
_accountAddresses
then
return
_account
end
ignoring
end
repeat
end
repeat
end
try
try
-- Only do this as a fallback, because some people have one remote Spam mailbox but multiple inboxes.
set
_account
to
account
of
mailbox
of
_message
if
_account
is
not
missing value
then
return
_account
-- Can happen for local mailboxes.
end
try
return
item
1
of
_accounts
end
tell
end
accountFromMessage
on
inboxFromAccount(
_account)
tell
application
"Mail"
set
_names
to
{"INBOX", "Inbox", "innboks", "Posteingang", "Boite de reception"}
repeat
with
_name
in
_names
try
set
_mailbox
to
mailbox
_name
of
_account
return
_mailbox
end
try
end
repeat
return
inbox
end
tell
end
inboxFromAccount
on
recipientAddressesFromMessage(
_message)
tell
application
"Mail"
set
_addresses
to
{}
set
_addresses
to
_addresses &
my
toAddressesFromMessage(
_message)
set
_addresses
to
_addresses &
my
ccAddressesFromMessage(
_message)
set
_addresses
to
_addresses &
my
extraAddressesFromMessage(
_message)
if
_addresses
is
not
{}
then
return
_addresses
return
my
parseAddressesFromMessage(
_message)
end
tell
end
recipientAddressesFromMessage
on
toAddressesFromMessage(
_message)
tell
application
"Mail"
set
_addresses
to
{}
if
(
count
_message's
to recipients
) > 20
then
-- Mail in 10.3.5 will hang if we ask it to get too many "to recipients"
set
_recipients
to
{
_message's
first
to recipient
}
else
set
_recipients
to
_message's
to recipients
end
if
repeat
with
_recipient
in
_recipients
copy
_recipient's
address
to
end
of
_addresses
end
repeat
return
_addresses
end
tell
end
toAddressesFromMessage
on
ccAddressesFromMessage(
_message)
tell
application
"Mail"
set
_addresses
to
{}
if
(
count
_message's
cc recipients
) > 20
then
set
_recipients
to
{
_message's
first
cc recipient
}
else
set
_recipients
to
_message's
cc recipients
end
if
repeat
with
_recipient
in
_recipients
copy
_recipient's
address
to
end
of
_addresses
end
repeat
return
_addresses
end
tell
end
ccAddressesFromMessage
on
extraAddressesFromMessage(
_message)
tell
application
"Mail"
set
_addresses
to
{}
set
_headerNames
to
{"envelope-to", "x-original-to", "x-envelope-to", "delivered-to"}
try
set
_headers
to
_message's
headers
repeat
with
_header
in
_headers
try
set
_name
to
name
of
_header
ignoring
case
if
_name
in
_headerNames
then
copy
content
of
_header
to
end
of
_addresses
end
if
end
ignoring
on
error
-- Accessing headers seems broken on 10.7.0
end
try
end
repeat
end
try
return
_addresses
end
tell
end
extraAddressesFromMessage
on
parseAddressesFromMessage(
_message)
tell
application
"Mail"
set
_addresses
to
{}
try
set
_allHeaders
to
all headers
of
_message
repeat
with
_headerName
in
_headerNames
set
AppleScript's
text item delimiters
to
_headerName & ": "
try
ignoring
case
set
_value
to
paragraph
1
of
text item
2
of
_allHeaders
end
ignoring
copy
_value
to
end
of
_addresses
end
try
end
repeat
end
try
return
_addresses
end
tell
end
parseAddressesFromMessage
on
lookupDefaults(
_keys,
_defaultValues)
tell
application
"SpamSieve"
try
set
_result
to
{}
repeat
with
_i
from
1
to
count
of
_keys
set
_key
to
item
_i
of
_keys
set
_defaultValue
to
item
_i
of
_defaultValues
set
_value
to
lookup single
key
_key
default value
_defaultValue
copy
_value
to
end
of
_result
end
repeat
return
_result
on
error
-- SpamSieve 2.9.15 and earlier
return
lookup
keys
_keys
default values
_defaultValues
end
try
end
tell
end
lookupDefaults
-- Logging
on
debugLog(
_message)
if
pEnableDebugLogging
then
my
logToConsole(
_message)
end
debugLog
on
logToConsole(
_message)
set
_logMessage
to
"SpamSieve [Apple Mail Move If Spam] MJTLog " &
_message
do shell script
"/usr/bin/logger -s " &
_logMessage's
quoted form
end
logToConsole
on
makeLogMessage(
_action,
_mailbox,
_detail)
return
_action & " " &
my
describeMailbox(
_mailbox) & ": " &
_detail
end
makeLogMessage
on
describeMailbox(
_mailbox)
tell
application
"Mail"
set
_mailboxName
to
_mailbox's
name
try
set
_accountName
to
name
of
_mailbox's
account
on
error
set
_accountName
to
"On My Mac"
end
try
return
"“" &
_accountName & "” / “" &
_mailboxName & "”"
end
tell
end
describeMailbox
-- Logging Helpers
on
sourceFromMessage(
_message)
tell
application
"Mail"
my
debugLog(
my
makeLogMessage("Getting source of message in",
_message's
mailbox
,
_message's
subject))
return
_message's
source
end
tell
end
sourceFromMessage
on
moveMessage(
_message,
_mailbox)
tell
application
"Mail"
if
useJunkMailbox
then
my
debugLog("Moving message to Junk: " &
_message's
subject)
move
_message
to
junk mailbox
else
my
debugLog(
my
makeLogMessage("Moving message to",
_mailbox,
_message's
subject))
set
_message's
mailbox
to
_mailbox
end
if
end
tell
end
moveMessage