Saving Mail message attachments

how-to

(Mark Alldritt) #1

Here is a snippet of code showing how to save email message attachments using the Mail application. The script processes all selected messages and saves each attachment to the Desktop:

use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

--
--	Save attachments of selected Mail messages to the desktop
--

set desktopPath to (path to desktop)'s POSIX path

tell application "Mail"
	repeat with aMessage in (get selection)
		repeat with anAttachment in mail attachments of aMessage
			set attachmentName to name of anAttachment
			
			save anAttachment in POSIX file (desktopPath & attachmentName)
		end repeat
	end repeat
end tell

#2

And if you want to return a value (e.g. a list of all the filePaths saved to)

(to enable notification, for example, or composition within some larger process)

then concatMap (combined with list-wrapping of returned filePaths), allows (by concatenation), for a pruned list – with no ‘empties’ where where selected messages turned out to have no attachments.

use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

--
--    Save attachments of selected Mail messages to the desktop
--

set folderPath to (path to desktop)'s POSIX path

tell application "Mail"
    script attachmentsSaved
        on |λ|(mailItem)
            script fpSaved
                on |λ|(x)
                    set fp to folderPath & (name of x)
                    save x in POSIX file fp
                    {fp}
                end |λ|
            end script
            concatMap(fpSaved, get mail attachments of mailItem)
        end |λ|
    end script
    
    -- Return value: file paths of any saved files
    my concatMap(attachmentsSaved, get selection)

    --> {"/Users/houthakker/Desktop/labour draft.docx", "/Users/houthakker/Desktop/Socialist_dress_outline.isf"}
end tell


-- GENERIC  ------------------------------------------------------------------

-- concatMap :: (a -> [b]) -> [a] -> [b]
on concatMap(f, xs)
    set lng to length of xs
    set acc to {}
    tell mReturn(f)
        repeat with i from 1 to lng
            set acc to acc & |λ|(item i of xs, i, xs)
        end repeat
    end tell
    return acc
end concatMap

-- Lift 2nd class handler function into 1st class script wrapper
-- mReturn :: First-class m => (a -> b) -> m (a -> b)
on mReturn(f)
    if class of f is script then
        f
    else
        script
            property |λ| : f
        end script
    end if
end mReturn