In the article Exporting emails from Mail I used 3 different methods to export emails out of Mail:
- Export the emails to mbox.
- Make a copy of the emails.
- Drag the emails to the Finder.
Today I'm going to use AppleScript to also export the emails. As always I start with a simple script and make that more complex.
One of the criteria for evaluating the different methods for exporting was speed. Whatever I read about Monterey being faster with AppleScript this is not true for Mail. Any AppleScript is dog slow in Mail. For testing I'm going to start with the selection of emails and not a complete mailbox.
In an application I can have lots of options like for creating PDFs in Mail Archiver:

I can try to do similar options in AppleScript. But there the code gets unwieldy pretty quickly.
The tasks for exporting emails from Mail
Here is what I need to do:
- 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 will now go over every step.
Get some emails to export
As mentioned above AppleScript for Mail is slow. It's not fun to export thousands of emails. Therefore I'm going to start with the selection and will select about 6-10 emails for testing:
set SelectedMessages to (get selection)
if SelectedMessages = {} then
display dialog "Please select an email first!"
return
end if
Doing a loop with the emails
Doing the loop is easy:
repeat with theMessage in SelectedMessages
-- do something with the email theMessage
end repeat
Get some data out of an email
What data do I need from the email? For starting out I need the subject of the email because that is going to be the filename. Then I need the source for the content of the email:
set theSubject to subject of theMessage
set theSource to source of theMessage as Unicode text
Because I want to get all special characters of the emails I use "as Unicode text".
Prepare the data for writing
Subjects can contain any character. However, macOS doesn't allow the ":" in a filename. Therefore, the ":" character needs to be replaced:
set theSubject to my replace_chars(theSubject, ":", "_")
I have used the function replace_chars before so I'll only post it below.
Create a file for writing
For testing I'll use the desktop. But I could easily exchange the folder with another one or use a folder selection dialog. And then I make a file in the folder with the name of subject + file ending "eml":
set this_file to (((path to desktop folder) as string) & theSubject & ".eml")
Write the data to a file
The final step is to write the data to the file:
my write_to_file(theSource, this_file, true)
Like the replace_chars function I've used write_to_file before.
Full script so far
Here is what I have done so far with the 2 helper functions for replacing text and writing data to a file:
tell application "Mail"
--check if there is an email selected
set SelectedMessages to (get selection)
if SelectedMessages = {} 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 as Unicode text
--prepare data for writing
set theSubject to my replace_chars(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
--routine for writing data to file
on write_to_file(this_data, target_file, append_data)
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
try
close access file target_file
end try
return false
end try
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
Now I have a good framework to do improvements.
Testing the export
For parsing emails in Mail Archiver I divide emails into 3 categories: html, spam and other emails. Html usually is fine. For Mail Archiver the spam emails are important because they may try to break how emails work. Here I don't care about spam emails. That leaves me the personal emails for testing.
Emails have information in the header on how to interpret the email. When the information is missing then the result may be character salad which is called mojibake. I found one problematic email:
Original in Mail:
Exported email which I double-clicked to open it in Mail:
Looking at the email I can see that some header information is missing so it's likely a Windows email. The raw data in Mail also shows the mojibake. Mail fixes the mojibake when viewing or exporting the email. But the AppleScript source does not.
Verdict
For selected emails the export from Mail into eml files works fine. The AppleScript gives me a nice control over the export. Except the one single email with the mojibake the export went fine.
However, in AppleScript I can do way more than I what have done above.
- When exporting lots of emails I usually want to have the date in front of the subject.
- Emails with super long subject have the same problem as when dragging them to the Finder: writing fails. I need to find a way to make the filename shorter.
- From the article on getting mailboxes for Mail I know how the name of a mailbox looks like. The last task is to export one large mailbox.
I'm going to tackle the three features in the next article.