I'm sending out a whole bunch of individual text messaged using AppleScript on a MacBook laptop linked to an iPhone.
If I create a message, copy paste it manually into Messages, and send that out manually, one message at a time (copy paste message, copy paste phone number, send) things works just fine. I can easily format the message in my draft, and the formatting is retained. If I try to do this via script, the linefeeds get lost.
Desired message:
Hello Everybody,
This is going to be a special meeting taking place on Friday, 10AM.
Please call in to the group meeting, access line xxxxxxxxxxx
Topic of Discussion: Quarterly Sales.
Great Job everybody, Sales are thru the roof this quarter; We're all
getting pay raises, yippee. Details shared at the meeting.
Again, thanks to all
Susan,
Sales Manager
And this is how it arrives.
Hello Everybody,This is going to be a special meeting taking place on
Friday, 10AM. Please call in to the group meeting, access line
xxxxxxxxxxxTopic of Discussion: Quarterly Sales. Great Job everybody,
Sales are thru the roof this quarter; We're all getting pay raises,
yippee. Details shared at the meeting. Again, thanks to all Susan,
Sales Manager
And here is the appleScript:
set textMessage to "Hello Everybody,\n\nThis is going to be a special meeting taking place
on Friday, 10AM. Please call in to the group meeting, access line xxxxxxxxxxx\n\nTopic
of Discussion: Quarterly Sales. \n\nGreat Job everybody, Sales are thru the roof this
quarter; We're all getting pay raises, yippee. Details shared at the meeting.
\n\nAgain, thanks to all \n\nSusan, \nSales Manager\n"
set phonelist to {"1999-555-6850", "1999-555-9496", "1999-555-7170", "1999-555-4445",
"1999-555-1182", "1999-555-7463", "1999-555-1809", "1999-555-8916", "1999-555-5139",
"1999-555-5252", "1999-555-6646", "1999-555-3642", "1999-555-2437", "1999-555-0755",
"1999-555-8732", "1999-555-6202", "1999-555-0310", "1999-555-7410", "1999-555-3300",
"1999-555-0655"}
set i to 0
activate application "Messages"
tell application "System Events" to tell process "Messages"
repeat with indPhone in phonelist
set i to i + 1
key code 45 using command down -- press Command + N to start a new window
keystroke indPhone -- input the phone number
delay 1
key code 36
key code 36 -- press Enter to focus on the message area
keystroke textMessage -- type some message
delay 1
key code 36 -- press Enter to send
say i
delay 5 -- Audio plus delay = success tracking.
-- If for some reason something goes wrong, I know where I am.
-- e.g. phone rings during the process.
end repeat
end tell
Note: reference.
Note#2. Oh, and note this isn't the actual message being sent. It's just a contrived sample for StackOverflow. This audience receiving the messages just doesn't understand what happens when someone replies to a group message. They just don't get it, sigh. So no, group text pages are NOT the answer. We want individual text messages, one per person. But thanks for that suggestion. Typically we're sending out just less than 100 messages with this technique, at one time.
Any thoughts on why we're losing the \n formatting when this runs as a script? If you run this exact script on your Mac, do you see the same results?
Edit: I'm going to share some screen shots off the phone.
What I want (created via manual copy & paste into Messages app):
Here's what I get with the script above (/n/n):
And here's what I get with the RobC & return & technique. (See comments)
Just dealing with the 'newline' problem... To get an inline carriage return you need to type control-return. To accomplish that with AppleScript, break the textMessage variable up into a list of paragraphs, then keystroke in each paragraph followed by key code 36 using control down to make the paragraph break.
set textMessageParts to {"Hello Everybody,", "", "This is going to be a special meeting taking place on Friday, 10AM. Please call in to the group meeting, access line xxxxxxxxxxx", "", "Topic of Discussion: Quarterly Sales.", "", "Great Job everybody, Sales are thru the roof this quarter; We're all getting pay raises, yippee. Details shared at the meeting. ", "", "Again, thanks to all", "", "Susan,", "Sales Manager"}
-- empty strings are added above to make two sequential line breaks
set phonelist to {"1999-555-6850", "1999-555-9496", "1999-555-7170", "1999-555-4445", "1999-555-1182", "1999-555-7463", "1999-555-1809", "1999-555-8916", "1999-555-5139", "1999-555-5252", "1999-555-6646", "1999-555-3642", "1999-555-2437", "1999-555-0755", "1999-555-8732", "1999-555-6202", "1999-555-0310", "1999-555-7410", "1999-555-3300", "1999-555-0655"}
set i to 0
activate application "Messages"
tell application "System Events" to tell process "Messages"
repeat with indPhone in phonelist
set i to i + 1
keystroke "n" using command down -- press Command + N to start a new window
keystroke indPhone -- input the phone number
delay 1
key code 36
key code 36 -- press Enter to focus on the message area
repeat with thisPara in textMessageParts
keystroke thisPara -- type one paragraph from the list
key code 36 using control down -- type an inline line break
end repeat
delay 1
key code 36 -- press Enter to send
say i
delay 5 -- Audio plus delay = success tracking.
-- If for some reason something goes wrong, I know where I am.
-- e.g. phone rings during the process.
end repeat
end tell
This code works (partially adapted from here):
set textMessage to "Hello Everybody,\n\nThis is going to be a special meeting taking place
on Friday, 10AM. Please call in to the group meeting, access line xxxxxxxxxxx\n\nTopic
of Discussion: Quarterly Sales. \n\nGreat Job everybody, Sales are thru the roof this
quarter; We're all getting pay raises, yippee. Details shared at the meeting.
\n\nAgain, thanks to all \n\nSusan, \nSales Manager\n"
set phonelist to {"1999-555-6850", "1999-555-9496", "1999-555-7170", "1999-555-4445",
"1999-555-1182", "1999-555-7463", "1999-555-1809", "1999-555-8916", "1999-555-5139",
"1999-555-5252", "1999-555-6646", "1999-555-3642", "1999-555-2437", "1999-555-0755",
"1999-555-8732", "1999-555-6202", "1999-555-0310", "1999-555-7410", "1999-555-3300",
"1999-555-0655"}
repeat with indPhone in phonelist
tell application "Messages"
set targetService to (id of 1st service whose service type = iMessage)
set theBuddy to buddy ("+1" & indPhone) of service id targetService
send textMessage to theBuddy
end tell
end repeat
So it turns out when I upgraded the macOS to Big Sur version 11.0.1 the script provided by Ted Wrigley crashed. Here is a corrected version, ready for copy paste.
set textMessageParts to {"Hello Everybody,", "", "This is going to be a special meeting taking place on Friday, 10AM. Please call in to the group meeting, access line xxxxxxxxxxx", "", "Topic of Discussion: Quarterly Sales.", "", "Great Job everybody, Sales are thru the roof this quarter; We're all getting pay raises, yippee. Details shared at the meeting. ", "", "Again, thanks to all", "", "Susan,", "Sales Manager"}
-- empty strings are added above to make two sequential line breaks
set phonelist to {"1999-555-6850", "1999-555-9496", "1999-555-7170", "1999-555-4445", "1999-555-1182", "1999-555-7463", "1999-555-1809", "1999-555-8916", "1999-555-5139", "1999-555-5252", "1999-555-6646", "1999-555-3642", "1999-555-2437", "1999-555-0755", "1999-555-8732", "1999-555-6202", "1999-555-0310", "1999-555-7410", "1999-555-3300", "1999-555-0655"}
set i to 0
activate application "Messages"
tell application "System Events" to tell process "Messages"
repeat with indPhone in phonelist
set i to i + 1
keystroke "n" using command down -- press Command + N to start a new window
delay 1
keystroke indPhone -- input the phone number
delay 1
key code 36
key code 36 -- press Enter twice to focus on the message area
repeat with thisPara in textMessageParts
keystroke thisPara -- paste one paragraph from the list
key code 36 using shift down -- insert an inline line break
end repeat
delay 1
key code 36 using command down -- press Command Enter to Send
log ("SMS completed: " & indPhone) -- Text completed to this phone #
say i -- audible progress feedback
delay 3 -- Delay to provide an opportunity to stop the script here.
-- If for some reason something goes wrong, I know where I am.
-- e.g. phone rings during the process.
end repeat
end tell
I wanted to add a few lessons learned in fixing this thing:
The log is probably a better way to track progress than an audio clue. You do have to make the log area visible in the Script Editor via top menu --> View --> Show Log. You will want to be in the "Messages Tab" to see the log entries.
key code {57, 36} is not the same as key code 36 using shift down. Not sure what's up with that. One method works, one does not.
Before you start the script / macro you need to ensure Messages is open and running on the MacOS.
You don't want to start the macro while Messages is half way complete with a previous message. Odd things happen.
Stopping the program while the macro is running is problematic. If you are stopping the action during the middle of a paste operation, the content intended for the Messages ends up pasted in the middle of the Script Editor. That was a total mess. If you must stop, ensure you haven't corrupted your original script.
For really long lists of phone numbers, you may need to use "option L" at end of each line as continuation character (¬) per S.O.63927015
Many thanks to Ted Wrigley for his input on the original question.
So, I finally got tired of manually sorting and archiving email on my Mac to get around some archaic mailbox size limits. I'm not a fan of the way Apple handles mail archiving, so I dug into a few examples that others had written to sort mail and slapped a short script together to filter through my email and archive everything older than 90 days. For the most part, easy stuff.
It is a tad annoying that Mail doesn't see "On My Mac" as a local account, so you need to adjust the code to blindly reference mailbox names.. but.. it works.
I think I'm just having an evaluation problem. I can sort the "Inbox" and archive mail from there quite easily.
on archive_email(target_account, target_mailbox, destination_account, destination_mailbox, oldemaildate)
tell application "Mail"
#Identify messages that need to be moved. If unread messages shouldn't be moved, change the end of the variable definition to read "is less than oldsentdate and read status is true)
set _msgs_to_capture to (every message of mailbox target_mailbox of account target_account whose date received is less than oldemaildate)
repeat with eachMessage in _msgs_to_capture
set archiveMailbox to (mailbox (destination_mailbox as string))
move eachMessage to archiveMailbox
end repeat
end archive_email
This doesn't work for the "Sent" folder, however. My guess is that the evaluation "whose date received is less than" is improper for the "sent" folder. Sadly, "whose date sent is..." doesn't seem to work either. I'm struggling to find the right variable and evaluation here.
The line bellow is perfectly working, assuming target_account and oldmaildate have correct values. To be sure, I replaced target_mailbox directly by "Sent Messages" :
set _msgs_to_capture to every message of mailbox "Sent Messages" of target_account whose date sent is less than oldemaildate
Please check values/types of your variables.
Also, I suggest you set the line below before the repeat loop and not inside, to increase speed :
set archiveMailbox to (mailbox (destination_mailbox as string))
You can do away with the repeat loop, which is inefficient, and achieve the move with a single command:
on archive_email(target_account as text, target_mailbox as text, ¬
destination_account as text, destination_mailbox as text, ¬
oldemaildate as date)
tell application "Mail" to ¬
move (every message ¬
of mailbox target_mailbox ¬
of account target_account ¬
whose date sent ¬
is less than oldemaildate) ¬
to mailbox destination_mailbox
end archive_email
Use date sent for Sent items, which I can confirm works.
System info: AppleScript version: "2.7", system version: "10.13.4"
I want my script to be listening/detecting any keystroke(any key pressed) via keyboard. If no key is pressed for about 5seconds, then continue to do something. Otherwise, keep on recording the keys pressed in a text edit.
Any help would be greatly appreciated.
Since you specified TextEdit in your question, I wrote a script for you that checks for changes in a TextEdit document within the specified number of seconds. Do note that this only detects keys that input something into the document, so it's not exactly what you wanted. However, there's no way to detect any and every key being pressed in raw AppleScript, so this is the closest you can get (unless someone wrote a Scripting Addition or agent application to do that).
Here's the script, hope it is of use:
global lastText, lastTime, startTime
on run
set lastText to application "TextEdit"'s (text of the document of the front window)
set lastTime to current date
set startTime to current date
repeat
if (checkForRecentTextUpdate given seconds:5) is true then
-- Do something while the user is typing
else
-- Do something after the user has stopped typing
exit repeat -- This is only an example
end if
end repeat
end run
to checkForRecentTextUpdate given seconds:secsRequired
tell application "TextEdit"
-- If midnight just passed, reset the last time
if (the day of (the current date)) > (the day of the lastTime) ¬
then set lastTime to current date
-- If we just started, we can't judge; give a positive
if ((the time of (the current date)) - (the time of the startTime)) < secsRequired ¬
then return true
-- If there have been changes since the last run, update info
if (the text of the document of the front window) ≠ the lastText then
set lastTime to the current date
set lastText to the text of the document of the front window
end if
-- If the specifiied number of seconds has passed without any text updates, give a negative
if ((the time of (the current date)) - (the time of the lastTime)) ≥ secsRequired ¬
then return false
-- If we got this far, there were changes in the seconds specified; give a positive
return true
end tell
end checkForRecentTextUpdate
I have the below Applescript for Outlook 2011 (at bottom). I'm trying to move Inbox messages older than four months to the "on my computer" folder (on my computer of application).
When I run the script, this line always seems to return true, so it archives every message:
if time received of msg > (current date) - 4 * (4 * weeks) then
I'm posing this Nov 5, and the oldest messages in my inbox are Sep 1, so this if statement should not trigger.
Here is the Events log of a sample run:
tell application "Microsoft Outlook"
activate
get every message of inbox
count every message of inbox
current date
end tell
tell current application
current date
end tell
tell application "Microsoft Outlook"
get time received of item 1 of every message of inbox
(*time received of item 1 of every message of inbox*)
move item 1 of every message of inbox to on my computer
current date
end tell
tell current application
current date
end tell
tell application "Microsoft Outlook"
get time received of item 2 of every message of inbox
(*time received of item 2 of every message of inbox*)
move item 2 of every message of inbox to on my computer
current date
end tell
tell current application
current date
end tell
tell application "Microsoft Outlook"
get time received of item 3 of every message of inbox
(*time received of item 3 of every message of inbox*)
move item 3 of every message of inbox to on my computer
Full script:
tell application "Microsoft Outlook"
activate
if messages of inbox = {} then
error "No messages."
error -128
end if
repeat with msg in messages of inbox
if time received of msg > (current date) - 4 * (4 * weeks) then
move msg to on my computer
end if
end repeat
end tell
4 * (4 * weeks) is 4 months ago from Nov 5th, so that's about July 5th. If your time of message is Sept 1 then it surely will trigger it because Sept 1 is greater than July 5. Maybe you meant to use the less than (i.e. <) sign?
I am trying to create a simple program that loops for user speech input using com.apple.speech.recognitionserver. My code thus far is as follows:
set user_response to "start"
repeat while user_response is not equal to "Exit"
tell application id "com.apple.speech.recognitionserver"
set user_response to listen for {"Time", "Weather", "Exit"} with prompt
"Good Morning"
end tell
if user_response = "Time" then
set curr_time to time string of (the current date)
set curr_day to weekday of (the current date)
say "It is"
say curr_time
say "on"
say curr_day
say "day"
else if user_response = "Weather" then
say "It is hot outside. What do you expect?"
end if
end repeat
say "Have a good day"
If the above is run on my system it says good morning and it then pops up with the speech input system and waits for either Time, Weather, or Exit. They all do what they say they are going to do, but instead of looping if I say Time and Weather and asking again until I say exit the speechserver times out and never pops up again. Is there a way of either keeping that application open until the program ends or is applescript not capable of looping for user speech input?
If you don't find a way to keep speech recognition open, try adding a delay before you call it again. I recall (long ago) finding that events can be just lost if you try to send an event to an application that's already in the middle of quitting (it doesn't reopen the application).
Before your end Repeat add
tell application "SpeechRecognitionServer"
quit
end tell
After about 35 seconds it will repeat, it is slow as honey on a cold day but it works. give it a try.
Here is a Simple Example:
repeat
tell application "SpeechRecognitionServer"
set theResponse to listen for {"yes", "no"} with prompt "open a finder?"
set voice to (theResponse as text)
end tell
if voice contains "yes" then
tell application "Finder"
activate
end tell
else
say "not understood"
end if
tell application "SpeechRecognitionServer"
quit
end tell
end repeat