In one of my previous articles I made an AppleScript to export emails from Mail to eml. I stressed the importance for having a framework instead of using unstructured code. The benefit of having a simple framework means that adapting the AppleScript for Outlook is very simple.
Here is the framework again:
- Get some emails. I'll start with the selected emails.
- Do a loop with the emails I have.
- Get some data out of an email.
- Prepare the data for writing to a file.
- Create a file for writing.
- Write the data to a file.
I need to change only part 1 of getting emails from Outlook and part 3 of getting data out of the email. The rest can stay as is.
Get the email selection from Outlook
Getting the selection works like in Mail. If no email is selected then I need to check against "missing value". However, in Outlook it's also possible to select a mailbox. Therefore, I also need to check if the class of the selection selection is "mail folder":
set selectedMessages to selection
if selectedMessages is missing value or class of selectedMessages is mail folder then
display dialog "Please select an email first!"
return
end if
Get some data out of an email for Outlook
Getting the data of the email works almost like in Mail. Mail uses "date received" for all emails. Outlook uses "time received" for incoming emails and "time sent" for sent email. If there is no "time received" then the script uses "time sent". Again the value is checked against "missing value":
set theSubject to subject of theMessage
set theSource to source of theMessage
set theDate to time received of theMessage
if theDate is missing value then
set theDate to time sent of theMessage
end if
This is all that needs to be changed!
The finished script for exporting emails out of Outlook
And now I already have the finished script:
use framework "Foundation"
use scripting additions
property maxLength : 250
property FileEnding : ".eml"
tell application "Microsoft Outlook"
--check if there is an email selected
set selectedMessages to selection
if selectedMessages is missing value or class of selectedMessages is mail folder then
display dialog "Please select an email first!"
return
end if
repeat with theMessage in selectedMessages
--get basic data
set theSubject to subject of theMessage
set theSource to source of theMessage
set theDate to time received of theMessage
if theDate is missing value then
set theDate to time sent of theMessage
end if
--prepare data for writing
set theSubject to my replace_chars(theSubject, ":", "_")
set theSubject to my format_date(theDate) & " " & theSubject
set theSubject to my get_string_with_maxlength(theSubject)
--use file on desktop
set this_file to (((path to desktop folder) as string) & theSubject & ".eml")
--write data to file
my write_to_file(theSource, this_file, true)
end repeat
end tell
--format the date of the email: makes an sql date type out of the date 2022-08-10
on format_date(theDate)
set theYear to year of theDate
set theMonth to (month of theDate) as integer
set theDay to day of theDate
return (theYear & "-" & theMonth & "-" & theDay) as string
end format_date
--write data to file
on write_to_file(this_data, target_file, append_data)
tell application "Finder"
try
set the target_file to the target_file as string
set the open_target_file to open for access file target_file with write permission
if append_data is false then set eof of the open_target_file to 0
write this_data to the open_target_file as «class utf8» starting at eof
close access the open_target_file
return true
on error errMsg number errNr
try
display dialog errMsg & " Nr.: " & errNr
close access file target_file
end try
return false
end try
end tell
end write_to_file
--replace characters in text
on replace_chars(this_text, search_string, replacement_string)
set AppleScript's text item delimiters to the search_string
set the item_list to every text item of this_text
set AppleScript's text item delimiters to the replacement_string
set this_text to the item_list as string
set AppleScript's text item delimiters to ""
return this_text
end replace_chars
on get_string_with_maxlength(theText)
--get the full length of the string first
set theLength to my get_precomposed_length(theText) as number
if theLength ≤ maxLength then return theText
--split the string into characters
set TextAsArray to my split_string(theText, "")
--for each character get the length
set CharacterLengths to {}
repeat with theChar in TextAsArray
set CharLength to my get_precomposed_length(theChar)
set end of CharacterLengths to CharLength
end repeat
--concatenate characters and count the length of the characters
set currentLength to 0
set Counter to 1
set theText to ""
repeat while currentLength < maxLength
set currentLength to (item Counter of CharacterLengths) + currentLength
set theText to theText & item Counter of TextAsArray
set Counter to Counter + 1
end repeat
return theText
end get_string_with_maxlength
--convert the string to precomposed and get the length of the string
on get_precomposed_length(theText)
set theApp to a reference to current application
set theNSString to theApp's NSString's stringWithString:theText
set theMutableNSString to theApp's NSMutableString's stringWithString:(theNSString's decomposedStringWithCanonicalMapping())
return theMutableNSString's |length|() as text
end get_precomposed_length
on split_string(theString, theDelimiter)
-- save delimiters to restore old settings
set oldDelimiters to AppleScript's text item delimiters
-- set delimiters to delimiter to be used
set AppleScript's text item delimiters to theDelimiter
set theArray to every text item of theString
-- restore the old setting
set AppleScript's text item delimiters to oldDelimiters
return theArray
end split_string