Apple’s mail client has an annoying limitation: If you want to export mail messages as .eml
or .emlx
you have to do it one by one, i.e. dragging one message at a time from the Mail App’s window to a Finder window. It won’t let you drag several messages at the same time.
However with a small script this limitation can be circumvented easily. (This is Part II of the other Mail Export post.)
As you may have noted, the intro text above is the same as on my other post about bulk-exporting mails. The script here in Part II however is quite different.
The differences:
- The script from Part I exports the messages as
.emlx
, the script here exports as.eml
. See below for the differences between of the two formats. - The script from Part I is a Bash shell script, while the script here is an AppleScript.
- The script here is more convenient to use. (No need to copy the messages to an Export box, just select them and run the script.)
.eml
or .emlx
?
.eml
is almost identical to.emlx
..emlx
contains a couple of lines more metadata. The content is the same..eml
is a standardized format. If you want cross-platform compatibility, then you have to go.eml
..emlx
is Apple-only..eml
is not transparent to Spotlight, i.e. the contents of exported.eml
messages will not appear in your Spotlight searches. Technically spoken: macOS does not include an mdimporter for.eml
files, only for.emlx
. However, there are mdimporters available, provided by third-party software, like EagleFiler. So, if you do have an mdimporter for.eml
installed, you shouldn’t have to worry about Spotlight.
So, if you’re fine with .eml
, then go with the script here, if you want to export as .emlx
, see my other Mail Export script.
Usage:
- In Mail.app select the messages you like to export.
- Launch the script in your preferred way.
- You can launch the script via the Scripts menu in the menu bar, via LaunchBar, via Keyboard Maestro, via Automator, or however you like.
- The script will ask you for the destination of the exported messages. Choose one and hit OK.
- The selected messages will be exported and named with this pattern:
<dateTtime> <sender mail address without TLD> <subject line>.eml
1
Once the export has finished you will receive a popup with some stats.
- The selected messages will be exported and named with this pattern:
Well, basically, that’s all.
OK, some more:
- If you you don’t want to be asked each time for the destination, you can set a fixed destination in the script. The script is already prepared for this:
- At the beginning of the script you find some explanatory comments as well as some examples. Uncomment one of the example lines and and adapt it to your needs.
- The maximum file name length on macOS is 255 chars. However, decomposed non-ASCII-chars (ü, ö, é, ñ, etc.) count twice. This means, if you get an error, because you have lots of non-ASCII chars in one of the subject lines, try to reduce the maximum file name length. (I have set it to 180, which should leave enough room for weird subject lines.) You find the setting around line 86 in the script (and also an explanatory comment there).
Download (1.0.0 / 2017-03-29)
Below you find the content of the script. Please do not copy the source code from here, instead use the download link above, to make sure you get the latest version.
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
set exportDestination to missing value
# If you like, set your export folder here (HFS notation = separate path components with a colon “:” + trailing “:”)
# If you don’t set a folder here the script will ask you each time for the destination.
# Some examples:
--set exportDestination to (path to desktop) & "Exported Mails:" as text
--set exportDestination to (path to documents folder) & "My Mails:" as text
--set exportDestination to (path to home folder) & "My Backup Folder:Exported Mail Messages:" as text
set fieldSeparator to space
set msgSubjects to {}
set msgDates to {}
set msgSenders to {}
set msgSources to {}
set msgCount to 0
# Ask for destination (if no path is set at the beginning of the script)
if exportDestination is missing value then set exportDestination to chooseFolder() as text
# Start stop watch
set timeStart to current date
# Grab the messages
tell application "Mail"
set selMsgs to the selected messages of the front message viewer
if selMsgs is missing value then
my alertNoSelection()
error number -128
end if
repeat with theMsg in selMsgs
set {end of msgSubjects, end of msgSenders, end of msgDates, end of msgSources} to {subject of theMsg, sender of theMsg, date received of theMsg, source of theMsg}
end repeat
end tell
# Write messages to file
repeat with i from 1 to count of msgSubjects
set {theSender, theSubject, theDate, theSource} to {item i of msgSenders, item i of msgSubjects, item i of msgDates, item i of msgSources}
set saveTID to AppleScript's text item delimiters
# Format sender
# Full email address
--set AppleScript's text item delimiters to {"<", ">"}
# Email address without TLD
set AppleScript's text item delimiters to {"<", "."}
set theSender to text item -2 of theSender
# Format date/time as short ISO
set AppleScript's text item delimiters to {""}
set theDate to theDate as «class isot» as string
set theDate to words 1 thru -2 of theDate as text
set theDate to text 3 thru -1 of theDate
# Format subject
# ':' is the only forbidden character on macOS. You can add more characters if you want, for example '{".", "?", "/", "<", ">", "\", "|"}'
set AppleScript's text item delimiters to {":"}
set theSubject to every text item of theSubject
set AppleScript's text item delimiters to {"-"}
set theSubject to theSubject as text
set AppleScript's text item delimiters to saveTID
# Compose file name
set msgFileName to theDate & fieldSeparator & theSender & fieldSeparator & theSubject
# Limit file name length
# Max is 255, but decomposed characters like ü, ä, é etc. count as two charcters (UTF-8 NFD!); so we better have some margin.
if (count of msgFileName) > 180 then set msgFileName to text 1 thru 180 of msgFileName
set msgFileName to msgFileName & ".eml"
# Save to file
try
set newFile to (open for access file (exportDestination & msgFileName) with write permission)
on error errMsg number errNum
if errNum is -43 then
alertDestination(exportDestination, errNum, errMsg)
else if errNum is -1410 then
alertNameLength(msgFileName, errNum, errMsg)
else
alertOther(errNum, errMsg)
end if
error number -128
end try
write theSource to newFile
close access newFile
set msgCount to msgCount + 1
end repeat
# Read stop watch
set timeElapsed to (current date) - timeStart
# Display stats
display alert "Completed" message "Exported " & msgCount & " message(s) in " & timeElapsed & " seconds to “" & (POSIX path of exportDestination) & "”." as informational
------------------------------------------------------------------------
# Handlers
on chooseFolder()
tell application (path to frontmost application as text)
set dest to (choose folder with prompt "Pick a folder to export your mails to:")
end tell
return dest
end chooseFolder
on alertNoSelection()
display alert "No Message Selected!" message "Select one or more messages in the messages list and run the script again." buttons {"Got it!"}
end alertNoSelection
on alertDestination(dest, eNum, eMsg) # -43
display alert "Destination folder missing or not accessible" message "Please check the folder path you have set at the beginning of the script or check the write permissions of the destination folder:" & return & return & dest & return & return & "# Error number:" & return & eNum & return & return & "# Error message:" & return & eMsg as critical
end alertDestination
on alertNameLength(fName, eNum, eMsg) # -1410
display alert "File name too long" message "Because of a very long Subject line the file name of this email message is too long:" & return & return & fName & return & return & "Please lower the file name length limit in the script." & return & return & "# Error number:" & return & eNum & return & return & "# Error message:" & return & eMsg as critical
end alertNameLength
on alertOther(eNum, eMsg)
display alert "An error has occurred" message "The following error has occurred:" & return & return & "# Error number:" & return & eNum & return & return & "# Error message:" & return & eMsg as critical
end alertOther