Hi All,
For those who’d like it, here’s a nifty script for marking all messages as read. One catch though, it’s too damn slow…
Can anyone tell me why Mail is so slow to mark messages as read? I get that it has to search the whole mailbox to find unread messages before it can mark them as read, but once it starts marking them as read, it’s so painfully slow, marking about 4 messages per second. The same happens if I simply do the inbox like,
tell application "Mail" to set read status of every message of inbox to true
Why is it that I can select a arbitrary number of messages manually and mark them all nearly instantaneously, but using applescript it can’t reproduce that behavior? With how slow this is, it would be faster to GUI script Mail to activate each mailbox, select all, and hit the mark as read hotkey.
Thoughts?
Thanks,
Tim
on run
tell application "Mail" to set AllAccounts to every account
repeat with AnAccount in AllAccounts
tell application "Mail"
set TheMailboxes to every mailbox of AnAccount
end tell
repeat with TheMailbox in TheMailboxes
try
tell application "Mail"
if unread count of TheMailbox > 0 then set (read status of every message of TheMailbox whose read status is false) to true
end tell
end try
end repeat
end repeat
return 0
end run
So the slowness issue disappears if an account is offline, so it seems to be related to Mail syncing with the account (IMAP and iCloud accounts, at least) after it changes each message’s read status. So the obvious solution is to take an account offline before you marked its messages as read, except that particular function isn’t scriptable for some odd reason. You can disable the account, but then you lose access to its messages too, so that’s no good.
Enter GUI scripting (sigh…). Here’s an updates version that is WAY faster, marking hundreds of messages a second instead of 3 or 4. The overkill GUI scripting is to try and overcome its finickiness. Here’s two versions, one with no display of any kind, and another that shows Mr. Stanley’s awesome progress bar for you.
Takes less than 2 seconds to run if there’s no unread messages for my 70 mailboxes and 30000 messages. took a little over a minute to mark ~1000 messages as read amongst all the mailboxes. The more unread messages, and the more messages that are in the mailbox with the unread ones, the longer it will take to get the list of messages to mark.
Simple version:
on run
tell application "Mail" to set AllAccounts to every account
set AccountNum to 1
set AccountsOnline to true
repeat with AnAccount in AllAccounts
tell application "Mail"
set TheMailboxes to every mailbox of AnAccount
end tell
repeat with TheMailbox in TheMailboxes
try
with timeout of 600 seconds
tell application "Mail"
if unread count of TheMailbox > 0 and (name of TheMailbox does not contain "Draft") then
if AccountsOnline then
tell application "System Events" to tell process "Mail"
repeat 10 times
try
click menu item "Take All Accounts Offline" of menu "Mailbox" of menu bar 1
end try
end repeat
end tell
delay 1
set AccountsOnline to false
end if
set (read status of every message of TheMailbox whose read status is false) to true
end if
end tell
end timeout
end try
end repeat
set AccountNum to AccountNum + 1
end repeat
if not AccountsOnline then
tell application "System Events" to tell process "Mail"
repeat 10 times
try
click menu item "Take All Accounts Online" of menu "Mailbox" of menu bar 1
end try
end repeat
end tell
end if
return 0
end run
ASObjC Runner progress window version (Go Shane!!):
on run
tell application "Mail" to set AllAccounts to every account
set BoxCount to 0
repeat with AnAccount in AllAccounts
tell application "Mail" to set BoxCount to BoxCount + ((count of every mailbox) of AnAccount)
end repeat
tell application "ASObjC Runner"
reset progress
set properties of progress window to {name:"Mark All Read", message:"Marking all messages as read. Press Cancel to quit.", max value:BoxCount, current value:0, button visible:true, button title:"Cancel"}
show progress
activate
end tell
set BoxNum to 1
set AccountNum to 1
set AccountsOnline to true
repeat with AnAccount in AllAccounts
tell application "Mail"
set AccountName to name of AnAccount
set TheMailboxes to every mailbox of AnAccount
end tell
repeat with TheMailbox in TheMailboxes
tell application "Mail" to set CurrentBox to (AccountName & "'s " & name of TheMailbox)
tell application "ASObjC Runner"
set properties of progress window to {current value:BoxNum, detail:"Processing " & CurrentBox}
if button was pressed of progress window then
hide progress
return 0
end if
end tell
try
with timeout of 600 seconds
tell application "Mail"
if unread count of TheMailbox > 0 and (name of TheMailbox does not contain "Draft") then
if AccountsOnline then
tell application "System Events" to tell process "Mail"
repeat 10 times
try
click menu item "Take All Accounts Offline" of menu "Mailbox" of menu bar 1
end try
end repeat
end tell
delay 1
set AccountsOnline to false
end if
set (read status of every message of TheMailbox whose read status is false) to true
end if
end tell
end timeout
end try
set BoxNum to BoxNum + 1
end repeat
set AccountNum to AccountNum + 1
end repeat
if not AccountsOnline then
tell application "System Events" to tell process "Mail"
repeat 10 times
try
click menu item "Take All Accounts Online" of menu "Mailbox" of menu bar 1
end try
end repeat
end tell
end if
tell application "ASObjC Runner" to hide progress
return 0
end run