At the request from : Brian Jones
I wrote an Applescript for a Mail.app Rule that will Automatically Save Attachments in Mail.app .
(* For Yosemite : please see Reported issues below *)
Each messages attachments from the sender is then placed in a time stamped folder. The time stamp derives from the date received of the message.
I have not put in any code to mark the message as read or processed. But you can do this if you want.
Open script in Applescript Editor
1- Where to save the Script file
Unlike previous Os versions where you could place your Applescript any where in the file system. In 10.8 you need to place Mail.app Applescripts in:
~/Library/Application Scripts/com.apple.mail/
You can simply copy the above path, open a new Finder window.
Hit the keys Cmd + Shift G A sheet will slide down. Past the path in the text field and hit Go.
you will be taken to the folder. Place you Applescript file inside.
The Script will now appear for your selection in the Mail Rules.
2 – Setting your sub folder path for the saved attachment directories and files.
If you wish to change the path of where your attachments folders go. You can make a simple change to the line of code :
set folderName to “Attachments”.
For example I want my attachment folders to go into:
/Users/UserName/Documents/mailstuff/mail_Attachments.
The folderName line will look like this:
set folderName to “documents:mailstuff:mail_Attachments”
Notice the colons (:) they are used instead of the forward slashes (/) to mark directorie separation.
Make sure you do not put a colon at the beginning or at end of your path. They are not needed.
The path to the user home folder is set later on in the line:
set homePath to (path to home folder as text ) as text
So you only need to concern yourself with sub folders of the user home folder.
Another thing to note.
If you only have some of the directories in the folderName path or none at all. The script will create them. It will not over write any folders already existing but will add the missing intermediary ones.
Tested on : Mac Os 10.8.3 , Mail.app Version 6.3 (1503)
Reported issues:
1, I have filed a bug report (below) with Apple: Nov. 2014 this will most likely be a duplicate as ALL theses types of Applescript will be affected and others have noticed it. Hopefully apple will fix this soon.
The Problem is not with the code here. so please do not post comments if you are using Yosemite and getting the error described below.**Update – Apple have closed my Bug report on this as a duplicate. This means they are still looking at it..
Bug Report:
As of 10.9 and 10.10 ( Yosemite) you can no longer access Mail.app’s ‘mail attachments’ from Applescript.
This means you cannot save or count them.
You will 9 times out of 10 get resulting error “error “Mail got an error: AppleEvent handler failed.” number -10000”
This appears to happen for 90% of the emails that are in an inbox, individual or consolidated ones.
This bug is reproducible when using a “get selection” Applescripts
This bug is reproducible when Performing a “Run Applescript” action in the Mail.app mail Rules.
2, Reported in comment . : Umlauts in folder names may stop the script from completing.
The removal of umlauts from the name solved the problem.
Hi,
Spaces in file names should not normally be a problem. Unfortunately I cannot test against a symlinked user home folder; which may indeed cause a problem. commands like set homePath to (path to home folder as text) as text may run into problems. Try and replace such with a hard coded path and see how that works.
Hi Mark, great you’re helping so many people!
Somehow i cannot get your script to work, perhaps because spaces in filenames and/or a symlinked user home folder
// Besides, actually, I only need a script which directs the attached file of a chosen e-mail to a chosen folder or, when there are severel files as attachment, make the e-mail an attachment itself and places it inside the folder.
I want to use either a rule (with the script) or by highlighting a mail in mail.app (using a shortcut to perform the script. But i can imagine this is a little to complicated.. //
Thanks anyway for a reply.
Setting Notifications is a nice idea.. what will yours actually be helping you monitor regarding the attachments.
My own script was broken since Mavericks. Installed yours and it works OK. Have to customize it for my own purpose. Since Mavericks Applescripts supports Notifications, so in any case I will add some to monitor incoming attachments.
Thx
Peter
Hi, it does work on Mavericks. The only problem is with Entourage accounts on all OS versions
Hi,
I’m interested to know if someone managed to make this work on Mavericks ?
Peter
Hi Florian,
I will email you so we can take this to email. Rather than clutter the comments with this too much.
Cheers
Hi Mark,
not really as before it not even worked at the beginning… now it works initially/one-time during confirmating to apply the rule to existing inbox mails, before it has never worked that way.
But after the initial work then it appears as similar.
Best, Florian
Hi Florian.
Is this the similar or the same problem you had before with you exchange account?
Sorry Marc,
another problem appears: The scripts works always when i create the rule and confirm to apply the rule to all existing mails. The script does not work (by its own) when a new email is coming in. A verification by an second rule (marking incoming mails yellow) works. So unclear why the attachments are not stored as it seem that the rule works, but not the script?! … Any ideas? Florian
Hi Mark,
we have already been in contact in the past and i am very thankful about your help. Quick question on the original posted script, which i use under 10.9.1 and Mail 7.1 (1827).
I would like to save all attachments in one folder (“Attachments”), without structuring them into subfolders.
The filename i am looking for is “YYYY-MM-DD_HH-MM___”. Maybe it is necessary to cut the name in case it gets to long (i.e. 70 characters?).
Could you please be so kind to support me as i am not expert enough to adapt the code properly?
Many (many) thanks for your help in advance!
btw: is there any way to apply the script one-time to already received mails, stored in a folder substructure?
Florian
You welcome . Glad it was of help.
M.
Sincerest thanks for this tremendously helpful script, tinkering with only a wee part of it I was able to create attachment nirvana on my work machine, where I sometimes get >100 PDF attachments from our network-enable scanner. Phew. Thanks so much.
Hi
Has anybody tested this in Mavericks/Mail.app 7?
Also, given the new ‘Export to PDF…’ command in Mail, I was wondering if this could be extended/enhanced by
A) also putting a PDF of the email message in the same folder as the attachment
B) optionally, instead (or in addition) of putting the attachment/PDFinto a folder with the sender, putting either the messages/attachments or the sender-folders into a folder corresponding to the path in Mail.app (i.e. the filing hierarchy already established in Mail, for those of us who still file email…).
Thanks!
Thank you for your kind response. I apologize for my misunderstanding of the purpose of your site and greatly appreciate your help.
Hi Reino,
You should be able to just change the line:
set savePath to attachmentsFolder & ":" & subFolder & ":" & timeStamp & ":" & originalName
to :
set savePath to attachmentsFolder & ":" & subFolder & ":" & originalName
This should take out the timestamp.
Cheers
Hi Duane,
I assume you are asking for help with your script. This post is not a general help for scripts and you would help yourself by actually asking nicely for such help. Rather than posting some random code and an error.
But since I have gone to the trouble of allowing your comment and replying. Here is how your code should be written.
set attachmentsFolder to ((path to home folder as text) & “Sites:Schoollibrariesnet:us:sc:L1:ghs:”) as text
set savePath to attachmentsFolder
tell application "Mail"
set theMessage to (get selection)
repeat with i from 1 to number of items in theMessage
set this_item to item i of theMessage
set attach to mail attachments of this_item
repeat with j from 1 to number of items in attach
set this_itemj to item j of attach
set attName to name of this_itemj
save this_itemj in file (savePath & attName)
end repeat
end repeat
end tell
As I show in the script.
It is advisable to iterate over each message and each of it’s attachments.
You need to add a name of the saved file to the end of your path. Otherwise the folder ghs will become the file name and be overwritten.
The mail attachments are called ‘mail attachments’ not ‘attachments’
I advice your to do a little reading up on Applescript to get some foundation on it’s syntax and use.
Introduction to AppleScript Overview
Introduction to AppleScript Language Guide
I’m on 10.8.5 Can not get the attachment.
Here is a simple variation of the required script with error message
tell application “Finder”
set attachmentsFolder to ((path to home folder as text) & “Sites:Schoollibrariesnet:us:sc:L1:ghs”) as text
end tell
tell application “Mail”
set theMessage to (get selection)
set savePath to attachmentsFolder
save attachment of theMessage in file (savePath)
end tell
display dialog “The Script has Run”
error “Can’t get attachment of {message id 193150 of mailbox \”INBOX\” of account \”DuaneWS\” of application \”Mail\”}.” number -1728 from attachment of {«class mssg» id 193150 of «class mbxp» “INBOX” of «class mact» “DuaneWS”}
Hey and thanks for the sript! Can you please advice, what I need to remove from the script, if I don’t want to rename attachment, but just save it into a defined folder automatically? Thank you!
Hi Joris,
In comment #40 I posted a cut down script that among other things checked for MIME Type of the files.
I have combine part of that script with the original scripts to do what you want. I have only tested it in Applescript Editor where it worked without a problem. Do not in the comments about malformed file names. i.e file name with characters in them that the finder system objects to. These will stop the script. The is code amongst the scripts I posted in other comments to deal with this. Which you can dig out if you wish.
Here is the new main script for you.
And here is a mime type script you can run on a selected file in the Finder to get it’s mime type. Which you will need to place in the “set MIMEType to ..” line at the top of the main script.
You can save a new main script file for each type you want. And attach it to a new mail rule. i.e each rule will have it’s own script to look for one file type.
Hi Mark,
works like a charm… Very nice…. I was wondering, would it be possible to limit the “saving” of the attachments only to specific file extensions ? eg. .pdf .zip etc..
Thx
Greetings,
Joris
this is an amazing piece of Script and work, thanks for posting it and being so clear with your site
will follow you immediately
I just ran a test. And realised why you possibly are getting two folders with two emails…
The script is working as expected when a single email or multiple emails are selected.
But if you have your emails view set to ‘Organise by Conversation’ then when you select single email selection you may actually be selecting multiple emails in a Conversation.
My test proved this to be true.
You log shows that two emails with different IDs are selected.
get selection
! ! –> {message id 71076 of mailbox “INBOX/ReceiptsSIR” of account “RS – Field Estates”,
message id 71079 of mailbox “INBOX/ReceiptsSIR” of account “RS – Field Estates”}
And both have the same attachment. Inv_147025_from_Elmer_Sweetwood__Sons_3016.pdf
Remember we are using a test script. Which uses get selection to get the selected emails so we can test the basic code in Applescript Editor.
But I understand your goal will be run the script as a Mail rule. Which will not have the get selection line. Therefor this should not be a problem.
Cheers.
In response to an Email from Drew,
Hi Drew,
At the bottom of my last comment I mention that there is one line commented on in the script which you can change to true or false.
This is the code that may stop files from not saving if there are bad characters in the file name. it is set to false at the moment.
You would need to set it to true to take care of the bad file name.
The other problem is very odd.. and I am not sure whats is going on there the only hing I did notice is the folder where the files are save already exists.
I have now change the code to make sure that the folder name is a timestamp only and will only be used once for each job.
Here is the script
Hi Drew,
There is a similar way to do this in Automator with the Actions:
1, get the selected emails.
2, get the attachments from Mail Messages.
3, New Email Message.
4, Run Applescript. ( setting first paragraph of content to some string )
This works by getting the emails, passing on the attachments to the new email message and then adding the text without wiping out the rest of the content that includes the attachments.
Now here is the thing.
The only reason this Automator action works is because it can get the path of the attachments passed to it. And the only reason it can get them is because the action (2) get the attachments from Mail Messages. Saves the attachments somewhere first.
In your script it is not possible to get the paths of the attachments. Which are needed for the ” {file name:theAttachment} ” part of the script. Because the paths of the attachments in the original email do not exist in a way that we can get at. (not that I have found anyway)
I also looked at the email you sent using the forward command to compose an email that automatically picks up the attachments.
It is one I have used in the past. Unfortunately as you discovered one of the pit falls is that you get the rest of the original email quoted in the content. i.e quote levelled text.
Removing this is possibly but I have not found a way to keep the attachments in place.
So the simple answer is to save the files some where. The ideal place would be your user temp folder. Which should be cleared out by the system every now and then. (AFAIAA).
This Script does that and composes an email with the attachments and where you can easily add text content. There is one line commented on in the script which you can change to true or false.
This is the code that may stop files from not saving if there are bad characters in the file name. it is set to false at the moment.
The script also has the using terms from application “Mail”
on perform mail action with messages theMessages for rule theRule
code commented out and set to select emails. Don for test running in Applescript Editor.
Good luck.
Mark
Hi Teddy,
To be honest I am not sure. But maybe declaring the container a file to save the given data to, allows the sandbox to give the write to file permission. Rather than save to some unknown container type??
Thanks a lot Mark! after reading your script carefully I know what made my older script didn’t work anymore in mountain lion.
I was having errors in the console: sandboxd deny file-write-create
before: save theAttachment in savePath
after: save theAttachment in file (savePath)
could be just the difference in that “file” bit
do you know why that tiny difference was a problem with the sandbox?
Hi Mark,
I’ve never coded in ApplieScript but tried figuring out how to adapt your script to “email attachments to a third party” rather than saving attachments to a flat file on my Mac. (I do not need text in the email body forwarded to the third party, just the attachments…otherwise I could just forward the emails as is.) Despite my best attempt, coding isn’t my thing…but you seem to be a pro! If you have the time, would you you take a look at the attached AppleScript? Thanks, Mark! 🙂
tell application “Mail”
set theMessages to (get selection)
repeat with eachMessage in theMessages
set attachCount to count of (mail attachments of eachMessage)
if attachCount is not equal to 0 then
try
— Email the attachment
repeat with theAttachment in eachMessage’s mail attachments
set theSubject to “Attachment for Processing”
set theBody to “Attachment name is ” & theAttachment
set theAddress to “sender@abcompany.com”
set theSender to “recipient@thirdpartycompany.com”
set theNewMessage to make new outgoing message with properties {subject:theSubject, content:theBody & return & return, visible:true}
tell theNewMessage
set visibile to true
set sender to theSender
make new to recipient at end of to recipients with properties {address:theAddress}
try
make new attachment with properties {file name:theAttachment} at after the last word of the last paragraph
set message_attachment to 0
on error errmess — oops
log errmess — log the error
set message_attachment to 1
end try
log “message_attachment = ” & message_attachment
#send
end tell
end repeat
–on error msg
–display dialog msg
end try
end if
end repeat
end tell
–end perform mail action with messages
–end using terms from
on pad(n)
return text -2 thru -1 of (“0” & n)
end pad
Hi Mark – I am running scripts with Mail Rules via Indev’s Mail-Act-On. When I specify your most recent script, everything works properly (including the long file name issue discussed earlier). When I run a Mail Rule pointing to the original script in this blog, nothing happens…which is why I’m perplexed. LOL.
The original script and my updates are only meant to run within Mail.app and as structured will not run in ApplescriptEditor.
The Test Script has some changes that allow it to run as a normal applescript within ApplescriptEditor. This allows for some debugging.
I thought you running the scripts per my instruction in the Post.. i.e via a Mail rule.
Hi Mark – I did as instructed and it works fine! When I try executing script in your original post though, nothing happens and the event log is blank. What’s causing this?
Read my comments above. I experienced a problem where the script will run one or twice and then stop working. After a lot of experiment, I concluded it was a bug in Mac OS and was not the fault of the script. I still have not found a solution to this problem. Try googling “AppleScript not working on mountain lion” for various discussion.
Hi,
I ran the updated script on my Mac with your path with no problems.
Select an email with an attachment in Mail.app
Open the script here in Applescript editor.
Select the Events tab so you can see what the script is doing and any errors..
Then run script directly in Applescript editor.
Let me know what the result is..
Open in Applescript
Hi Mark,
I’ve been trying to get this to work for a few hours. After having no luck, I deleted the original script and redownloaded from the original post (by clicking “open script in AppleScript editor”) and saving. Next I changed the file location to “downloads:mail_attachments” and compiled. The script is stored in ~/Library/Application Scripts/com.apple.mail/.
Unlike before when I downloaded the orignial script, I cannot get the original script to work. I’ve rebooted my MBP and no go. I’m running 10.8.4. Is there a file I need to refresh somewhere? (I’m not a developer so learning as we go here.)
Hi Mark,
Downloaded/compiled. Upon executing, nothing happens (including sub-folder creation).
If I remove the above code you sent, the script works fine on all attachments except emails having the lengthy attachment name (discussed above).
Not sure whats going on there. Try this: click to open in AppleScript Editor
Thanks, Mark! I copied/pasted and recompiled. When executed, script will not save any attachments from any emails now. Here’s the code. Syntax error?
using terms from application “Mail”
on perform mail action with messages theMessages for rule theRule
— set up the attachment folder path
tell application “Finder”
set folderName to “Downloads:Mail_Attachments”
set homePath to (path to home folder as text) as text
set attachmentsFolder to (homePath & folderName) as text
end tell
tell application “Mail”
repeat with eachMessage in theMessages
–set the sub folder for the attachments to the senders mail address.
— All future attachments from this sender will the be put here.
set subFolder to (sender of eachMessage)
— set up the folder name for this mail message’s attachments. We use the time stamp of the date received time stamp
set {year:y, month:m, day:d, hours:h, minutes:min} to eachMessage’s date received
—set timeStamp to (y & “-” & my pad(d) & “-” & my pad(m as integer) & “_” & my pad(h) & “-” & my pad(min)) as string — month as number
set timeStamp to (y & “_” & my pad(d) & “-” & m & “_” & my pad(h) & “-” & my pad(min)) as string
— use the unix /bin/test command to test if the timeStamp folder exists. if not then create it and any intermediate directories as required
if (do shell script “/bin/test -e ” & quoted form of ((POSIX path of attachmentsFolder) & “/” & subFolder & “/” & timeStamp) & ” ; echo $?”) is “1” then
— 1 is false
do shell script “/bin/mkdir -p ” & quoted form of ((POSIX path of attachmentsFolder) & “/” & subFolder & “/” & timeStamp)
end if
try
— Save the attachment
repeat with theAttachment in eachMessage’s mail attachments
set originalName to my replaceBadChars((name of theAttachment as string))
set savePath to attachmentsFolder & “:” & subFolder & “:” & timeStamp & “:” & originalName
try
save theAttachment in file (savePath)
end try
end repeat
–on error msg
–display dialog msg
end try
end repeat
end tell
end perform mail action with messages
end using terms from
on pad(n)
return text -2 thru -1 of (“0” & n)
end pad
on replaceBadChars(TEXT_)
–log TEXT_
set OkChars to {“a”, “b”, “c”, “d”, “e”, “f”, “g”, “h”, “i”, “j”, “k”, “l”, “m”, “n”, “o”, “p”, “q”, “r”, “s”, “t”, “u”, “v”, “w”, “x”, “y”, “z”, “A”, “B”, “C”, “D”, “E”, “F”, “G”, “H”, “I”, “J”, “K”, “L”, “M”, “N”, “O”, “P”, “Q”, “R”, “S”, “T”, “U”, “V”, “W”, “X”, “Y”, “Z”, “1”, “2”, “3”, “4”, “5”, “6”, “7”, “8”, “9”, “0”, “_”, “.”, “(“, “)”, “-“, “,”, space}
set TEXT_ to characters of TEXT_
repeat with i from 1 to number of items in TEXT_
set this_char to item i of TEXT_
if this_char is not in OkChars then
set item i of TEXT_ to “_”
else
end if
end repeat
set TEXT_ to TEXT_ as string
do shell script ” echo ” & quoted form of TEXT_
end replaceBadChars
Hi Drew.
Thanks for your comment.
Strangely at work the scripts I wrote there take care of this with an old handler I use to replace bad characters in file names with an underscore. But for some reason I did not put it in this script.
I have never had to rewrite the handler because it just works. And is easy to change the characters to ones I want for other tasks. But I have taken out some of the allowed characters that should not really be in a file name.
to use it:
Replace the line
set originalName to name of theAttachment
with
set originalName to my replaceBadChars((name of theAttachment as string))
And add the code below at the end of the script ( after the line end pad )
on replaceBadChars(TEXT_)
--log TEXT_
set OkChars to {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "_", ".", "(", ")", "-", ",", space}
set TEXT_ to characters of TEXT_
repeat with i from 1 to number of items in TEXT_
set this_char to item i of TEXT_
if this_char is not in OkChars then
set item i of TEXT_ to "_"
else
end if
end repeat
set TEXT_ to TEXT_ as string
do shell script " echo " & quoted form of TEXT_
end replaceBadChars
Hope this helps.
Hi Mark,
I have a contractor who sends PDF invoices with a lengthy (odd) file name. After testing your script out, I noticed PDFs from this contractor are not saved. I presume the file name is the issue. Here’s an example of a PDF he sent: C/\Users\Mark\AppData\Local\Temp\Inv_3990.pdf. Yes, the “C/\Users\Mark\AppData\Local\Temp\Inv_3990” appears before the dot PDF extension. Aside from asking him to rename PDFs before sending, might you have a solution?
Thanks, Mark! 🙂
Hi Craig,
I do not have any Mac Mail server setup so I cannot tell you if this code or a crafted one from this would work on yours.
What do you know about your server and it executing scripts?
Hi. Would this script work on Mail server? We are trying to save e-mailed faxes (ring central) to a folder, and we want the attachments saved on the server side versus the client/user side. Thanks!
Thank you! This is indeed a great script – will use it to archive attachments from gmail! I’ll also search for a script now – I think I’ve seen it earlier somewhere – that can delete attachments from mails – > to reduce the size of the account!
thanks again!
Hi Theresa,
Thank you for your comment. I am out and about at the mo.
But will get back to you later to get some more details from you.
In the meantime could you post you current script
Just remember to change personal info if any that you do not want public to a general wording.
Like you bosses name would be UserName.
Cheers.
Mark, I am a newby to scripts but decided to try this script as my boss wanted to find a quick way to extract attachments from an email. It works. I’m not surprised that it works because I’ve read your blog from start to finish and I know you are an expert on this stuff. I’m surprised it works because it was me that tried to modify the subdirectory where the attachments go. That worked, too, because of your excellent explanation.
Just a few questions and if you don’t have time for this, I completely understand.
First, in our office we rarely receive any attachments other than pdf or docx. Sometimes jpg. What we don’t want is the vcf (vCard) attachments and really, not the jpg’s either as typically, that is an office image or some such thing. Is there a way to eliminate these from being extracted?
Also, I sent a test email with a pdf attachment to my boss to see if it worked (I have access to his email on my computer so I can see what he gets). The script dropped the attachment to MY folder rather than his.
Also, I had someone send me an email with an attachment and it didn’t extract that one at all. Am I doing something wrong? I didn’t change a thing on your script except where I wanted the attachments to where I wanted them to go.
/Users/Secretary/Screen Shot_Redacted.pdf
Yes, it happens with other Applescripts as well. I don’t think it is caused by your script specifically. As I said, there are lots of conversations online about this issue. Why it would work the first few times and then stop working thereafter is beyond me. If anybody has this issue or finds a solution, please post a reply here.
Hi Callum,
I am just on 10.8.4 myself so will see if it starts to fail. But you seemed to have the problem through 10.8.3 and with other scripts.
I suspect you are right that it is a bug somewhere in the OS and possibly the script runner triggered by something in the local setup.
This script works a few times but then stops working thereafter. I spent hours reading forums on Apple support about this problem. I don’t think it’s the script, since it does work a few times before quitting. I had thought it was an Apple mail problem, but I tried setting it up on Outlook and it doesn’t work there either. I believe it’s an Applescript bug in OX 10.8.4. Anyway, I thought I’d share my experience for anybody who is experiencing this problem of it not working.
Thanks had blinkers on… Should have expected there in such well written/documented code
Hi Joop,
If you look at the code with the line for the “set timeStamp..” you will notice a commented out version above it “–set timeStamp..” I left that line in so people could see how to change the month to a number.;-)
my pad(m as integer) -- month as number
Hope that helps.
best regards
Mark.
Awesome script… nicely structured.
would like the date subfolder in slightly mote structured way… YYYYMMDD_hh-mm.
assuming I should change following line:
set timeStamp to (y & “_” & my pad(d) & “-” & m & “_” & my pad(h) & “-” & my pad(min)) as string
Can do the rearrangements but it seems that the m (month) is not a number so how do i get month number?
Thanks….