Apple Mail - Server Junk Mailbox

Summary: Automatically applies SpamSieve to unread messages in server Junk mailboxes.
Requires: SpamSieve, Apple Mail
Install Location: ~/Library/Application Scripts/ or ~/Library/Scripts/Applications/Mail/
Last Modified: 2019-09-25


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. Additionally, most people don’t want to deal with two separate spam mailboxes, one for the server junk filter and one for SpamSieve. It’s often best simply to turn off the server junk filter, however some mail servers such as iCloud do not allow this.

This script solves two problems:

  1. It saves you from mistakes that the server junk filter made by moving any messages that it thinks are good back to the inbox.
  2. It consolidates the spam messages from all the accounts into a single spam mailbox (the same one where SpamSieve is already putting your spam).

To install:

  1. Download the script using one of the links below. On macOS 10.8 or later, the script must be saved in the folder /Users/<username>/Library/Application Scripts/ This is because Mail is sandboxed and only has access to run scripts in that folder. To access the Library folder, click on the Go menu in the Finder while holding down the Option key.
  2. Open the script in AppleScript Editor and enter your account and junk mailbox names in accountAndServerJunkMailboxNames(). The account name comes from the Description field in the Accounts tab of Mail’s preferences. For example, if you have one account called Account 1 and want to process its Junk mailbox, you would use:

    on accountAndServerJunkMailboxNames()
        return {{"Account 1", {"Junk"}}}
    end accountAndServerJunkMailboxNames

    The mailbox name is normally the same as what you see in Mail. (If you are using the special Junk mailbox, you can get its actual name from the Mailbox Behaviors tab of that account in Mail’s preferences.) You can also get the AppleScript names using the Apple Mail - List Mailboxes script. In rare cases, if you have a Gmail account you may need to enter [Gmail]/Spam instead of Spam.

    If you want to process the Junk mailbox of the Personal account and the Junk and Bulk mailboxes of the Work account you would use:

    on accountAndServerJunkMailboxNames()
        return {{"Personal", {"Junk"}}, {"Work", {"Junk", "Bulk"}}}
    end accountAndServerJunkMailboxNames
  3. By default, SpamSieve consolidates the spam in a mailbox called Spam under On My Mac. This configuration is specified using:

    on mainSpamMailboxInfo()
        return {"", "Spam"}
    end mainSpamMailboxInfo

    You can also specify a particular mailbox in one of your accounts. For example, if you had created a SpamSieveSpam mailbox in the Personal account you could specify that using:

    on mainSpamMailboxInfo()
        return {"Personal", "SpamSieveSpam"}
    end mainSpamMailboxInfo
  4. To specify that each account’s spam should be collected in a separate mailbox, set pPerAccountSpamMailboxes to true.

  5. Go to Mail’s Preferences window and create a new rule at the top of the list (above the SpamSieve rule) called Server Junk Mailbox SpamSieve.
  6. The rule conditions should say Every Message.
  7. The rule actions should say Run AppleScript […]Apple Mail - Server Junk Mailbox.scpt. First, choose Run AppleScript from the pop-up menu; then select the Apple Mail - Server Junk Mailbox.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 all the server junk mailboxes that you specified and check the unread messages. Any that are spam will be moved to the Spam mailbox. Any that are good will be moved to the inbox.

Normally, the script will run when Mail receives a new message in the inbox and applies the “Server Junk Mailbox 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


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 pPerAccountSpamMailboxes : false
property pOnlyMarkSpamAsRead : false
property pEnableDebugLogging : false

on accountAndServerJunkMailboxNames()
return {{"Account 1", {"Junk"}}}
end accountAndServerJunkMailboxNames

on mainSpamMailboxInfo()
return {"", "Spam"}
end mainSpamMailboxInfo

-- Do not modify below this line.

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
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 - Server Junk Mailbox” access to control Mail and SpamSieve from System Preferences > Security & Privacy > Privacy > Automation. For more information, please see:"
display alert _error message _alertMessage
end if
end try
tell application "Mail"
repeat with _pair in my accountAndServerJunkMailboxNames()
set {_accountName, _mailboxNames} to _pair
set _account to account _accountName
repeat with _mailboxName in _mailboxNames
my filterAccountMailboxNamed(_account, _mailboxName)
on error _error number _errorNumber
my logToConsole("Error " & _errorNumber & " filtering mailbox “" & _mailboxName & "” of account “" & _accountName & "”: " & _error)
end try
end repeat
end repeat
on error _error
my logToConsole("Error filtering junk mailboxes: " & _error)
end try
end tell
end filterServerJunkMailboxes

on filterAccountMailboxNamed(_account, _mailboxName)
tell application "Mail"
set _mailbox to _account's mailbox _mailboxName
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 unread, non-deleted 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
end timeout
my debugLog(my makeLogMessage("Messages to process in mailbox", _mailbox, count of _messages))
set _spamMailbox to my spamMailboxForAccount(_account)
set _inbox to my inboxFromAccount(_account)
repeat with _message in _messages
if not my processMessageIfSpam(_message, _spamMailbox) then
if pMarkGoodMessagesRead then set _message's read status to true
my moveMessage(_message, _inbox)
end if
end repeat
my debugLog(my makeLogMessage("Finished checking mailbox", _mailbox, ""))
end tell
end filterAccountMailboxNamed

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 or pOnlyMarkSpamAsRead) then
set _message's read status to true
end if
if not pOnlyMarkSpamAsRead then
set _moveToTrash to my colorMessageAndDecideIfShouldMoveToTrash(_message, _score)
if _moveToTrash then
delete _message
else if _isSpam then
my moveMessage(_message, _spamMailbox)
end if
end if
return _isSpam
end tell
end processMessageIfSpam

on colorMessageAndDecideIfShouldMoveToTrash(_message, _score)
tell application "Mail"
set _table to
blue, pMoveBlueMessagesToTrash, 6}, ¬
gray, pMoveGrayMessagesToTrash, 5}, ¬
purple, pMovePurpleMessagesToTrash, 4}, ¬
red, pMoveRedMessagesToTrash, 3}, ¬
orange, pMoveOrangeMessagesToTrash, 2}, ¬
yellow, pMoveYellowMessagesToTrash, 1}, ¬
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 spamMailboxForAccount(_account)
if pPerAccountSpamMailboxes then
tell application "Mail"
set {_accountName, _mailboxName} to my mainSpamMailboxInfo()
return mailbox _mailboxName of _account
on error _error
my logToConsole("Error getting per-account spam mailbox: " & _mailboxName)
end try
end tell
end if
return my mainSpamMailbox()
end spamMailboxForAccount

on mainSpamMailbox()
set {_accountName, _mailboxName} to my mainSpamMailboxInfo()
tell application "Mail"
if _accountName is "" then
return mailbox _mailboxName
return mailbox _mailboxName of account _accountName
end if
end tell
end mainSpamMailbox

on inboxFromAccount(_account)
tell application "Mail"
set _names to {"INBOX", "Inbox", "innboks", "Posteingang", "Boite de reception"}
repeat with _name in _names
set _mailbox to mailbox _name of _account
return _mailbox
end try
end repeat
return inbox
end tell
end inboxFromAccount

-- Logging

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

on logToConsole(_message)
set _logMessage to "SpamSieve [Apple Mail Server Junk Mailbox] " & _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
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"
my debugLog(my makeLogMessage("Moving message to", _mailbox, _message's subject))
set _message's mailbox to _mailbox
end tell
end moveMessage