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 Mail.app 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](https://www.macsparky.com/blog/2021/8/my-free-apple-mail-seminar) 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 Mail.app

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>
											<key>FireType</key>
											<string>Pressed</string>
											<key>KeyCode</key>
											<integer>46</integer>
											<key>MacroTriggerType</key>
											<string>HotKey</string>
											<key>Modifiers</key>
											<integer>4096</integer>
										</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
					else
						
						-- Will create a New Macro Group to be used only within Mail.app
						set theMacroGroup to make new macro group with properties {name:theMacroGroupName, available application xml:"<dict>
					<key>Targeting</key>
					<string>Included</string>
					<key>TargetingApps</key>
					<array>
						<dict>
							<key>BundleIdentifier</key>
							<string>com.apple.mail</string>
							<key>Name</key>
							<string>Mail</string>
							<key>NewFile</key>
							<string>/System/Applications/Mail.app</string>
						</dict>
					</array>
				</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>
				<key>DisplayKind</key>
				<string>None</string>
				<key>HonourFailureSettings</key>
				<true/>
				<key>IncludeStdErr</key>
				<false/>
				<key>MacroActionType</key>
				<string>ExecuteAppleScript</string>
				<key>Path</key>
				<string></string>
				<key>Text</key>
				<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>
				<key>TimeOutAbortsMacro</key>
				<true/>
				<key>TrimResults</key>
				<true/>
				<key>TrimResultsNew</key>
				<true/>
				<key>UseText</key>
				<true/>
			</dict>"}
						end tell
					end tell
				end tell
			end repeat
			
			-- Resets account list for next Account iteration
			set mailboxList to {}
		else
			
		end if
	end repeat
end tell
5 Likes

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:

I just found this thread, while looking for a solution to the lack of support for SmallCube’s MailSuite in Mac Sonoma. Do you know if this still works, and if so, could it be modified to find folders “On My Mac”? I have an old POP system, and want to move emails to those folders, but since they aren’t attached to any account, they don’t come up as choices when the script cycles through the folders.

Have you guys checked out Mail Butler? Just a thought

Since this post, I’ve created an Alfred Workflow (see GitHub repo here) to perform this very task with the advantage of using Alfred’s search algorithm to surface the most used folders to the top of the list. If you do decide go this way, make sure to download the JSON Helper app for AppleScript (free on Mac Apple Store). Instructions and links are described on the GitHub page.

It basically work along the lines of a (very) paired down MsgFiler.

So, I no longer use these Keyboard Maestro Macros, but I guess they do work, since the AppleScript commands for Mail are still usable on Mail.app accounts (except for Gmail accounts that have some weird ways of handling on the backend).

1 Like

Very cool. Alfred’s ML is a big plus. I also noticed that, with multiple accounts, your workflow knows which Archive folder to use. IIRC that was something that stumped the last KM macro I tried to use.

Very well done and thank you for sharing :+1:

1 Like

Mail Butler can’t move messages to folders. It does lots of other stuff, but not that.