I'm new to Applescript and I've built this from code I've found online, and can't really get it to work.
What I want to do is the following
A rule in Apple Mail will trigger the script to find 2 text strings inside the body of the mail.
I want to extract two things from the e-mail
Due date (Återlämningsdatum)
Title of the book (Titel)
Then I want to create a todo in Things with the title of the book as name of the todo and the due date as due date.
The problem I run into now is that I don't get any data from the mail, just a empty todo is created.
Any ideas?
E-mail below
2017-03-22 18:43:55
MALMÖ STADSBIBLIOTEK
Stadsbiblioteket
Låntagarnummer: **********
Utlån
-------------------------
Titel: Ägg : recept & teknik / Tove Nilsson ; [fotografi: Charlie Drevstam]
Exemplarnummer: 3054550018
Återlämningsdatum: 2017-04-19
-------------------------
Antal utlånade material: 1
Code below
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
set subjectText to "Återlämningsdatum: "
set contentSearch to "Titel: "
using terms from application "Mail"
on perform mail action with messages theMessages for rule theRule
tell application "Mail"
set theContent to content
set theDate to my getFirstWordAfterSearchText(subjectText, theContent)
set theTitle to my getFirstWordAfterSearchText(contentSearch, theContent)
end tell
end perform mail action with messages
end using terms from
tell application "Things3"
set newToDo to make new to do
set name of newToDo to theTitle
set due date of newToDo to theDate
end tell
(*============== SUBROUTINES =================*)
on getFirstWordAfterSearchText(searchString, theText)
try
set {tids, AppleScript's text item delimiters} to {AppleScript's text item delimiters, searchString}
set textItems to text items of theText
set AppleScript's text item delimiters to tids
return (first word of (item 2 of textItems))
on error theError
return ""
end try
end getFirstWordAfterSearchText
In my testing, your script returns the following values:
theDate: "2017"
theTitle: "Ägg"
So, I'm assuming you should perhaps get a blank to-do named "Ägg" ? If not, you could try:
tell application "Things3" to make new to do with properties ¬
{name: theTitle, due date: theDate}
(although I neither use nor own Things 3, so cannot test this for you).
Anyway, to address the original problem, the issue is in only asking your handler getFirstWordAfterSearchText to return the first word. I don't speak Swedish, but it looks to me that the title contains more than one word. The date most definitely does, as each word is separated by a hyphen (which is considered a non-word character in AppleScript).
My suggestion would be to split the email content into paragraphs, isolate the lines of text that start with either "Titel" or "Återlämningsdatum", then return those lines, excluding any unwanted words. Here's a handler that does this:
to getFirstParagraphThatStarts on searchString ¬
from theText ¬
apart from excludedStrings : null
local searchString, theText, excludedStrings
repeat with P in theText's paragraphs
if P starts with the searchString then exit repeat
end repeat
set the text item delimiters to {null} & the excludedStrings
text items of P as text
end getFirstParagraphThatStarts
I called the handler much like you did yours:
set theDate to getFirstParagraphThatStarts on subjectText from theContent
set theTitle to getFirstParagraphThatStarts on contentSearch from theContent
(I omitted the apart from parameter to begin with, to test the return result before any exclusions were imposed). The return result was this:
theDate: "Återlämningsdatum: 2017-04-19"
theTitle: "Titel: Ägg : recept & teknik / Tove Nilsson ; [fotografi: Charlie Drevstam]"
Then I added in the apart from parameter:
set theDate ¬
to getFirstParagraphThatStarts on subjectText ¬
from theContent ¬
apart from subjectText
set theTitle ¬
to getFirstParagraphThatStarts on contentSearch ¬
from theContent ¬
apart from contentSearch
and the return results were as follows:
theDate: "2017-04-19"
theTitle: "Ägg : recept & teknik / Tove Nilsson ; [fotografi: Charlie Drevstam]"
which, I think, is more along the lines of what you are wanting.
ADDENDUM 1: Dates
Another thought I had regarding Things 3 is that the due date property might require an actual AppleScript date object, rather than just a string that looks like it might be a date. That is, "2017-04-19" might not be a valid due date. Again, I neither use nor own Things 3, so this is just speculation.
AppleScript date formats are intrinsically tied to your system settings. As I have my system date/time preferences set to use international ISO-8601 date representations, i.e. yyyy-mm-dd, I can create the AppleScript date object straight from theDate variable like so:
date theDate
If this is the case with you, and it turns out that you do require a date object, then you can simply set due date of newToDo to date theDate, or (if using my suggested code from above):
tell application "Things3" to make new to do with properties ¬
{name: theTitle, due date: date theDate}
If, however, your system settings are set differently, you'll need to construct the AppleScript date object yourself. Here's a handler that will do this:
to makeASdate out of {year:y, month:m, day:d}
local y, m, d
tell (the current date) to set ¬
[ASdate, year, its month, day, time] to ¬
[it, y, m, d, 0]
ASdate
end makeASdate
You would then use your theDate variable with this handler like so:
makeASdate out of {year:word 1, month:word 2, day:word 3} of theDate
--> date "Wednesday, 19 April 2017 at 0:00:00"
ADDENDUM 2: Scripting Mail (added 2018-08-12)
After further testing and debugging, you've found that there are other issues with your script that stop it from functioning. This was an oversight on my part, as I ought to have highlighted these errors initially, but became focussed on your handler returning incomplete strings that I neglected to come back to the rest of the script and address its other problems.
The problem section, as you've discerned, is this one here:
using terms from application "Mail"
on perform mail action with messages theMessages for rule theRule
tell application "Mail"
set theContent to content
set theDate to my getFirstWordAfterSearchText(subjectText, theContent)
set theTitle to my getFirstWordAfterSearchText(contentSearch, theContent)
end tell
end perform mail action with messages
end using terms from
You tell application "Mail" to set theContent to content, however, you haven't specified what the content belongs to (or, rather, implicitly, you've specified that the content belongs to application "Mail", which it doesn't).
Presumably, you wish to refer to the content of theMessages that are sent through to this script by your mail rules ?
The other major thing to note is that on perform mail action with messages is an event handler, i.e. it responds to an event taking place in Mail, which causes the handler to be invoked. Defining other handlers elsewhere in the script is perfectly fine; but having stray lines of code that don't belong to any explicit handler will therefore belong to an implicit (hidden) on run handler. This, in a way, is an event handler as well: it responds to a script being run, which is problematic if the script is also being asked to respond to a Mail event simultaneously.
Therefore, the tell app "Things3" block needs to be moved, and I imagine the variable declarations at the beginning need to be housed as well.
Bearing all this in mind, I reworked your script to quite a large extent, whilst also trying to keep it resembling your original so it was somewhat recognisable:
using terms from application "Mail"
on perform mail action with messages theMessages for rule theRule
set dateToken to "Återlämningsdatum: "
set titleToken to "Titel: "
repeat with M in theMessages
set theContent to getMessageContent for M
set datum to restOfLineMatchedAtStart by dateToken from theContent
set titel to restOfLineMatchedAtStart by titleToken from theContent
if false is not in [datum, titel] then
set D to makeASdate out of (datum's words as list)
createToDoWithDueDate on D given name:titel
end if
end repeat
end perform mail action with messages
end using terms from
to makeASdate out of {Y, M, D}
local Y, M, D
tell (the current date) to set ¬
[ASdate, year, its month, day, time] to ¬
[it, Y, M, D, 0]
ASdate
end makeASdate
to createToDoWithDueDate on D as date given name:N as text
tell application "Things3" to make new to do ¬
with properties {name:N, due date:D}
end createToDoWithDueDate
to getMessageContent for msg
local msg
tell application "Mail" to return msg's content
end getMessageContent
on restOfLineMatchedAtStart by searchString from theText
local searchString, theText
ignoring white space
repeat with P in theText's paragraphs
if P starts with the searchString then
set i to (length of searchString) + (offset of searchString in P)
try
return text i thru -1 of P
on error -- matched entire line
return ""
end try
end if
end repeat
end ignoring
false -- no match
end restOfLineMatchedAtStart
Now, as I don't use Mail and cannot test these mail rules out myself, there could be one or two minor tweaks that you'll discover need to be made before it's running properly. On the other hand, it might run correctly as it is, which would amaze me. But, having spent a lot of time thinking about each line of code, I'm hopeful it's close to what you need.
The major change you can see is that every piece of code now belongs inside a handler. The custom handlers each get called from inside the main event handler, on perform mail action with messages. I also changed some of the variable names, mainly as part of my mental debugging that was going on (I changed them several times, and have left them to what their last meaningful label was in my head).
Let me know how it goes. Report back any errors.
NOTE: Don't forget, however, that this script is designed to be called by the Mail application in response to a mail rule being actioned. Running it from within Script Editor will not do anything.
I wrote an application for my colleagues so that they can easily set their Outlook signature. Here is the code:
property includeInRandom : false
property sigName : "${signature.name}"
property sigContent : "${signature.content}"
try
tell application "Microsoft Outlook"
activate
set newOutlookSignature to make new signature with properties ¬
{name:sigName, content:sigContent, include in random:includeInRandom}
end tell
end try
The problem is that if a colleague changes his signature in the application and sets it in Outlook again there are two signatures with the same name. Is it possible to check if the current signature already exists and if it exists it should be edited/updated?
I don't have Microsoft Outlook, so I can't test my suggestions out, but I imagine you could get every signature whose name is sigName, then decide if you want to just delete them all and make a new one, or keep one, edit it, and delete the rest. I'm obviously working on the assumption there could be anywhere between 0 and N signatures sharing one name that have accumulated over time. From this standpoint, I'd say that deleting them all and making new one would be easiest coding wise, provided Outlook lets you delete a list of signatures the way, say, Finder lets you delete a list of files in a single command:
tell application "Microsoft Outlook" to delete every signature whose name is sigName
If it doesn't, you would have to construct a repeat loop and delete them one by one:
tell application "Microsoft Outlook" to repeat with S in ¬
(every signature whose name is sigName)
set S to the contents of S # (dereferencing)
delete S
end repeat
If you decide you want to keep one and edit it, then:
tell application "Microsoft Outlook"
set S to every signature whose name is sigName
if (count S) is 0 then
# make new signature
else
set [R] to S
delete the rest of S
set the content of R to the sigContent
end if
end tell
If delete the rest of S doesn't work, a repeat loop again will let you delete items 2 onwards individually, and keep just the first item to edit.
I'm sorry I can't test this for you, but it's at least an indication of how to go about trying to do it.
Okay i want to check to see if the "user" has entered a number above 10, but i do not know where to put it or how to do it.
set volume 10
say "Hello and Welcome to Tyler's Spam Bot"
set amount to text returned of (display dialog "How many times?" default answer "More than 10")
repeat amount times
tell application "Finder" to make new Finder window
if amount comes before 10 then
return true
else
return false
end if
end repeat
Check if the value can be converted to an integer using a try/on error block. If it can, continue, and ask if the number is greater than 10; if so, perform your action.
set received_integer to "False"
repeat while received_integer is not "True"
set amount to text returned of (display dialog "How many times?" default answer "More than 10")
try
set amt_as_int to amount as integer
if amt_as_int ≥ 10 then
set received_integer to "True"
repeat amt_as_int times
tell application "Finder" to make new Finder window
end repeat
end if
end try
end repeat
I am new to AppleScript and I cannot seem to find any good sources to help me with my problem.
Given a file with dates and descriptions:
September 5, 2013
Event 1.
September 8, 2013
Event 2.
etc.
I want to parse the file for the Date and event information, then create events in the Mac Calendar app that are at these days (with these descriptions ad the event titles). However, I am stuck with the following code:
tell application "Finder"
set Names to paragraphs of (read (choose file with prompt "Pick text file containing track names"))
repeat with nextLine in Names
set x to "Thursday, " & nextLine & " 12:00:00 AM"
if nextLine starts with "Sept" then
tell application "Calendar"
tell calendar "My Calendar"
make new event with properties {description:"Event Description", summary:"Event Name", location:"Event Location", start date:date x, allday event:true}
end tell
end tell
end if
end repeat
end tell
The code does not work yet because it complains about the improper date format, and on top of that I have no idea how I could get the second line to be read with the date line.
Any help would be appreciated, Thanks.
I solved the date parsing issue on my system by changing the external file format to:
5 September 2013
This could be a local system date format setting, as that is how mine is defined in the Language & Text - System Preference. Explore your settings first perhaps.
I've reworked your script a bit below to show you how to get at the event name by changing the loop to an index based one.
Also i've dropped the tell "Finder" block as it is not needed, you were not using any commands from the Finder in this case.
I also renamed some of your variables to be more legible (subjective), other tweaks are commented in the script.
set cal_data to the paragraphs of (read (choose file with prompt "Pick text file containing track names"))
set c to the count of cal_data
repeat with i from 1 to c
set currentLine to item i of cal_data
if currentLine contains "September" then
set dt to date (currentLine) -- Dropped the time as an all day event does not need this and the date parse will auto set it to 12:00am
set ev_name to item (i + 1) of cal_data -- The next item in cal_data should be the event name
tell application "Calendar"
tell calendar "My Calendar"
make new event with properties {description:"Event Description", summary:ev_name, location:"Event Location", start date:dt, allday event:true}
end tell
end tell
end if
end repeat
Hopefully this should get you onto the next steps.
I am trying to write a script that does the following job: it goes through all of the emails in the mailbox, finds the ones that have the word "French" in their subject line and then copies all the subject lines of those emails in a text file. Here is what I came up with
tell application "TextEdit"
make new document
end tell
tell application "Mail"
tell the mailbox "Inbox" of account "tigeresque#gmail.com"
set numm to count of messages
repeat with kk from 1 to numm
set wordsub to subject of the message kk
tell application "TextEdit"
if "French" is in wordsub then
set paragraph kk of front document to wordsub & return
end if
end tell
end repeat
end tell
end tell
Unfortunately, I keep receiving the error
"TextEdit got an error: The index of the event is too large to be valid."
and I have already spent a couple of hours trying to fix it without much success. Could you please take a look at my code and see what is wrong with it?
Your main problem is that the number of paragraphs in TextEdit and the number of email messages have nothing to do with each other, so if you're counting on the number of messages then TextEdit will not understand it. For example you may have 50 messages but TextEdit does not have 50 paragraphs so it errors. As such we just use a separate counter for TextEdit.
I made other changes too. I often see errors happen by having one "tell application" block of code inside another... so I separated them. Also notice that the only code inside of any "tell application" block is only what is necessary for that application to handle. This too avoids errors. These are good habits to have when programming.
Therefore give this a try...
set searchWord to "French"
set emailAddress to "tigeresque#gmail.com"
tell application "Mail"
set theSubjects to subject of messages of mailbox "INBOX" of account emailAddress
end tell
set paraCounter to 1
repeat with i from 1 to count of theSubjects
set thisSubject to item i of theSubjects
if thisSubject contains searchWord then
tell application "TextEdit"
set paragraph paraCounter of front document to thisSubject & return
end tell
set paraCounter to paraCounter + 1
end if
end repeat