Apple Mail - Rescue Good Messages

Summary: Automatically filter messages caught by server junk filters, moving the good messages to the inbox.
Requires: SpamSieve, Apple Mail
Install Location: ~/Library/Application Scripts/com.apple.mail
Last Modified: 2021-07-16

Description

The junk/spam filter on your mail server can cause problems. It is more likely than SpamSieve to mistakenly classify your good messages as spam, yet it rarely catches spam messages that SpamSieve would have missed. It’s often best simply to turn off the server junk filter, however some mail servers such as iCloud do not allow this. In such cases, this script saves you from mistakes that the server junk filter made by moving any messages that it thinks are good back to the inbox.

To install:

  1. Go through your Junk mailbox and delete or mark as read any old messages. You probably don’t want the script to process your entire spam archive, just new messages that the server filter catches.
  2. Click here to download the script. Move it to the folder /Users/<username>/Library/Application Scripts/com.apple.mail. To access the Library folder, click on the Go menu in the Finder while holding down the Option key.
  3. Go to Mail’s Preferences window and create a new rule at the top of the list (above the SpamSieve rule) called Rescue Good Messages SpamSieve.
  4. The rule conditions should say Every Message.
  5. The rule actions should say Run AppleScript […]Apple Mail - Rescue Good Messages.scpt. First, choose Run AppleScript from the pop-up menu; then select the Apple Mail - Rescue Good Messages.scpt file (using either the pop-up menu or the Choose… button).

Now, whenever you receive a new message in the inbox, SpamSieve will look in the Junk mailbox and check any unread messages that have not already been colored as spam by SpamSieve. Any that are not spam will be moved to the inbox. Any that are spam will be colored according to their spam level and left in the Junk mailbox.

Normally, the script will run when Mail receives a new message in the inbox and applies the “Rescue Good Messages SpamSieve” rule. You can also set up the script as a standalone application. This has less overhead than running the script from within Mail, and it allows the script to run on a more predictable schedule. To do this, use Script Editor to export the script as an application (with the Stay Open option checked) and then launch the application. You can set in the “idle” handler how often it should run.

To test this script you can run it in Script Editor (a.k.a. AppleScript Editor) and look for any error messages in the Console application. You can also enable debug logging by changing pEnableDebugLogging from false to true.

Installation Instructions · Download in Compiled Format · Download in Text Format

Script

property pMarkSpamMessagesRead : false
property pMarkGoodMessagesRead : 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 pEnableDebugLogging : false

on run
    
-- This is executed when you run the script directly.
    
my filterServerJunkMailboxes()
end run

on idle
    
-- This is executed periodically when the script is run as a stay-open application.
    
my filterServerJunkMailboxes()
    
return 60 * 5 -- Run again in 5 minutes.
end idle

using terms from application "Mail"
    
on perform mail action with messages _messages
        
-- This is executed when Mail runs the rule.
        
my filterServerJunkMailboxes()
    
end perform mail action with messages
end using terms from

on filterServerJunkMailboxes()
    
if application "Mail" is not running then return
    
try
        
tell application "Mail" to get version
    
on error _error number _errorNumber
        
if _errorNumber is -1743 then -- errAEEventNotPermitted
            
set _alertMessage to "You can give “Apple Mail - Rescue Good Messages” access to control Mail and SpamSieve from System Preferences > Security & Privacy > Privacy > Automation. For more information, please see:

https://c-command.com/spamsieve/help/security-privacy-acce"
            
display alert _error message _alertMessage
        
end if
    
end try
    
    
tell application "Mail"
        
try
            
set _mailboxes to mailboxes of junk mailbox
            
repeat with _mailbox in _mailboxes
                
try
                    
my filterMailbox(_mailbox)
                
on error _error number _errorNumber
                    
my logToConsole("Error " & _errorNumber & " filtering mailbox “" & _mailbox's name & "” of account “" & _mailbox's account's name & "”: " & _error)
                
end try
            
end repeat
        
on error _error
            
my logToConsole("Error filtering junk mailboxes: " & _error)
        
end try
    
end tell
end filterServerJunkMailboxes

on filterMailbox(_mailbox)
    
tell application "Mail"
        
my debugLog(my makeLogMessage("Start checking mailbox", _mailbox, ""))
        
set _total to count of messages of _mailbox
        
my debugLog(my makeLogMessage("Total messages in mailbox", _mailbox, _total))
        
my debugLog(my makeLogMessage("Getting unprocessed messages in mailbox", _mailbox, ""))
        
with timeout of 3 * 60 seconds
            
set _messages to messages of _mailbox whose read status is false and deleted status is false and background color is none
        
end timeout
        
my debugLog(my makeLogMessage("Messages to process in mailbox", _mailbox, count of _messages))
        
        
repeat with _message in _messages
            
if not my processMessageIfSpam(_message) then
                
if pMarkGoodMessagesRead then set _message's read status to true
                
my debugLog("Moving message to inbox: " & _message's subject)
                
move _message to inbox
            
end if
        
end repeat
        
my debugLog(my makeLogMessage("Finished checking mailbox", _mailbox, ""))
    
end tell
end filterMailbox

on processMessageIfSpam(_message)
    
set _source to my sourceFromMessage(_message)
    
tell application "SpamSieve"
        
set _score to score message _source without auto training
    
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 debugLog("Leaving spam message in Junk: " & _message's subject)
        
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

-- Logging

on debugLog(_message)
    
if pEnableDebugLogging then my logToConsole(_message)
end debugLog

on logToConsole(_message)
    
set _logMessage to "SpamSieve [Apple Mail Rescue Good Messages] " & _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