Go Back   The macosxhints Forums > Working with OS X > OS X Developer



Reply
 
Thread Tools Rating: Thread Rating: 3 votes, 5.00 average. Display Modes
Old 02-01-2009, 12:58 AM   #1
brainysmurf
Prospect
 
Join Date: Jan 2009
Posts: 26
Cannot make outgoing message in Mail from within perform rule action

I have searched high and low for others who have reported the following issue, which I'm seeing on two different computers (a MacBook Core Duo and a Mac Mini Core 2 Duo, both running. 10.5.6):

I wish to make a script that runs when a specific sort of email arrives in my inbox, which then interacts with Pages (I've left that part of the code out) to create a pdf file, and then sends that pdf file as an attachment in reply to the person who sent it to me.

The following script, which simply tells Mail to set up an outgoing message that I can see immediately, runs fine:


property pathtodesktop : path to desktop folder as text

on run
--using terms from application "Mail"
-- on perform mail action with messages theMessages for rule theRule
tell application "Mail"
set newone to make new outgoing message with properties {sender:"me@inbox.com", subject:"Testing", visible:true}
tell newone
make new to recipient with properties {address:"noone@in.particular"}
tell contents
make new attachment with properties {filename:((pathtodesktop & "knownfile.pdf") as alias)}
end tell
end tell
end tell
-- end perform mail action with messages
--end using terms from
end run


Now, converting this into a mail action, as the following:


property pathtodesk : path to desktop folder as text

--on run
using terms from application "Mail"
on perform mail action with messages theMessages for rule theRule
tell application "Mail"
set newone to make new outgoing message with properties {sender:"me@inbox.com", subject:"Testing", visible:true}
tell newone
make new to recipient with properties {address:"noone@in.particular"}
tell contents
make new attachment with properties {filename:((pathtodesktop & "knownfile.pdf") as alias)}
end tell
end tell
end tell
end perform mail action with messages
end using terms from
--on run


That latter code does nothing. When I add a 'display dialog' in the first instruction after the tell app "Mail" statement, that works, but then nothing happens. Further effort to put a try block with a display dialog in the on error block crashes Mail entirely, so after that I just had the on error block write to a file ... which reveals an Applescript error 100000 (no kidding!) of which I cannot find any documentation on whatsoever.

Again, this exact behavior occurred on both machines.

Probably I am completely misunderstanding the environment in which these perform mail actions occur ... but I don't seem to be finding anywhere where this sort of error is documented!

Any thoughts?

P.S. I have looked at command line solutions, for example Mutt, to send the pdf file but that introduces the install/setup headache so I could use any advice in that direction as well. But I really, really would prefer to use Mail.

Last edited by hayne; 02-01-2009 at 04:01 AM. Reason: coloured comments green for clarity
brainysmurf is offline   Reply With Quote
Old 02-01-2009, 08:47 AM   #2
brainysmurf
Prospect
 
Join Date: Jan 2009
Posts: 26
A typo on one of those lines:

tell contents

should be

tell content

No s. Still having the problem though.
brainysmurf is offline   Reply With Quote
Old 02-01-2009, 02:08 PM   #3
Red_Menace
All Star
 
Join Date: Mar 2006
Location: Littleton, Colorado, USA
Posts: 515
I know Leopard's Mail had a bug that wouldn't send a mail from a rule script - don't know if it is fixed yet (or considered a feature), but you might take a look at this solution.
__________________
MacBook Pro / OS X Yosemite (10.10) / Xcode 6.1 / RubyMotion FTW
Red_Menace is online now   Reply With Quote
Old 02-02-2009, 12:05 AM   #4
tw
Hall of Famer
 
Join Date: Apr 2007
Posts: 4,263
well, I can confirm it still has the featurebug. the error it throws is to the effect that loading the new editor window has to be done from the main application thread (rule actions run on a different thread.

that being said, though, you ought to be able to do what you want to do easily enough either by creating a standalone script application or by convincing Pages to run a script - either should (might) avoid the weird Mail issue. have you tried anything like that?
__________________
Philosophy is a battle against the bewitchment of our intelligence by means of language. -LW-
tw is offline   Reply With Quote
Old 02-02-2009, 02:33 AM   #5
brainysmurf
Prospect
 
Join Date: Jan 2009
Posts: 26
At least I understand the problem: a threading issue. That might also explain why crashes Mail when the error is thrown.

I'll try out that hacky solution... seems like it should work.

Apple really needs to fix that issue, I spend a few days up against that bug! Or at least document it somewhere.
brainysmurf is offline   Reply With Quote
Old 02-02-2009, 09:52 AM   #6
brainysmurf
Prospect
 
Join Date: Jan 2009
Posts: 26
Tried it and it works beautifully and perfectly. Ahhhhh. Thanks to all for the great tips.
brainysmurf is offline   Reply With Quote
Old 02-06-2009, 10:44 PM   #7
brainysmurf
Prospect
 
Join Date: Jan 2009
Posts: 26
Okay it looks like I spoke too soon on this one!

It works just fine when I apply the rule in Mail. You know, go to Preferences -> Rules -> open up the rule and make some change -> OK out -> Yes I want it to apply to current messages.

The action performs perfectly in this case. However, when I get an actual email it doesn't work.

It seems to me that Mail should have implemented this with a polling feature via a cron job or somesuch instead of calling this action from within that thread as is the current implementation. What a headache this has been.
brainysmurf is offline   Reply With Quote
Old 02-07-2009, 07:28 PM   #8
tw
Hall of Famer
 
Join Date: Apr 2007
Posts: 4,263
Quote:
Originally Posted by brainysmurf
Okay it looks like I spoke too soon on this one!

It works just fine when I apply the rule in Mail. You know, go to Preferences -> Rules -> open up the rule and make some change -> OK out -> Yes I want it to apply to current messages.

The action performs perfectly in this case. However, when I get an actual email it doesn't work.

ah, yeah, I've been bit by this issue before (sorry, I forgot or I'd have mentioned it). Mail rule actions work off of a reference to some list of received mail internal to Mail.app. basically, when Mail starts a connection to the server, the rule actions begin running, and as each piece of mail arrives (a process which can take several seconds per) the rule actions process them. this is also the reason it's on a separate thread. this means that when the rule action script starts running, the list of received messages is empty or incomplete, and that can muck up script execution.

here's the way I would do this, if I were going to do this. have a rule action script that does nothing except extract the information you want out of the email and write it to a text file. looks something like this:

Code:
property queueFolder : (path to home folder from user domain as text) & "mailQueue:"

using terms from application "Mail"
	on perform mail action with messages theMessages for rule theRule
		repeat with thisMessage in the messages
			tell application "Mail"
				set theFileName to sender of thisMessage
				set theText to subject of thisMessage & return & return & content of thisMessage
			end tell
			set fp to open for access alias queueFolder & theFileName with write permission
			write theText to fp
			close access fp
		end repeat
	end perform mail action with messages
end using terms from
then have a completely separate launchd plist (using the queuefolder trigger) that watches for files being added and runs a script using that data. the launchd item looks something like:
Code:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>Label</key>
	<string>stupid.mail.trick</string>
	<key>Program</key>
	<string>Path/to/script</string>
	<key>QueueDirectories</key>
	<array>
		<string>~/mailQueue</string>
	</array>
</dict>
</plist>
and the script it calls would look something like:
Code:
property queueFolder : (path to home folder from user domain as text) & "mailQueue:"

repeat
	tell application "System Events"
		try
			set theFile to file 1 of folder queueFolder
		on error
			-- no files in folder
			exit repeat
		end try
		set theFileName to name of theFile
	end tell
	if theFileName does not contain "DS_Store" then
		tell application "Mail"
			--create your new email here, using 
			--the information you extract from the file
		end tell
	end if
	tell application "System Events" to delete theFile
end repeat
it will surely take some tweaking, but this should do an end run around the threading issue in Mail.
__________________
Philosophy is a battle against the bewitchment of our intelligence by means of language. -LW-
tw is offline   Reply With Quote
Old 02-08-2009, 04:17 PM   #9
brainysmurf
Prospect
 
Join Date: Jan 2009
Posts: 26
Wow of course this is the ideal solution. Problem is that I've done all this, even tweaked it a bit. You'll want to pass the result of 'extract address from' for the file, and there's a typo. Anyway I cleaned up the target script:

property queueFolder : (path to home folder from user domain as text) & "mailQueue:"

tell application "System Events"
try
set thefile to file 1 of folder queueFolder
on error
-- no files in folder
exit repeat
end try
set theFileName to name of thefile
end tell

repeat
set theFileName to ""

tell application "System Events"
try
set thefile to file 1 of folder this_folder
on error
-- no files in folder
exit repeat
end try
set theFileName to name of thefile
end tell
if theFileName does not contain "DS_Store" then
tell application "Mail"
set firstline to read thefile until return
read thefile until return
set filecontents to read thefile
set filecontents to convert to Mac filecontents

my handle_mail_rule(theFileName, firstline, filecontents) --(sender, subject, message)
end tell
end if
tell application "System Events" to delete thefile
end repeat


And the rule script:

using terms from application "Mail"
on perform mail action with messages theMessages for rule theRule
tell application "Mail"
repeat with thisMessage in theMessages
set theFileName to extract address from (sender of thisMessage)
set theText to subject of thisMessage & return & content of thisMessage
set fp to open for access alias (queueFolder & theFileName) with write permission
write theText to fp
close access fp
end repeat
end tell
end perform mail action with messages
end using terms from


I'm having trouble linking the launchd to respond when the file is written. I've put it in the ~/Library/LaunchAgents folder and used launchctl to load it ... to no avail. I even converted the first script into a Folder Action. Nothing.

They work stand-alone though, and no errors are being thrown.

I have no idea what I'm doing wrong but thanks a lot for your help. Any chance you can swim me out of this one?
brainysmurf is offline   Reply With Quote
Old 02-09-2009, 10:56 AM   #10
brainysmurf
Prospect
 
Join Date: Jan 2009
Posts: 26
Solution Found:

Since I don't have developer tools installed I looked for a different workaround. After attempting to download plist editing apps, I had a brainstorm.

You can get around the threading issue simply with a do shell script "osascripts" and then passing the message information as an argument. This is very similar to a solution posted above, but in my version the script that is called by osascripts is saved externally as an Application.

This is probably the best "layman-savvy" way of solving the problem.

Will share when I've finalised the code.
brainysmurf is offline   Reply With Quote
Old 02-15-2009, 10:28 AM   #11
brainysmurf
Prospect
 
Join Date: Jan 2009
Posts: 26
After several iterations of code which I would rather not bother sharing, the best way to implement a make new outgoing message from within a mail rule is to simply not do so.

Instead, make an stay open applescript that polls for unread messages. It's the only way. Trust me.
brainysmurf is offline   Reply With Quote
Old 02-25-2009, 12:13 AM   #12
brainysmurf
Prospect
 
Join Date: Jan 2009
Posts: 26
Poll script

Here's what the polling script looks like. It needs to be saved as a "Stay Open" application, and would probably be best if you had it open at login after opening Mail.

Code:
on run
	-- do nothing special
end run

on idle
	tell application "Mail"
		try
			set allmsgs to every message of inbox whose read status is false
			
			repeat with thismsg in allmsgs
				if subject of thismsg is "whatever" then
					my handle_mail_rule(reply to of thismsg, subject of thismsg, content of thismsg)
					set read status of thismsg to true
				end if
			end repeat
			
		on error msg
			display dialog msg
		end try
	end tell
	
	delay 10
end idle

-- Allows script to be quit cleanly on shutdown or logout.
on quit
	continue quit
end quit

on handle_mail_rule (param1, param2, param3)
-- Pass this handler whatever is needed
end
brainysmurf is offline   Reply With Quote
Old 02-25-2009, 08:21 PM   #13
tw
Hall of Famer
 
Join Date: Apr 2007
Posts: 4,263
Smurf, a couple of points I feel compelled to mention:
  • Don't use 'Delay' in an idle handler. Replace the line 'Delay 10' with 'Return 10'. 'Delay 10' will cause the script to remain active (if delayed) for ten seconds, which eats up system resources. 'Return 10' tells the system send its next idle check in ten seconds (rather than the default one second). more efficient, that.
  • it really would be better to write a launchd item for this, rather than an stay-open app. launchd has the following advantages:
    • it will naturally thread if necessary (applescript doesn't thread)
    • it's much more efficient at handling resources than applescript apps
    • it has a better variety of event triggers (an applescript app would have to sit open all the time, waiting for info)
    • it's cooler.

'nough said
__________________
Philosophy is a battle against the bewitchment of our intelligence by means of language. -LW-
tw is offline   Reply With Quote
Old 02-26-2009, 05:07 PM   #14
naerey
Prospect
 
Join Date: Dec 2007
Posts: 11
Quote:
Originally Posted by tw
Smurf, a couple of points I feel compelled to mention:
  • Don't use 'Delay' in an idle handler. Replace the line 'Delay 10' with 'Return 10'. 'Delay 10' will cause the script to remain active (if delayed) for ten seconds, which eats up system resources. 'Return 10' tells the system send its next idle check in ten seconds (rather than the default one second). more efficient, that.
  • it really would be better to write a launchd item for this, rather than an stay-open app. launchd has the following advantages:
    • it will naturally thread if necessary (applescript doesn't thread)
    • it's much more efficient at handling resources than applescript apps
    • it has a better variety of event triggers (an applescript app would have to sit open all the time, waiting for info)
    • it's cooler.

'nough said

buuuuuuuut applescript is sooooo much easier to use... !!!
naerey is offline   Reply With Quote
Old 02-26-2009, 07:01 PM   #15
tw
Hall of Famer
 
Join Date: Apr 2007
Posts: 4,263
Quote:
Originally Posted by naerey
buuuuuuuut applescript is sooooo much easier to use... !!!

reminds me of that episode of the Simpsons where Homer buys a handgun, and then decides to use it for everything (opening cans, turning off lights...)
__________________
Philosophy is a battle against the bewitchment of our intelligence by means of language. -LW-
tw is offline   Reply With Quote
Old 02-27-2009, 05:58 AM   #16
brainysmurf
Prospect
 
Join Date: Jan 2009
Posts: 26
Point taken about launchd, but dude seriously I spent a day trying to get it to work and it didn't. But then I spent 10 minutes on the script and worked fine. And it doesn't use any processor time. So if you're talking about the difference between me not noticing it (with the applescript poll) and not noticing it (with launchd's event detection), then you're talking about no difference at all.

delay 10 was a rookie mistake, of course I meant return.

I'll give it another go, and will try it with a simpler project, but applescripting really is that much easier. And laymen can reuse it easier too.
brainysmurf is offline   Reply With Quote
Old 02-27-2009, 08:03 PM   #17
tw
Hall of Famer
 
Join Date: Apr 2007
Posts: 4,263
well, all THAT proves is that you're not a REAL geek. lol
__________________
Philosophy is a battle against the bewitchment of our intelligence by means of language. -LW-
tw is offline   Reply With Quote
Old 02-27-2009, 11:56 PM   #18
brainysmurf
Prospect
 
Join Date: Jan 2009
Posts: 26
Oh yeah every single code I write is to just to prove I belong. lol
brainysmurf is offline   Reply With Quote
Reply

Tags
applescript error, mail


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump



All times are GMT -5. The time now is 05:57 AM.


Powered by vBulletin® Version 3.8.7
Copyright ©2000 - 2014, vBulletin Solutions, Inc.
Site design © IDG Consumer & SMB; individuals retain copyright of their postings
but consent to the possible use of their material in other areas of IDG Consumer & SMB.