I try to save attachments using applescript, my script works well when the files are small (e.g 109 Bytes) but save empty file when the attachment is too large (304KB). I'm working on macOS High Sierra and had no clue how to fix it, anyone got any idea?
My acript:
using terms from application "Mail"
on perform mail action with messages theMessages
set myPath to "Macintosh HD:Users:MY_USER:Downloads:"
tell application "Mail"
repeat with eachMessage in theMessages
repeat with theAttachment in eachMessage's mail attachments
set originalName to name of theAttachment
set savePath to myPath & originalName
try
save theAttachment in savePath
end try
end repeat
end repeat
end tell
end perform mail action with messages
end using terms from
Thanks
As mentioned in https://apple.stackexchange.com/a/322724/156892, change:
save theAttachment in savePath
to:
save theAttachment in file savePath
In addition, it would be more robust if you set myPath like so:
set myPath to (path to downloads folder as text)
Related
I’m trying to set up an AppleScript that will get a path from a txt file(mockUPPath.txt) on the Desktop which in theory will allow me to attach a jpg. The name of the folder and jpg will change so I can’t hard code it. I also get the body of the email from another text file on the Desktop which I managed to get working. I can get it to build the email but not find and attach the jpg.
The text in the mockUPPath.txt file looks like this: Name_Mock-up/555.jpg.
The jpg 555.jpg is in a folder “Name_Mock-up” on the Desktop
This is what I have so far (below), anyone know where I’m going wrong?
set AppleScript's text item delimiters to return
set theFile to ((path to desktop as text) & "mockUPText.txt")
set theData to paragraphs of (read file theFile)
set myPath to ((path to desktop as text) & "mockUPPath.txt")
set thePath to paragraphs of (read file myPath)
set newPath to (POSIX path of (path to desktop folder)) & thePath
--Email
set theMessageSubject to "Test email"
set theRecipient to "email#test.com"
set theMessageContent to theData
set theMessageAttachment to newPath
tell application "Mail"
activate
set theMessage to make new outgoing message with properties {visible:true, subject:theMessageSubject, content:theMessageContent & linefeed & linefeed}
tell theMessage
make new to recipient at end of to recipients with properties {address:theRecipient}
make new attachment with properties {file name:theMessageAttachment as alias} at after the last word of the last paragraph
end tell
end tell
Based on the information you presented in your OP, the following example AppleScript code works for me as tested in Script Editor.
First I did the following:
Created a folder on my Desktop named Name_Mock-up containing a screenshot of the example AppleScript code in Script Editor naming it 555.jpg
Created a file on my Desktop named mockUPText.txt with a single line of text, Name_Mock-up/555.jpg.
The ran the example AppleScript code:
set theFile to ((path to desktop as text) & "mockUPText.txt") as alias
set theData to read theFile
set myPath to theFile
set thePath to read myPath
set newPath to (POSIX path of (path to desktop folder)) & thePath
set theMessageSubject to "Test email"
set theRecipient to "email#test.com"
set theMessageContent to theData
set theMessageAttachment to newPath
tell application "Mail"
activate
set theMessage to make new outgoing message with properties {visible:true, subject:theMessageSubject, content:theMessageContent & linefeed & linefeed}
tell theMessage
make new to recipient at end of to recipients with properties {address:theRecipient}
make new attachment with properties {file name:theMessageAttachment} at after the last word of the last paragraph
end tell
end tell
Here is a screenshot of the result of running the example AppleScript code:
Note: That all said, I would not necessarily code it in this manner and have only presented this to correct some of the code you originally posted as mentioned in part by my comment to your OP.
First of all the most reliable way to interact with read/write API is to coerce the path to «class furl» and delete the file keyword.
Second of all most of the text files are UTF 8 encoded. If so read it as «class utf8»
The error occurs because you cannot coerce a POSIX path to alias. You need an extra step
Text item delimiters makes no sense, read the body text as one string and get the first item of the thePath.
set theFile to ((path to desktop as text) & "mockUPText.txt") as «class furl»
set theData to (read theFile as «class utf8»)
set myPath to ((path to desktop as text) & "mockUPPath.txt") as «class furl»
set thePath to paragraphs of (read myPath as «class utf8»)
set newPath to (POSIX path of (path to desktop folder)) & item 1 of thePath
set newAlias to POSIX file newPath as alias -- if the file doesn't exist you'll get an error
--Email
set theMessageSubject to "Test email"
set theRecipient to "email#test.com"
set theMessageContent to theData
set theMessageAttachment to newAlias
tell application "Mail"
activate
set theMessage to make new outgoing message with properties {visible:true, subject:theMessageSubject, content:theMessageContent & linefeed & linefeed}
tell theMessage
make new to recipient at end of to recipients with properties {address:theRecipient}
make new attachment with properties {file name:theMessageAttachment} at after the last word of the last paragraph
end tell
end tell
I have albums and nested albums and folders in Photos application. I want my applescript to export images maintaining the Album or Folder structure that I have the in the application.
I tried scripts available online :
tell application "Finder"
set location_1 to (choose folder with prompt "Choose a folder to export into") as text
end tell
tell application "Photos"
set x to name of every folder
choose from list x with prompt "Choose a project to export"
set theP to item 1 of result
tell application "Finder" to make new folder at alias location_1 with properties {name:theP}
tell folder theP
set initflist to every folder
set initalist to every album
if initflist is equal to {} then
log "process albums"
processAlbums(initalist, location_1 & theP) of me
else
if initalist is not equal to {} then
log "process albums"
processAlbums(initalist, location_1 & theP) of me
end if
log "process sub folders "
processSfolders(initflist, (location_1 & theP)) of me
end if
end tell
end tell
on processAlbums(alist, apath)
tell application "Photos"
repeat with a in alist
tell a
set theimages to get media items of album a
set thename to name of a
tell application "Finder"
if not (exists folder thename in alias apath) then
make new folder at alias apath with properties {name:thename}
end if
set destination to apath & ":" & thename & ":"
end tell
with timeout of 6000 seconds
tell a
set settings to "JPEG - Original Size"
export theimages to alias destination
end tell
end timeout
end tell
end repeat
end tell
end processAlbums
on processSfolders(flist, fpath)
tell application "Photos"
repeat with a in flist
try
set thename to name of a
tell application "Finder"
if not (exists folder thename in alias fpath) then
make new folder at alias fpath with properties {name:thename}
end if
end tell
tell a
set sAlist to every album
set sflist to every folder
if sflist is equal to {} then
processAlbums(sAlist, fpath & ":" & thename) of me
else
if sAlist is not equal to {} then
processAlbums(sAlist, fpath & ":" & thename) of me
end if
processSfolders(sflist, fpath & ":" & thename) of me
end if
end tell
on error errMsg
log "error"
end try
end repeat
end tell
end processSfolders
The issue is that it gets names of only child albums and not top level albums. I have to maintain the entire structure of album or folder.
I do not know AppleScript and I tried tweaking this one but no luck so far. can I get a direction please?
You can get the name of the folders, and the albums contained in the folder, which will enable you to create the top level and child directories. Albums can only contain media items, not albums. Top level albums are classified as folders or containers. In the Applescript dictionary for Photos, it gives the definitions for these items.
tell application "Finder"
set location_1 to (choose folder with prompt "Choose a folder to export into") as text
end tell
tell application "Photos"
activate
set fds to folders
repeat with fd in fds
set fdName to name of fd
set abNames to every album of fd
if parent of fd is missing value then
my createFolders(fdName, abNames, location_1, fd)
end if
end repeat
end tell
on createFolders(fName, aAlbums, fPath, fd)
tell application "Finder"
if not (exists folder fName in alias fPath) then
make new folder with properties {name:fName} at fPath
end if
repeat with a in aAlbums
set aName to name of a
set aPath to ((fPath as alias) as text) & fName
if not (exists folder aName in alias aPath) then
make new folder with properties {name:aName} at aPath
end if
set exPath to ((aPath as alias) as text) & aName
my exportImages(a, exPath)
end repeat
end tell
tell application "Photos"
set rcFolders to every folder of fd
repeat with rcFd in rcFolders
set rcAlbums to every album of rcFd
set rcName to name of rcFd
set rcPath to ((fPath as alias) as text) & fName
my createFolders(rcName, rcAlbums, rcPath, rcFd)
end repeat
end tell
end createFolders
on exportImages(photoAlbum, destination)
tell application "Photos"
set theimages to get media items of photoAlbum
with timeout of 6000 seconds
tell photoAlbum
set settings to "JPEG - Original Size"
export theimages to alias destination
end tell
end timeout
end tell
end exportImages
EDIT - Error Handling
To handle errors, locate the command that is causing the error and wrap it in a try block. Solution could be to quit the application, so that the process will end, and maybe add a short delay and then continue with the script.
try
export theimages to alias destination
on error
-- statements to execute in case of error
error "The exporting of images failed to complete"
quit
end try
From the developer reference - When a command fails to complete in the allotted time (whether the default of two minutes, or a time set by a with timeout statement), AppleScript stops running the script and returns the error "event timed out". AppleScript does not cancel the operation—it merely stops execution of the script. If you want the script to continue, you can wrap the statements in a try statement. However, whether your script can send a command to cancel an offending lengthy operation after a timeout is dependent on the application that is performing the command. Further info regarding try statements.
I found this script in https://macscripter.net/viewtopic.php?id=43410:
tell application "Finder"
set thisFolder to choose folder with prompt "Please select the folder you wish to process." without invisibles
set theseFiles to files of thisFolder as alias list
end tell
tell application "TextEdit"
activate
repeat with thisFile in theseFiles
set newFilename to my getFilename(thisFile)
set thisDoc to make new document
tell thisDoc
make new attachment with properties {file name:thisFile}
set pathtofile to ((thisFolder as string) & newFilename & ".rtfd") as Unicode text
save in file pathtofile
end tell
close front document saving no
end repeat
end tell
on getFilename(thisFile)
set {atid, AppleScript's text item delimiters} to {AppleScript's text item delimiters, ":"}
set theFilename to last text item of (thisFile as text)
set AppleScript's text item delimiters to "."
set newFilename to first text item of theFilename
set AppleScript's text item delimiters to atid
return newFilename
end getFilename
This script do one TextEdit file per one file of source folder.
How can I modify this script to creates one TextEdit file of all files of source folder? The result file will contain all folder files.
I do not need a list of file names into TextEdit document. I need all FILES into TextEdit document with attachments (RTFD format).
I'll confess that I'm not precisely clear what an 'attachment' is in TextEdit lingo, or what it might be used for, but if you just want one file with all of these attachments added to it it, that's easy enough:
tell application "Finder"
set thisFolder to choose folder with prompt "Please select the folder you wish to process." without invisibles
set theFileName to name of thisFolder
set theseFiles to files of thisFolder as alias list
end tell
tell application "TextEdit"
activate
set thisDoc to make new document
set pathtofile to ((thisFolder as string) & theFileName & ".rtfd") as Unicode text
tell thisDoc
repeat with thisFile in theseFiles
make new attachment with properties {file name:thisFile}
end repeat
save in file pathtofile
end tell
close front document saving no
end tell
EDIT
Per the comments, here's a version that applies this routine to subfolders. I've cleaned up the code a bit (I like using System Events better than the Finder), but it's the same process.
set thisFolder to choose folder with prompt "Please select the folder you wish to process." without invisibles
tell application "System Events"
set subFolders to folders of thisFolder
repeat with aFolder in subFolders
set folderName to name of aFolder
set filePath to (POSIX path of thisFolder) & "/" & folderName & ".rtfd"
set fileList to (POSIX path of every file of aFolder whose visible is true)
tell application "TextEdit"
activate
set thisDoc to make new document
tell thisDoc
repeat with aFile in fileList
make new attachment with properties {file name:(POSIX file aFile) as alias}
end repeat
save in POSIX file filePath
end tell
close front document saving no
end tell
end repeat
end tell
return
I know you can do something like what you may be looking for in command line.
ls path_to_folder > path_to_export_file.txt
Example:
ls ~/Desktop/ > ~/Desktop/export2.txt
I am pretty sure you would be able to integrate that into AppleScript to do whatever else you need.
I am working with Mac OSX 10.12.6 and have built an AppleScript to create an email and then attach a PDF and a jpeg file. When I run the script i get an error when trying to attach the pdf and jpeg files.
Mail got an error: Can’t make {file name:"MacintoshHD:Users:peteradam:PPAttachments:EmailFolder:Quote_15018_301017.pdf", file size:200339} into type properties of attachment.
The error message is repeated for the jpeg with the file name changed.
I have also tried setting theSignature and theAttachment1 as aliases to no avail.
The script is as follows:
set TheRecipient to "name"
set theAddress to "me#me.com"
set theSubject to "Expoprint "
set theContent to "When in Doubt DON'T"
set theSender to "Me <me#me.com>"
tell application "Finder" to set theSignature to "MacintoshHD:Users:peteradam:PPAttachments:EmailFolder:ExpoPrint Signature.jpg"
set theSignatureSize to 20530
tell application "Finder" to set theAttachment1 to "MacintoshHD:Users:peteradam:PPAttachments:EmailFolder:Quote_15018_301017.pdf"
set theAttachmentSize1 to 200339
tell application "Mail"
set theMessage to make new outgoing message with properties {subject:theSubject, content:theContent & return & return, visible:true}
tell theMessage
set sender to theSender
make new to recipient at end of every to recipient with properties {name:TheRecipient, address:theAddress}
try
make new attachment with properties {file name:theAttachment1, file size:theAttachmentSize1} at after last paragraph
set message_Attachment to 0
on error errmess
log errmess
display dialog errmess
set message_Attachment to 1
end try
log "message_attachment =" & message_Attachment
make new attachment with properties {file name:theSignature, file size:theSignatureSize} at after last paragraph
delay 1
end tell
end tell
I resolved the problem by removing the File Size properties
I receive a lot of customer vcards to a specific email address. I want to automatically add the vcards to my contacts through the Mail rules and an AppleScript.
I searched a lot and found something. I modified it a bit. And the opening and adding process works fine. But only when I choose a file. I can't get the file into a variable from the mail message. I tried it but it won't work.
Here is my code so far:
tell application "Mail"
set att to attachment
end tell
set thefile to att
tell application "Contacts"
activate
open thefile
end tell
tell application "System Events" to keystroke return
If I delete line 1, 2 and 3 and write in line 4 "set thefile to choose file" then it will work - if I choose a file.
But the first three lines I tried something out, but without any success.
So my question is, how can I get the file from the message?
Thank you
Yours sincerely,
Chris
Solution:
set Dest to ((path to desktop folder) as string)
tell application "Finder" to make new folder in Dest with properties {name:"TempFiles"} -- create TempFiles folder
Set Dest to Dest & "TempFiles:"
tell application "Mail"
activate -- not sure is mandatory, but I prefer to see selected mails !!
set ListMessage to selection -- get all selected messages
repeat with aMessage in ListMessage -- loop through each message selected
set AList to every mail attachment of aMessage -- get all attachements
repeat with aFile in AList -- for each attachement
if (downloaded of aFile) then
set Filepath to Dest & (name of aFile)
do shell script "touch " & (quoted form of (POSIX path of Filepath)) -- required because "Save" only works with existing file !
save aFile in (Filepath as alias) as native format
end if
end repeat -- next file
end repeat -- next message
end tell
tell application "Finder" to set CardList to every file of folder Dest whose name extension is {"vcf"}
tell application "Contacts"
activate
repeat with aCard in CardList
open aCard
delay 1
tell application "System Events" to keystroke return
end repeat
end tell
delay 2
-- tell application "Finder" to delete folder Dest
The file attached from email respond to the 'save" command, but not to 'open'. Then, you must first save the attached files, and later, move them to next application (add in 'Contacts' in your case).
The attachement is a member of a list of 'mail attachement' of a message : keep in mind that there could be many files attached.
Also, you can only save the attached file if its 'downloaded' attribute is true.
Last, but not least, it seems that the "save" instruction which was working nice in Snow Leopard, does not work the same in El Capitain : the file where to save must exist before the "save"...this is why I added the "touch" command to create it first (just create the entry in the tempFiles folder).
I also add at bottom of script the open vCard with the enter key to validate in Contact. You may have to add a delay to leave sometime for your computer to process the card.
if the keys broke does not work in your case, please check System Preferences accessibility settings to allow your computer to let your script control your Mac.
I added as much comments as possible to make it clear...may be too much !
set Dest to ((path to desktop folder) as string)
tell application "Finder" to make new folder in Dest with properties {name:"TempFiles"} -- create TempFiles folder
Set Dest to Dest & "TempFiles:"
tell application "Mail"
activate -- not sure is mandatory, but I prefer to see selected mails !!
set ListMessage to selection -- get all selected messages
repeat with aMessage in ListMessage -- loop through each message selected
set AList to every mail attachment of aMessage -- get all attachements
repeat with aFile in AList -- for each attachement
if (downloaded of aFile) then
set Filepath to Dest & (name of aFile)
do shell script "touch " & (quoted form of (POSIX path of Filepath)) -- required because "Save" only works with existing file !
save aFile in (Filepath as alias) as native format
end if
end repeat -- next file
end repeat -- next message
end tell
tell application "Finder" to set CardList to every file of folder Dest whose name extension is {"vcf"}
tell application "Contacts"
activate
repeat with aCard in CardList
open aCard
tell application "System Events" to keystroke return
end repeat
end tell
-- tell application "Finder" to delete folder Dest
As you can see, I filter the content of the temp folder with only files with extension 'vcd'...just in case your selected emails contain also other type of file which Contact can't handled.
At end of the script, I delete the temp folder. however, until you test it, I set this last row as a comment only (more safe !)