Import From Apple Mail

Summary: Imports the selected or rule-processed messages from Apple Mail as .eml files.
Requires: EagleFiler
Install Location: ~/Library/Application Scripts/com.apple.mail or ~/Library/Scripts/Applications/Mail/
Last Modified: 2022-08-25

Description

The recommended way to import from Apple Mail is to select some messages and press the capture key. That will import the messages as a new mailbox file. This script is for situations where you want to:

Unlike when using the capture key, the unread/flagged status and MailTags are not preserved.

If you want the script to bring up the options window asking you where import the messages, remove the -- before with asking for options.

Installation Instructions · Download in Compiled Format · Download in Text Format

Script

on run
    
tell application "Mail"
        
if my isLionOrBetter() and (count of message viewers) is 1 then
            
-- If there's more than one, and full screen mode is active, we can't tell which is frontmost
            
return my importFromViewer(message viewer 1)
        
else
            
repeat with _viewer in message viewers
                
if index of _viewer's window is 1 then
                    
my importFromViewer(_viewer)
                
end if
            
end repeat
        
end if
    
end tell
end run

on isLionOrBetter()
    
considering numeric strings
        
return (system version of (system info)) ≥ "10.7"
    
end considering
end isLionOrBetter

using terms from application "Mail"
    
on perform mail action with messages _messages
        
my importMessages(_messages)
    
end perform mail action with messages
end using terms from

on importFromViewer(_viewer)
    
tell application "Mail"
        
set _messages to (get selected messages of _viewer)
        
my importMessages(_messages)
    
end tell
end importFromViewer

on importMessages(_messages)
    
set _paths to {}
    
repeat with _message in _messages
        
tell application "Mail"
            
set _subject to subject of _message
            
set _source to source of _message
        
end tell
        
set _inflatedPath to my createTempFolder() & "/" & "Inflated"
        
my writeInflatedUnicode(_inflatedPath, _source)
        
set _path to my createTempFolder() & "/" & my makeFileName(_subject)
        
my deflate(_inflatedPath, _path)
        
copy _path to end of _paths
    
end repeat
    
tell application "EagleFiler"
        
import files _paths -- with asking for options
    
end tell
end importMessages

on writeInflatedUnicode(_path, _string)
    
set _file to POSIX file _path
    
set _fd to open for access _file with write permission
    
write _string to _fd as Unicode text -- UTF-16; byte order doesn't matter since will ignore nil bytes
    
close access _fd
end writeInflatedUnicode

on deflate(_inflatedPath, _deflatedPath)
    
-- cat u.eml | tr -d '\000' > out.eml
    
set _script to "cat " & _inflatedPath's quoted form & " | "
    
# https://unix.stackexchange.com/questions/45404/why-cant-tr-read-from-dev-urandom-on-osx
    
set _script to _script & "LC_CTYPE=C tr -d '\\000'"
    
set _script to _script & " > " & _deflatedPath's quoted form
    
do shell script _script
end deflate

on createTempFolder()
    
set _tempFolder to do shell script "mktemp -d -t 'EFImportAppleMail'"
    
return _tempFolder
end createTempFolder

on makeFileName(_subject)
    
set _clean to my replace(_subject, "/", ":")
    
set _clean to my replace(_clean, ":", "-")
    
set _extension to ".eml"
    
set _hfsPlusLimit to 255
    
set _max to _hfsPlusLimit - (length of _extension)
    
set _shortened to my substringToIndex(_clean, _max)
    
return _shortened & _extension
end makeFileName

on substringToIndex(_string, _index)
    
if length of _string > _index then
        
set _end to _index
    
else
        
set _end to length of _string
    
end if
    
return my join(characters 1 thru _end of _string, "")
end substringToIndex

on replace(_string, _source, _replacement)
    
return my join(my split(_string, _source), _replacement)
end replace

on join(_list, _sep)
    
set _temp to AppleScript's text item delimiters
    
set AppleScript's text item delimiters to _sep
    
set _result to _list as string
    
set AppleScript's text item delimiters to _temp
    
return _result
end join

on split(_string, _sep)
    
set _temp to AppleScript's text item delimiters
    
set AppleScript's text item delimiters to _sep
    
set _result to text items of _string
    
set AppleScript's text item delimiters to _temp
    
return _result
end split