An AppleScript way to create Keyboard Maestro Macros to implement MacSparky's move to shortcuts

@Macsparky’s idea of using the same “Move” shortcut (^M) combined with a Keyboard Maestro Pallete is really something. But the prospect of creating and changing each rule to be somewhat tedious.

So I’ve hacked my way with AppleScript to automate the creation of these macros. (It would probably be easier to create them manually instead of figuring out the code, but what’s the fun in that?)

It will fetch a list of the folders (mailboxes in Mail parlance) for each of your accounts and ask for which ones you would like to create Macros for.

I’m sure there are many ways that this code coud be better more efficient, but hey… I’m not a dev myself and it worked fine for me. Hope it can help someone as well and, please, feel free to improve on it.

UPDATED: Added a step to select the desired accounts, to work around issue raised by @dennis bellow

-- Based on @MacSparky['s idea]( of using the `⌃M` shortkey to trigger a Conflict Pallete on Keyboard Maestro that will filter Macros to Move Messages to specific folders on macOS

use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

How this script works:
 0. Please set the variables bellow
 1. Gets the list of Accounts in Mail.App and asks to point which ones should be scanned
 2. Loops for each selected account
 	2.1. Creates a list of every mailbox on that account
 	2.2. Asks for user selection of desired mailboxes on that list
 	2.3. Creates the corresponding set of Macros for Keyboard Maestro

-- Parameters to set up
## The Keyboard Maestro Macro Group Name (will be created if there is no such group yet).
set theMacroGroupName to "Mail Moves"

## The Keyboard Maestro Trigger
-- Keyboard Maestro sets the contents of its items properties via xml dictionaries. It's easier to copy and paste its contents from a example in Keyboard Maestro Editor window and its menu (Edit > Copy as > Copy as XML)
-- Here's the XML for using ⌃M as a trigger for this macro
set theXMLfortheTrigger to "<dict>

# The script itself

-- Scafolding, do not bother
set accountList to {}
set mailboxList to {}

tell application "Mail"
	-- Creates account List
	set allAccounts to every account
	repeat with eachAccount in allAccounts
		set the end of accountList to (name of eachAccount)
	end repeat
	-- Chooses desired Accounts from accountlist		
	set selecterAccounts to choose from list accountList with title ("Pick the desired accounts") with multiple selections allowed
	-- Loops for each account
	repeat with eachAccount in selecterAccounts
		set thisAccount to account named eachAccount
		-- Fetches the names for account mailboxes (folders) to create a list
		set accountMailboxes to every mailbox of thisAccount
		repeat with eachMailbox in accountMailboxes
			set the end of mailboxList to (name of eachMailbox)
		end repeat
		-- Chooses desired Mailboxes from that list		
		set selectedMailboxes to choose from list mailboxList with title ("Pick the desired mailboxes from " & eachAccount) with multiple selections allowed
		-- This if statement to allow for no selection to be passed via the Cancel button
		if (count of selectedMailboxes) > 0 then
			-- Loops the selected Mailboxes to create their corresponding Macros on Keyboard Maestro
			repeat with theMailbox in selectedMailboxes
				set theMailbox to theMailbox
				set theMacroName to "Move to " & eachAccount & " - " & theMailbox
				-- Will use the Keyboard Maestro Editor NOT the Engine
				tell application "Keyboard Maestro"
					-- Creates a Macro Group if there isn`t one named as intended.
					if macro group theMacroGroupName exists then
						set theMacroGroup to macro group theMacroGroupName
						-- Will create a New Macro Group to be used only within
						set theMacroGroup to make new macro group with properties {name:theMacroGroupName, available application xml:"<dict>
					end if
					-- Creates the Macro	
					tell theMacroGroup
						-- Creates new macro
						set theMacro to make new macro with properties {name:theMacroName}
						-- Uses a tell command to address the new Macro
						tell theMacro
							-- Creates the Trigger from the XML provided above
							make new trigger with properties {xml:theXMLfortheTrigger}
							-- Creates the AppleScript Action
							make new action with properties {xml:"<dict>
				<string>tell application \"Mail\"
		    set selMessage to selection
		    set thisMessage to item 1 of selMessage
		    set mailbox of thisMessage to mailbox \"" & theMailbox & "\" of account \"" & eachAccount & "\"
		    display notification with title \"Message Moved to " & eachAccount & " " & theMailbox & "\"
		end tell</string>
						end tell
					end tell
				end tell
			end repeat
			-- Resets account list for next Account iteration
			set mailboxList to {}
		end if
	end repeat
end tell

This is super cool! I got it to work on three of my seven email accounts in Apple Mail. Then I received this error:

error “Mail got an error: List is empty.” number -50

It would be great if there was a way to run the script again and have it skip the accounts already setup.

I’m impressed who it ran and setup the three that it did. Nice work!

A workaround would be to use the same list strategy to pick the Accounts in a previous step.

Changed that to the original post and I think it should work!

Yeah, I ended up using copy/paste from the one’s that did work. Thanks for sharing!

Just implemented this. And it is great! I’ve been looking for a way to do this for a long time. Kudos!

Now, if there were a way to have it operate on multiple-selected emails at the same time… :grinning: