I have checked each rule like you suggested. They work as intended. And each rule has checked ‘Do not apply other rules to messages that meet these conditions’.
I don’t think this is the issue though, because all of the rules have this checked, and therefore the second and later rules should not execute, no matter the order (unless there is some resetting of the messages after the script handles them. And-Somehow Spamsieve rule knows not to reprocess rules when the script moves the good email back to the Inbox - maybe at that time the other rules might process? I am not sure how this works and wonder if this is related to the issue.
The other rules do not have a requirement for the email to be of the folder Inbox, which is the only condition of the Spamsieve rule.
My understanding is that when a message is downloaded from the server into the Outlook Inbox, the Outlook rule moves the messages out of the Inbox folder and into the InboxSpamSieve folder - this is what the rule states.
Then the script tests the InboxSpamSieve contents and moves ‘not-spam’ back to the inbox, and spam to the junk folder.
Also, the Inbox folder is synced with the server (it is not the Inbox that is on my hard-drive - (I can delete or move an email out of the Inbox folder using Outlook, and that move will be reflected in the server when using an internet browser of phone mail app to look at emails. The other folders are also folders on the server. I am not sure if that is causing some problem.
Here is the spamsieve script, if it helps.
-- Outlook - Filter Mailboxes
-- https://c-command.com/scripts/spamsieve/outlook-filter-mailboxes
-- Summary: Periodically filter new messages in the inbox with SpamSieve.
-- Requires: SpamSieve, Outlook 365
-- Install Location: /Applications
-- Last Modified: 2019-01-25
global gDebug, gSecondsBetweenChecks, gInboxSpamSieveName, gGoodCategoryName, gGoodFolderName
set _keys to {"OutlookScriptDebug", "OutlookFilterMailboxesSecondsBetweenChecks", "OutlookFilterMailboxesInboxSpamSieveName", "OutlookFilterMailboxesGoodCategoryName", "OutlookFilterMailboxesGoodFolderName"}
set _defaultValues to {false, 1 * 60, "InboxSpamSieve", "Good", "", "Inbox"}
set {gDebug, gSecondsBetweenChecks, gInboxSpamSieveName, gGoodCategoryName, gGoodFolderName} to my lookupDefaults(_keys, _defaultValues)
my filterMailboxes()
on idle
-- This is executed periodically when the script is run as a stay-open application.
my filterMailboxes()
return gSecondsBetweenChecks
end idle
on reopen
-- This is executed when you click on the Dock icon after the script app is already running.
my filterMailboxes()
end reopen
on filterMailboxes()
if application "Microsoft Outlook" is not running then
my debugLog("Outlook is not running")
return
end if
try
set _mailboxes to my mailboxesToFilter()
repeat with _mailbox in _mailboxes
set _messages to my messagesToFilterFromMailbox(_mailbox)
if gDebug then
my debugLog((count of _messages) & " messages to filter in " & describeFolder(_mailbox))
end if
repeat with _message in _messages
set _score to scoreMessage(_message)
if _score ≥ 50 then
my processSpamMessage(_message, _score)
else
my processGoodMessage(_message, _score)
end if
end repeat
end repeat
on error _error number _errorNumber
my logToConsole("Error: " & _error)
if _errorNumber is -1743 then -- errAEEventNotPermitted
set _alertMessage to "You can give “Outlook Filter Mailboxes” access to control Outlook 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
end filterMailboxes
on mailboxesToFilter()
tell application "Microsoft Outlook"
set _result to every mail folder whose name starts with gInboxSpamSieveName
if _result is not {} then return _result
set _result to {}
set _accounts to imap accounts & pop accounts & exchange accounts -- Just "accounts" does not work.
repeat with _account in _accounts
copy _account's inbox to end of _result
end repeat
copy inbox to end of _result -- For Google accounts
end tell
return _result
end mailboxesToFilter
on messagesToFilterFromMailbox(_mailbox)
tell application "Microsoft Outlook"
if name of _mailbox starts with gInboxSpamSieveName then
with timeout of 2 * 60 seconds
return messages of _mailbox -- Faster than checking unread and category
end timeout
end if
set _messages to my unreadMessagesFromMailbox(_mailbox)
set _result to {}
repeat with _message in _messages
if my shouldFilterMessage(_message) then
copy _message to end of _result
end if
end repeat
return _result
end tell
end messagesToFilterFromMailbox
on unreadMessagesFromMailbox(_mailbox)
set _startDate to current date
tell application "Microsoft Outlook"
try
with timeout of 2 * 60 seconds
-- Using "whose" clause seems to make Outlook unresponsive.
set _allMessages to messages of _mailbox -- whose is read is false
end timeout
set _messages to {}
repeat with _message in _allMessages
if _message's is read is false then
copy _message to end of _messages
end if
end repeat
on error _error number _errorNumber
my logToConsole("Outlook reported error “" & _error & "” (number " & _errorNumber & ") getting the messages from " & my describeFolder(_mailbox))
return {}
end try
end tell
set _endDate to current date
set _duration to _endDate - _startDate
set _statusMessage to "Outlook took " & _duration & " seconds to get " & (count of _messages) & " unread messages out of " & (count of _allMessages) & " total messages from " & my describeFolder(_mailbox)
if _duration > 3 then
my logToConsole(_statusMessage)
else
my debugLog(_statusMessage)
end if
return _messages
end unreadMessagesFromMailbox
on shouldFilterMessage(_message)
if gGoodCategoryName is "" then
return true
end if
return not my doesMessageHaveCategoryNamed(_message, gGoodCategoryName)
end shouldFilterMessage
on doesMessageHaveCategoryNamed(_message, _categoryName)
tell application "Microsoft Outlook"
set _categories to _message's category
repeat with _category in _categories
if _category's name is _categoryName then
return true
end if
end repeat
return false
end tell
end doesMessageHaveCategoryNamed
on scoreMessage(_message)
tell application "Microsoft Outlook"
set _source to _message's source
end tell
if _source is missing value then
my logToConsole("Outlook could not get the source of message: " & my subjectOfMessage(_message))
return 49
else
tell application "SpamSieve"
return score message _source
end tell
end if
end scoreMessage
on processSpamMessage(_message, _score)
my debugLogMessage("Predicted Spam (" & _score & ")", _message)
if my isSpamScoreUncertain(_score) then
my applyCategoryNamed(_message, "Uncertain Junk")
else
my applyCategoryNamed(_message, "Junk")
end if
my moveToSpamFolder(_message)
end processSpamMessage
on moveToInbox(_message)
tell application "Microsoft Outlook"
try
set _inbox to inbox of _message's account
on error _errorMessage -- Will fail for new Google accounts that aren't scriptable.
my logToConsole("Error getting inbox of message so using generic inbox: " & _errorMessage)
try
move _message to inbox
on error _errorMessage
my logToConsole("Error moving message to fallback generic inbox: " & _errorMessage)
end try
return
end try
my debugLogMessage("Moving to inbox " & my describeFolder(_inbox), _message)
move _message to _inbox
end tell
end moveToInbox
on destinationFolderForMessage(_message)
tell application "Microsoft Outlook"
set _inboxFolderName to name of _message's folder
set AppleScript's text item delimiters to ""
set _start to (length of gInboxSpamSieveName) + 1
set _destinationName to (characters _start through -1 of _inboxFolderName) as Unicode text
set _account to _message's account
if _account is missing value then
return mail folder _destinationName
else
try
tell _account
return mail folder _destinationName
end tell
on error -- If message is POP, the above won't search nested On My Computer folders, but this will.
return mail folder _destinationName
end try
end if
end tell
end destinationFolderForMessage
on moveToFolder(_message)
tell application "Microsoft Outlook"
try
set _folder to my destinationFolderForMessage(_message)
on error _errorMessage
my logToConsole("Error getting destination for message, so moving to inbox: " & _errorMessage)
my moveToInbox(_message)
return
end try
my debugLogMessage("Moving to folder " & my describeFolder(_folder), _message)
move _message to _folder
end tell
end moveToFolder
on moveToSpamFolder(_message)
tell application "Microsoft Outlook"
set _destFolder to my junkFolderForMessage(_message)
my debugLogMessage("Moving to junk mailbox " & my describeFolder(_destFolder), _message)
move _message to _destFolder
try
if _message's folder is not _destFolder then
my debugLogMessage("Removing to junk mailbox " & my describeFolder(junk mail), _message)
move _message to junk mail
end if
end try
end tell
end moveToSpamFolder
on junkFolderForMessage(_message)
tell application "Microsoft Outlook"
try
set _destFolder to junk mail of _message's account
if _destFolder is not missing value then return _destFolder
end try
try
set _destFolder to junk mail
if _destFolder is not missing value then return _destFolder
end try
try
set _destFolder to folder "Junk E-mail" of _message's account
if _destFolder is not missing value then return _destFolder
end try
try
set _destFolder to folder "Junk" of _message's account
if _destFolder is not missing value then return _destFolder
end try
display dialog "Could not find the “Junk E-mail” folder"
return junk mail
end tell
end junkFolderForMessage
on processGoodMessage(_message, _score)
my debugLogMessage("Predicted Good (" & _score & ")", _message)
tell application "Microsoft Outlook"
set _folderName to name of _message's folder
if _folderName is gInboxSpamSieveName then
my moveToInbox(_message)
else if _folderName starts with gInboxSpamSieveName then
my moveToFolder(_message)
else
if gGoodCategoryName is not "" then
my applyCategoryNamed(_message, gGoodCategoryName)
end if
if gGoodFolderName is not "" then
my moveToFolderNamed(_message, gGoodFolderName)
end if
end if
end tell
end processGoodMessage
on isSpamScoreUncertain(_score)
tell application "SpamSieve"
set _keys to {"Border", "OutlookUncertainJunk"}
set _defaults to {75, true}
try
set {gUncertainThreshold, gUncertainJunk} to lookup keys _keys default values _defaults
on error
set {gUncertainThreshold, gUncertainJunk} to _defaults
end try
end tell
return _score < gUncertainThreshold and gUncertainJunk
end isSpamScoreUncertain
on subjectOfMessage(_message)
tell application "Microsoft Outlook"
try
return (_message's subject) as Unicode text
on error
return "<Error getting subject of message id " & _message's id & ">"
end try
end tell
end subjectOfMessage
on moveToFolderNamed(_message, _folderName)
tell application "Microsoft Outlook"
try
move _message to folder _folderName of _message's account
on error _error
-- Folder probably doesn't exist. Not sure how to create it.
my logToConsole("Error moving to " & _folderName & ": " & _error)
end try
end tell
end moveToFolderNamed
-- Categories
on categoryForName(_categoryName)
tell application "Microsoft Outlook"
try
-- "exists category _categoryName" sometimes lies
return category _categoryName
on error
try
-- getting by name doesn't always work
repeat with _category in categories
if _category's name is _categoryName then return _category
end repeat
end try
set _category to make new category with properties {name:_categoryName}
if _categoryName is gGoodCategoryName then
set _category's color to {0, 0, 0}
end if
end try
return category _categoryName
end tell
end categoryForName
on applyCategoryNamed(_message, _categoryName)
tell application "Microsoft Outlook"
set _categoryToApply to my categoryForName(_categoryName)
set _categories to _message's category
repeat with _category in _categories
if _category's id is equal to _categoryToApply's id then return
end repeat
set category of _message to {_categoryToApply} & category of _message
end tell
end applyCategoryNamed
-- Logging
on debugLogMessage(_string, _message)
if not gDebug then return
tell application "Microsoft Outlook"
try
set _location to my describeFolder(_message's folder)
on error
set _location to "<error getting message's mailbox>"
end try
set _subject to my subjectOfMessage(_message)
end tell
my debugLog(_string & ": " & _location & "] " & _subject)
end debugLogMessage
on describeFolder(_folder)
tell application "Microsoft Outlook"
set _container to _folder's container -- For some reason, this doesn't work inside the "try"
try
set _containerName to my describeFolder(_container)
on error
try
return name of _folder's account
on error
return "[Unknown/OnMyComputer/Google]"
end try
end try
set _folderName to _folder's name
return _containerName & "/" & _folderName
end tell
end describeFolder
on debugLog(_message)
if gDebug then my logToConsole(_message)
end debugLog
on logToConsole(_message)
set _prefix to "SpamSieve [Outlook Filter Mailboxes]"
set _logMessage to _prefix & " " & _message
try
do shell script "/usr/bin/logger -s " & _logMessage's quoted form
on error _error number _errorNumber
set _alertMessage to "An error occurred while logging the message:" & return & return & _message & return & return & "to Console. Error " & _errorNumber & ": " & return & return & _error & return & return & "This error message will dismiss itself after 10 seconds so that your filtering is not interrupted."
display alert _prefix message _alertMessage giving up after 10
end try
end logToConsole
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
try
return lookup keys _keys default values _defaultValues
on error _errorMessage
my logToConsole("Error getting fallback defaults: " & _errorMessage)
return _defaultValues
end try
end try
end tell
end lookupDefaults