I have searched a good bit and can’t seem to find the rather obvious method of how to send an ordinary email from within AppleScript using Mail.app for some reason. So here is my code so far, the comments explain everything, please someone educate this newbie! thanks in advance!
Les
-- Command Line Utility
-- by Les Hall
-- started 1-4-2014
-- AppleScript program to respond to an incoming email by executing the incoming subject as a
-- command line entry and email the result back to the originator. This is the off-world component
-- of a Second Life product that allows shell scripts to be executed from within Second Life.
-- begin main program
tell application "Mail" -- we are going to be interacting with Mail.app here
set theMessage to selection -- not sure, selection must be the incoming email
repeat with this_message in theMessage -- not sure why repeat, in case of many messages?
set message_subject to subject of this_message -- sets a variable to the incoming email subject
set response to do shell script message_subject -- executes the command and saves result
-- here add extract of return email address from the original sender or the body
-- here add command to send email back with same subject and body is the response
end repeat -- end of repeat statement
end tell -- end of tell statement
-- end of main program
-- Command Line Utility
-- by Les Hall
-- started 1-4-2014
-- AppleScript program to respond to an incoming email by executing the incoming subject as a
-- command line entry and email the result back to the originator. This is the off-world component
-- of a Second Life product that allows shell scripts to be executed from within Second Life.
-- begin main program
tell application "Mail" -- we are going to be interacting with Mail.app here
set theMessage to selection -- not sure, selection must be the incoming email
set message_subject to subject of theMessage -- sets a variable to the incoming email subject
set response to do shell script message_subject -- executes the command and saves result
-- here add extract of return email address from the original sender or the body
set message_sender to sender of theMessage
-- here add command to send email back with same subject and body is the respons
set this_message to make new outgoing message with properties {subject:message_subject, recipient:message_sender, content:response}
send this_message
end tell -- end of tell statement
-- end of main program
Hi. Welcome to the forum. You asked about the repeat loop… repeating allows you to traverse the list that results from getting your selection. Your outgoing message must also have a to recipient. I formatted this example, but it’s semi-untested.
tell application "Mail" to repeat with aMessage in (get selection) -- assumes you've selected one or more messages
set {message_subject, message_sender} to aMessage's {subject, sender}
set response to my runwith(message_subject) --assumes the shell will return text from a properly formatted command
tell (make new outgoing message with properties {subject:message_subject, content:response, visible:true})
(make new to recipient at to recipients's end with properties {address:message_sender})
send
end tell
end repeat
on runwith(this)
run script (this)
end runwith
I tested it and got it to work! Actually the AppleScript part is working and most of the Second Life part is working, but it still does not actually receive the emails and display them to the user. I’ll work on that now, so in the mean time here is the code that works:
tell application "Mail" to repeat with aMessage in (get selection) -- assumes you've selected one or more messages
set {message_subject, message_sender} to aMessage's {subject, sender}
set response to do shell script message_subject -- executes the command and saves result
tell (make new outgoing message with properties {subject:message_subject, content:response, visible:true})
(make new to recipient at to recipients's end with properties {address:message_sender})
send
end tell
end repeat
please note that i had to change the shell script command back to what worked in the first place, but all the rest of the code is identical to that provided by Marc. Good job mark, you did your good deed for the day in helping this newbie out! I’ll report when the whole system works properly, and thanks so much!
Hmmm… after further testing I believe the script will need just a tiny bit of fine tuning.
The main issue is that the script is triggering off of the keyword “selection” which is really confusing when you’ve been looking at emails, a new one comes in, and your selection from previous use is what gets sent to the script rather than the new email. The script needs to be updated in such a way that it always grabs the newest message, and in this case it should be only one of them at all times, so we can just grab the most recent message or better yet a way to refer to the message that triggered the Mail.app rule that ran the script.
There may be other concerns, but that one is the major one. Anyone care to have a try at modding what we’ve produced so far?
Oops. My brain jumped its rails; in my initial post, I used “run script” instead of “do shell script,” however, it’s still a good practice to keep standard addition commands outside the main body.
I’m not sure if simply grabbing the newest message will actually work reliably, but that example is below; receiving more than one email at a time”even if it’s just junk mail”may interfere with the expected operation. Is there some commonality”such as the sender being in a group or the subject containing a common word”that could be the basis of a rule that triggers the script? I recall that there have been some recent Mail-related scripts that worked with rules, but my experience in Mavericks has left me with the impression that the on perform mail action handler may not work properly.
tell application "Mail"
set aMessage to inbox's message 1 --assumes the most recent message is a valid target
set {message_subject, message_sender} to aMessage's {subject, sender}
set response to my runwith(message_subject) --assumes the shell will return text from a properly formatted command
tell (make new outgoing message with properties {subject:message_subject, content:response, visible:true})
(make new to recipient at to recipients's end with properties {address:message_sender})
send
end tell
end tell
on runwith(this)
do shell script (this)
end runwith
Thank you for your continued attention to this post, I will try your code next. The Mail.app rules in the preferences panel to the far right do what you mention. The rule says if the recipient is my email address and the sender ends with @lsl.secondlife.com, then the applescript will be run. So there is already sufficient filtering so that only the desired messages go to the applescript.
To understand how the whole thing works may be helpful if only for curiosity’s sake. In Second Life I am wearing an invisible object containing a script that i wrote in the Linden Scripting Language, the one used in Second Life. When I type “computer pwd” into local chat, this script sends an email to my account that simply says “pwd” in the subject line and contains a body who’s last line is the sender email address (which is different from the sender of the email because of the email handling method). This triggers a rule to run the applescript, which then runs the subject as a shell script and reports the result back to applescript as a variable. this result then gets emailed back to the sending object which displays the email contents in an instant message to me.
So in simpler terms, my SL object, when commanded, sends an email that triggers an applescript to run a shell script and return the results back via email to the SL object which then tells me the results. This is an interesting product because it enables shell scripting to be done remotely by an in world object. I’ll add presets for things like netstat and trace route and have some fun with it!
OK, I got this to work in the system it’s intend to work within, so all is good. Here is the code:
Les
tell application "Mail"
set aMessage to inbox's message 1 --assumes the most recent message is a valid target
set message_subject to aMessage's subject
set message_sender to paragraph 5 of aMessage's content
set message_sender to (characters 1 thru ((length of message_sender) - 1) of message_sender) as rich text
set response to my runwith(message_subject) --assumes the shell will return text from a properly formatted command
tell (make new outgoing message with properties {subject:message_subject, content:response, visible:true})
(make new to recipient at to recipients's end with properties {address:message_sender})
send
end tell
end tell
on runwith(this)
do shell script (this)
end runwith
Hello, again. For clarity, there is no direct filtration provided by a rule to a script; it’s just a trigger. If you have 2 or more incoming messages and only one initiates the script, the wrong email may be evaluated.
To make this more reliable, you can either wrap the body of the code in a mail action handler similar to the below example or roll your own whose clause as a filter.
using terms from application "Mail"
on perform mail action with messages theMessages --what the rule filtered
tell application "Mail" to repeat with aMessage in theMessages
end repeat
end perform mail action with messages
end using terms from
--or something along these lines (which may be slower):
tell application "Mail" to set aMessage to inbox's message 1 whose subject is "pwd"
I bring you strange news! I got the whole system working, wrote an instructions notecard, and put the whole thing up for sale open sourced, or “full perms” as it is called in Second Life. What happened was, the first person who bought it responded to my thank you message by explaining to me (very politely, thankfully) that the system had a security flaw so big you could drive a Mac truck through it! A Mac truck sized security hole on a Mac computer is just too weird to be funny, I say! So I withdrew the product and left a humorous status message informing everyone of what happened in this Second Life forum thread:
As it turns out, the security flaw can be sealed up fairly well with encryption and authentication, so perhaps there is some future for this product after all. At least we got it working, yay for that!
What, exactly, was for sale? I see that someone on the site found “your program” to be well written… should I be flattered or offended that some code I provided was incorporated into a commercial product without my knowledge?
I’m going to hazard a guess that the security issue was in the idea itself”letting an email have unfettered access to run commands; yes, I see how that could be risky if someone besides the user knew there was a client on the other side and was being malicious. :rolleyes:
Oh wow I didn’t even think of the fact that your work is in this product, and I am usually so responsible about such issues. Thank you so much for mentioning this. OK, here’s the deal: I put it up as a product on the Second Life marketplace for L$250 which is about one dollar US. Then I took it off the marketplace because someone warned me of the security flaw and refunded that persons purchase, so i actually lost L$13, lol, which is about a nickel!
However it is good that you mentioned this because there is a second monetary issue here, and this one is not a slow stream of dollars, it is a $10,000 reward for finding a security flaw in the Linden Labs systems. I was told in the other thread to file a SEC JIRA in their system informing them of the issue and they say that sending out an email does not constitute a security risk. So right now, they are not in any position of coughing up 10k US, however that can change.
At this point i am considering option including making security exploits using their Linden Scripting Language or possibly relisting the L$250 item for sale. We should discuss what percentage of the profit you would like to receive for your contributions in case anything ever pays out.