Search code examples
applescriptfile-renameautomatorfinder

How can I write an Applescript to change file extension to .eml?


I have the following workflow for Automator. The idea is that when I load a file into the email folder, then Automator will add the extension .eml. In practice this works fine with one exception. After I move a file into the email directory, Automator will pop-up the dialog box to select the file and confirm the extension name. Once this action is complete, the dialog box will pop-up again. I then have to manually hit the cancel button to stop the loop.

Is there a way to clean this up so that Automator will just take this action once? Also, is there a way to have this action take place without all the pop-ups and confirmations?

enter image description here

EDIT:

Okay, after viewing the comments I am now looking for some direction on an Applescript to accomplish the extension rewrite.


Solution

  • As discussed in the comments, the reason your folder action is being called twice is because it changes the file extension of any files it's given. Folder actions are triggered by any new files added to the watched folder; and by changing the file extension, you've effectively given the folder a new file that wasn't there before, hence the action is called again.

    Automator doesn't have much by way of flow control, so being able to redirect the action, or even terminate it, when it receives a file that it's already processed is pretty much impossible.

    Therefore, your best bet is to use AppleScript. To do this, delete all of the current actions from your workflow, and add a Run AppleScript action, which can be found in the Utilities category.

    Then paste this code into the text area:

        on run {input, parameters}
    
            set the text item delimiters of AppleScript to "."
    
            tell application "Finder" to ¬
                repeat with f in input
                    repeat 1 times -- An intentionally redundant loop
                        -- Allows us to move straight to the
                        -- next iteration of the outside loop
    
                        -- Ignore files that already have the ".eml" extension
                        if the name extension of f is "eml" then exit repeat
                        -- Ignore folders
                        if the kind of f is "Folder" then exit repeat
    
                        set the name extension of f to "eml"
                    end repeat
                end repeat
    
        end run
    

    If you skim the script, you'll see that there are instructions for it to ignore files that already have the extension .eml and also to ignore folders (just in case). The folder action will still be called twice, but once it reaches those lines during the second execution, the script will terminate.

    This is part of the reason that the general advice with regards to folder actions is to get the action to first move the files out of the watched folder into a separate folder, and then process them there, especially if there is going to be renaming and such taking place. This prevents actions and scripts being called a second time.

    In your case, the consequence was a mere inconvenience of having the alerts pop up a second time. However, in other cases, you can create an infinite processing loop that needs user intervention in order to terminate. An example of this would be an action that, rather than changing the file extension to .eml, simply added the extension to the end of the filename, so filename.txt would become filename.txt.eml, which would then become filename.txt.eml.eml and so on, ad infinitum.

    However, my personal feeling on this is that it's fine to keep files in the watched folder, as long as you can cater for the possibility of an action or script being recursively called.

    My script above does this with those lines telling it to ignore .eml files and folders.

    Another means to doing this is, as I said, moving the files elsewhere to be processed. This can include a sub-folder of the watched folder, as folder actions on get triggered by files added to the actual folder being watched, and not any of its sub-folders.

    If you wanted to use this method, then this script will do that for you:

        on run {input, parameters}
    
            set the text item delimiters of AppleScript to "."
    
            get some item of (input as list) as text
            set fol to the result & "::" as alias   -- The watched folder path
    
            tell application "Finder" to ¬
                repeat with f in input
                    repeat 1 times -- An intentionally redundant loop
                        -- Allows us to move straight to the
                        -- next iteration of the outside loop
    
                        -- Ignore files that already have the .eml extension
                        -- and all folders
                        if the name extension of f is "eml" then exit repeat
                        if the kind of f is "Folder" then exit repeat
    
                        -- Moving the file before renaming will prevent this
                        -- folder action from being called a second time
                        move f to folder "renamed" in folder fol
                        set the name extension of the result to "eml"
    
                    end repeat
                end repeat
    
        end run
    

    This moves the files it's given (with the exception of .eml files and folders) to a sub-folder in the "email" folder called "renamed". You can, of course, change this to anything you want. However, this script doesn't create the folder for you, so you'll have to make sure it exists yourself first. If not, the folder action will terminate, and nothing will happen.

    If you have any questions, leave a comment, and I'll get back to you.


    I actually did this by accident during testing of the second script. I was attempting to get the folder action to create the sub-folder if it didn't already exist. However, it ended up trying to create the sub-folder again and again and again before I had to terminate the script. Oops.