Hi there,
I need a little help with scripting of Apple Mail.
I’m looking for a script, that is attached to an Apple Mail rule and saves every incoming Mail as .eml on HD.
Can anybody help me with that?
Thank you
Carl
Browser: Safari 605.1.15
Operating System: macOS 10.14
I written 2 scripts for Mail.app rules as far. The first saves chozen message as EML. The second creates mail rule programatically. Understand the idea of this 2 scripts to adapt for your needs:
-- Script: save email as EML file
-- get name and source of chosen message
tell application "Mail"
set aMessage to item 1 of (get selection)
set richSource to (source of aMessage) as rich text
set theSubject to subject of aMessage
end tell
-- replace every ":" symbol in theSubject with "_"
set {ATID, AppleScript's text item delimiters} to {AppleScript's text item delimiters, ":"}
set {itemList, AppleScript's text item delimiters} to {text items of theSubject, "_"}
set {theSubject, AppleScript's text item delimiters} to {itemList as text, ATID}
-- build destination file's HFS path
set outputFile to (((path to desktop folder) as text) & theSubject & ".eml")
-- write rich text to EML file
try
set fileReference to open for access file outputFile with write permission
set eof of fileReference to 0
write richSource to fileReference
close access fileReference
on error
try
close access file outputFile
end try
end try
-- Script: make new rule programatically
set ruleConditionAccountConstant to «constant eruttacc»
tell application "Mail"
tell (make new rule with properties {name:"Delete Apple Support Commubities thread intrusive messages", delete message:true, all conditions must be met:true})
make new rule condition with properties {rule type:ruleConditionAccountConstant, expression:"imap://kniazidis.rompert%40gmail.com/"}
set its enabled to true
set stop evaluating rules to false
end tell
save
end tell
Creating the rule programatically you can avoid, using manual way. Steps:
- Choose “if all of the following conditions is meat”
- Choose “message is addressed to my full name”
- Choose “Run Applescript”
- Then you should attach to this rule following script, which uses idea of my script 1 (save it to Mail actions scripts location before the attaching):
using terms from application "Mail"
on perform mail action with messages these_messages for rule this_rule
tell application "Mail"
repeat with eachMessage in these_messages
set richSource to (source of eachMessage) as rich text
set theSubject to subject of eachMessage
set outputFile to my buildEMLfilePath(theSubject)
my writeToEmlfile(richSource, outputFile)
end repeat
end tell
end perform mail action with messages
end using terms from
on buildEMLfilePath(theSubject)
-- replace every ":" symbol in theSubject with "_"
set {ATID, AppleScript's text item delimiters} to {AppleScript's text item delimiters, ":"}
set {itemList, AppleScript's text item delimiters} to {text items of theSubject, "_"}
set {theSubject, AppleScript's text item delimiters} to {itemList as text, ATID}
-- build destination file's HFS path
set outputFile to (((path to desktop folder) as text) & theSubject & ".eml")
end buildEMLfilePath
on writeToEmlfile(richSource, outputFile)
-- write rich text to EML file
try
set fileReference to open for access file outputFile with write permission
set eof of fileReference to 0
write richSource to fileReference
close access fileReference
on error
try
close access file outputFile
end try
end try
end writeToEmlfile
Thank you KniazidisR very much.
Just to check, if I understand it correctly…
The script for creating the rule is just an example to help me build a script with rules that fit my needs?
Cheers
Carl
Yes. Better, make rule manually, to not open one other topic, related to programatically creating the rule and activating it.
Here is one new rule I created using the Mail.app Preferences–>Rules–>Add Rule. As you see I used “Every message” instead of “message is addressed to my full name”.
“ExportAsEMLfile.scpt” is name of the script above (last script of the post #2). I stored it in the Mail action scripts location. On my Mac it is “/Users/123/Library/Application Scripts/com.apple.mail/”
POSIX path of (((path to library folder) as text) & "Application Scripts:com.apple.mail:")
This is a script that I use to save selected email messages in .eml format in Apple Mail. I use it on both incoming and outgoing messages. I haven’t adapted it to work based on a Mail rule on all incoming email, but you may be able to do that. I trigger it with a keyboard shortcut on the emails I want to save. I’d be interested in how you get on with using it with a Mail rule.
A few notes:
- The script saves the message/s that is selected in the first message viewer window. If you have multiple message viewer windows open, or multiple messages open, you may get unexpected results if you don’t keep that fact in mind that the script will just save the messages that are selected in the first message viewer window.
- The script uses GUI scripting to save the email. I don’t know any way around this but would love to hear of it if others know more. This means that you’ll need to give accessibility access in System Preferences to whatever app you use to trigger the script. It also means that your Mac will jump around visibly doing something when the script is triggered which might be a bit distracting if you have it set with a Mail rule to trigger on every incoming email.
- If you use the Small Cubed Mail Suite/MailTags plug in, like I do, the script will put the project name of the message in the file name. If you don’t have the plug in, it should just omit it with no issues.
I’m currently running it on macOS 11.2, but have been using versions of this script for a few years on various versions of macOS including Mojave and earlier.
-- save selected email messages in the Downloads folder
-- Version 1.2, 28 February 2021
-- Copyright 2017 by Nicholas Parsons
-- declare a proprety for where the email message will be saved
property theLocation : missing value
try
-- set theLocation if it hasn't already been set
if theLocation is missing value then set theLocation to choose folder with prompt "Choose where you want your emails to be saved."
-- if the user cancels it should trigger an error number -128 which will end execution of the script
set theLocation to POSIX path of theLocation
-- try to get the selected messages from the frontmost window of Mail
with timeout of 10 seconds
tell application "Mail" to set selectedMessages to the selected messages of message viewer 1
end timeout
-- only proceed if some messages have been selected
if selectedMessages is not missing value then
-- take the first message selected and extract the relevant info
set theSender to getSender for item 1 of selectedMessages
set theRecipient to getRecipient for (item 1 of selectedMessages)
tell application "Mail" to set theDate to the date sent of item 1 of selectedMessages
set theProject to getProject for (item 1 of selectedMessages)
set theSubject to getSubject for (item 1 of selectedMessages) given project:theProject
else -- there are no messages selected
display notification "No email messages selected." with title "Select a message first"
error number -128
end if -- there are some selected messages
-- generate a file name for the email
set fileName to getDateString(theDate) & " Email from " & theSender & theRecipient & " about " & theSubject & ".eml"
log fileName
saveEmail to fileName
on error errorMessage number errorNumber
if errorNumber is not -128 then display notification errorMessage & return & return & "Error " & errorNumber with title "Whoops, something went wrong" sound name "Basso"
end try
on getDateString(theDate)
-- get the day of the given date in a two digit format
try
if (day of theDate) is less than 10 then
set dayString to 0 & (day of theDate as string)
else
set dayString to (day of theDate as string)
end if
on error
set dayString to "xx"
end try
-- get the month of the given date in a two digit format
try
if (month of theDate as number) is less than 10 then
set monthString to 0 & (month of theDate as number)
else
set monthString to (month of theDate as number)
end if
on error
set monthString to "xx"
end try
-- generate a date string in yyyy-mm-dd format
try
set dateString to (year of theDate as string) & "-" & monthString & "-" & dayString
on error
display notification "Some data that was expected to be a date was not in fact a date." with title "Whoops, something went wrong"
set dateString to "xxxx-" & monthString & "-" & dayString
end try
return dateString
end getDateString
on getSender for thisMessage
tell application "Mail" to set theSender to extract name from the sender of thisMessage
log theSender
return theSender
end getSender
on getRecipient for thisMessage
tell application "Mail" to tell thisMessage
-- try to get the name of the first recipient of the email
if the (count of to recipients) is 1 then
set theRecipient to the name of the first to recipient
else -- if there are more than one recipients
set theRecipient to (the name of the first to recipient) & " et al"
end if
log theRecipient
-- If the recipient was just an email address with no name, it will now be missing value. IN this case, we will leave it as an empty string.
if theRecipient is missing value then
set theRecipient to ""
else -- if there is a recipient, format it for inclusion in the file name
set theRecipient to " to " & theRecipient
end if
end tell
return theRecipient
end getRecipient
on getSubject for thisMessage given project:theProject
tell application "Mail" to set theSubject to the subject of thisMessage
-- get rid of any leading "Re:" or "Fwd" from the email subject
if theSubject is not missing value and theSubject is not "" then
try
if text 1 through 5 of theSubject is "Fwd: " then set theSubject to text 6 through -1 of theSubject
repeat while text 1 through 4 of theSubject is "Re: " or text 1 through 4 of theSubject is "RE: " or text 1 through 4 of theSubject is "FW: "
set theSubject to (text 5 through -1 of theSubject) as text
end repeat
end try
end if -- theSubject is missing value or empty string
-- if the messsage has a project that isn't referenced in it's subject line, get it to append to the end of the file name
if theSubject is missing value then
if theProject is missing value then
set theSubject to "missing value"
else -- there's a project
set theSubject to theProject
end if -- there's no project
else if not ((theProject is missing value) or (theSubject contains the last word of theProject)) then
set theSubject to theSubject & " – " & theProject
end if -- no subject
log theSubject
return theSubject
end getSubject
on getProject for thisMessage
-- get the MailTags project of the email
tell application "Mail"
try
tell application "SmallCubed MailSuite" to set theProject to the project of thisMessage
on error
set theProject to missing value
end try
end tell
return theProject
end getProject
on saveEmail to fileName
-- save the email message
with timeout of 10 seconds
log "Saving email"
tell application "Mail" to activate
-- send commands through System Events for GUI scripting
tell application "System Events" to tell application process "Mail"
-- trigger save as keystroke
keystroke "s" using {command down, shift down}
-- wait for the save sheet to appear
with timeout of 5 seconds
repeat until sheet 1 of window 1 exists
end repeat
end timeout
delay 0.5
tell sheet 1 of window 1
-- set the file name
if the fileName is not "" then set value of text field 1 to the fileName
delay 0.2
-- set the save in location
keystroke "g" using {command down, shift down}
with timeout of 5 seconds
repeat until sheet 1 exists
end repeat
end timeout
-- check what version OS is running
-- In macOS Sierra, the location field is a combo box. In earlier versions, it was a text field.
tell sheet 1
if my macOSIsNewerThan("10.12") then
set the value of combo box 1 to theLocation
else
set the value of text field 1 to theLocation
end if
click button "Go" -- to set the location
-- do something to check that the path has been entered correctly and the dialog dismissed
end tell -- go to sheet
-- Prior to High Sierra, the "Save" button was button 1. In High Sierra, it's no longer button 1, but it is the last UI element
if my macOSIsNewerThan("10.13") then
click the last UI element -- to save
else
click button 1 -- to save
end if
end tell -- sheet 1/save dialog
end tell -- System Events/Mail
end timeout
display notification "Message Saved" with title "The email message has been saved in Downloads folder." sound name "Glass"
end saveEmail
on macOSVersion()
set theInfo to system info
set theVersion to system version of theInfo
-- when running this script in ScriptDebugger system info still reports macOS 11 Big Sur as version 10.16
-- but when running it from KM (I think) it reports it as 11.x
return theVersion
end macOSVersion
on macOSIsNewerThan(specifiedVersion)
set usersVersion to macOSVersion()
considering numeric strings
return usersVersion is greater than or equal to specifiedVersion
end considering
end macOSIsNewerThan
(* change log
##New in Version 1.2##
* updated for compatibility with macOS Big Sur
* refactored
*)