Mailsmith
Other Programs
Scripts
Mailsmith.scpt
Archive to sub-mailbox
Check Spelling
Find reply
Change font size
Submit Script to JEM
Fix common spelling errors
Setting SMTP server
URL from Safari
Address from AB
linkMunge
Export to Address Book
Saving attachments
Digest Script
File with same
POP window position
Position of new windows
iCal and Mailsmith
Edit From Line
Modified Thread Script
Reply to Selection
Temporary Text Window
Compact gain
Tracking backups
Edit subject
Googler
Auto-rewrap
MMA
SMTP server
Open, fetch, and close
URL Manager
BrainForest
Thread by Author
Thread by subject
Export Email
Get Selection
Read Addresses
Export Email
Organize Email
Account setup
Mailsmith 2 BBEdit
BBEdit 2 Mailsmith
Search II
Check One
Delete Enclosure
Open, fetch, close
Set Answered
Set Redirected
Empty Trash
List found
Print Several
Del. old. msg.
Delete Enclosures
Accounts
Address Book
Editing
Filters
General
Import/Export
Links
Mailboxes
Memory
Scripting
Speed
send/receive
Tips/Tricks


File with same

Author Anton Rang
Last modified 2003-01-12
What is this?

The following script should, more or less, be what you want. It acts on one or more selected messages, and does the following:

  1. Groups the messages by thread;
  2. For each thread:
    1. locates all mailboxes containing messages from that thread, excluding the current mailbox;
    2. sorts the mailbox list by number of messages, then by name;
    3. allows you to choose a mailbox from the list (if only one, that's the default, so you can just hit enter);
    4. moves the messages there (unless you choose to cancel).

Tested (somewhat) with Mailsmith 1.5 on Mac OS X 10.2.3. It's not incredibly fast (be patient while it searches for messages with matching subjects) but it should still be a timesaver over doing this manually.

For fun, try it on a message with no subject, and you'll be able to see how many messages without subjects you have in each mailbox....

-- Anton

P.S. This will probably get word-wrapped in annoying ways. Sorry about that. Might take a little tweaking until it compiles in script editor, hopefully it will be obvious where the wraps occurred.

P.P.S. It probably wouldn't be too hard to exclude particular mailboxes, like the trash or inboxes, but I didn't. It's already pretty long. face_smile


tell application "Mailsmith 1.5"
    set msglist to my currentMessages()
    if msglist = {} then
        display dialog "This script requires one or more selected messages." buttons "Cancel" default button 1
        return
    end if
    set msglist to my getThreads(msglist)
    if (count of msglist) > 1 then
        set msglist to my quicksort(msglist, msg_compare)
    end if
    set msglist to my mergethreads(msglist)
    set mbox_list to my buildMailboxList()
    repeat with msggroup in msglist
        set newmbox to my findmatchingmbox(mbox_list, thr of msggroup, container of item 1 of msgs of msggroup)
        if newmbox is not null then
            move (msgs of msggroup) to newmbox
        end if
    end repeat
end tell

on currentMessages()
    tell application "Mailsmith 1.5"
        activate
        set retry to false
        try
            set the_list to get selection as list
            set m to item 1 of the_list
            if class of m is not message then set retry to true
        on error
            set retry to true
        end try
        if retry then
            set retry to false
            try
                set the_list to message of window 1 as list
                set ignore to (thread title of item 1 of the_list) -- catch cases where we didn't get a message
            on error
                set retry to true
            end try
        end if
        if retry then set the_list to {}
    end tell
    return the_list
end currentMessages

on getThreads(msglist)
    set newlist to {}
    tell application "Mailsmith 1.5"
        repeat with msg in msglist
            set rec to {msg:msg, thr:thread title of msg}
            set newlist to newlist & {rec}
        end repeat
    end tell
    return newlist
end getThreads

on buildMailboxList()
    tell application "Mailsmith 1.5"
        set l to mailboxes
        set ct to count of l
        repeat with i from 1 to ct
            set mb to item i of l
            set l to l & my scanMailbox(mb)
        end repeat
    end tell
end buildMailboxList

on scanMailbox(mbox)
    tell application "Mailsmith 1.5"
        set l to (mailboxes of mbox)
        set ct to count of l
        repeat with i from 1 to ct
            set mb to item i of l
            set l to l & my scanMailbox(mb)
        end repeat
    end tell
    return l
end scanMailbox

on quicksort_internal(the_list, sort_list, comparison)
    if (length of sort_list) is less than or equal to 1 then
        return sort_list
    else
        local pivot, pivot_value, list1, list2
        set pivot to some item of sort_list
        set pivot_value to contents of (item pivot of the_list)
        set list1 to {}
        set list2 to {}
        repeat with entry in sort_list
            set entry to contents of entry
            if entry is not equal to pivot then
                tell comparison to compare_items((item entry of the_list), pivot_value)
                if the result < 0 then
                    set list1 to list1 & {entry}
                else
                    set list2 to list2 & {entry}
                end if
            end if
        end repeat
        set list1 to quicksort_internal(the_list, list1, comparison)
        set list2 to quicksort_internal(the_list, list2, comparison)
        return list1 & {pivot} & list2
    end if
end quicksort_internal

on quicksort(the_list, comparison)
    local sort_list, new_list, n
    if class of the_list is not list then
        error "Expected list"
    end if
    if class of comparison is not script then
        error "Bad comparison operator"
    end if
    
    set n to length of the_list
    set sort_list to {}
    repeat with i from 1 to n
        set sort_list to sort_list & i
    end repeat
    set sort_list to quicksort_internal(the_list, sort_list, comparison)
    set new_list to {}
    repeat with i from 1 to n
        set new_list to new_list & {(item (item i of sort_list) of the_list)}
    end repeat
    return new_list
end quicksort

script msg_compare
    to compare_items(left_item, right_item)
        local left_name, right_name
        set left_name to thr of left_item
        set right_name to thr of right_item
        if (left_name < right_name) then
            return -1
        else if (left_name > right_name) then
            return 1
        else
            return 0
        end if
    end compare_items
end script

script match_compare
    to compare_items(left_item, right_item)
        local left_name, right_name, diff
        set diff to (ct of right_item) - (ct of left_item) -- sense is reversed to sort high counts first
        if diff is not 0 then return diff
        set left_name to name of mbox of left_item
        set right_name to name of mbox of right_item
        if (left_name < right_name) then
            return -1
        else if (left_name > right_name) then
            return 1
        else
            return 0
        end if
    end compare_items
end script

on mergethreads(msglist)
    set ct to count of msglist
    if ct = 1 then
        return {{thr:(thr of item 1 of msglist), msgs:{msg of item 1 of msglist}}}
    end if
    set mergedlist to {}
    set msglist to msglist & {{thr:null, msg:null}}
    set curthr to (thr of item 1 of msglist)
    set curmsglist to {}
    repeat with m in msglist
        set newthr to thr of m
        if (newthr is not equal to curthr) then
            set mergedlist to mergedlist & {{thr:curthr, msgs:curmsglist}}
            set curthr to newthr
            set curmsglist to {msg of m}
        else
            set curmsglist to curmsglist & {msg of m}
        end if
    end repeat
    return mergedlist
end mergethreads

on findmatchingmbox(mbox_list, thr, exclude)
    tell application "Mailsmith 1.5"
        activate
        set matchlist to {}
        repeat with mb in mbox_list
            if (name of mb is not equal to name of exclude) then
                set mm to (messages in mb whose thread title is thr)
                set ct to count of mm
                if ct is not 0 then
                    set str to name of mb & ": " & ct
                    set matchlist to matchlist & {{mbox:mb, ct:ct, str:str}}
                end if
            end if
        end repeat
        if matchlist = {} then
            display dialog "No mailboxes found containing thread '" & thr & "'"
            return null
        end if
        if (count of matchlist) > 1 then
            set matchlist to my quicksort(matchlist, match_compare)
        end if
        set choicelist to {}
        repeat with m in matchlist
            set choicelist to choicelist & {str of m}
        end repeat
        if ((count of choicelist) = 1) then
            set choice to choose from list choicelist with prompt ("Choose destination for thread '" & thr & "'") default items choicelist
        else
            set choice to choose from list choicelist with prompt ("Choose destination for thread '" & thr & "'")
        end if
        if (choice = false) then
            return null
        else
            set choice to item 1 of choice
            repeat with m in matchlist
                if (choice = str of m) then
                    return (mbox of m)
                end if
            end repeat
        end if
    end tell
    return null -- not found, strange
end findmatchingmbox