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: 2025-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, if present) 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
pUnflagSpamMessages : 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
            try
                if
pMarkSpamMessagesRead then
                    set
_message's read status to true
                end if
            end try
        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
pUnflagSpamMessages then
                    set
_message's flag index to -1
                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