AppleScript - new note

Hi,

Let me first explain where I want to go, what I want to (try) to do:
For many years I have used and still use Veritrope - Justin Lancy’s scripts to save browser tags to DEVONthink. Link to Veritrope code library.
There’s a ton of smallish scripts to add stuff to Evernote, Devonthink, Omnifocus just to name a couple. Probably many Tinderboxers are familiar with them. Most of the scripts I use are called by Alfred.app in combination with a keyboard shortcut. (similar of what Dominique Renauld is doing, mentioned here on the forum as well)

Now to my question:
I searched the forum on how to create a note using AppleScript, and of course plenty of answers came up. Among the ones that were most promising, I chose @dmrogers example Captain’s Log as a starting point. (link)

I do have a copy of Script Debugger, but have not used this tool very much.
The AppleScript errors out on the line that says:

set newNote to make new note at theContainer

What needs to be changed to the code in order to make a new note?
What am I missing / why does the code fail?

At the bottom of the Script Debugger’s window, it says: Stopped (Error: Can’t make missing value into type location specifier.)

For completenes sake, I add my full code below:

tell application "Tinderbox 10"
	set this_moment to (the current date)
	set nmMonth to (month of this_moment) as string
	set nmYear to (year of this_moment) as string
	set thePath to "Captain's Log/" & nmYear & "/" & nmMonth & " " & nmYear & "/" & date string of this_moment
	tell document "Captain's Log.tbx" -- suffix .tbx required on my machine
		-- this is how to specify a note down in the hierarchy:
		set theContainer to find note in it with path thePath
		set newNote to make new note at theContainer
		tell newNote
			if entryTitle is not missing value then set value of attribute "Name" to entryTitle
			set value of attribute "Text" to entryText
			set value of attribute "Prototype" to "p_Entry"
		end tell
	end tell
end tell

As always: Thanks for helping out!

I just ran the script to enter an email into the log and it worked fine, my first instinct is that there’s something missing in your Tinderbox file.

I think I uploaded the tbx file back then, but I didn’t see it when I glanced through the thread. If you’re using the file I created, it should have automatically created a 2025 container beneath the Captain’s Log root container, and 2025 should have created a January 2025 container, all of which are required for thePath to match up with the document.

If you’re not using the file I created, or you’ve changed the name of the document or root container, you’ll have to change the references to “Captain’s Log” within the script to whatever you’ve named your file, and whatever the root container is named, and ensure it created the relevant 2025 and January 2025 containers.

Also, are you using Tinderbox 10?

I’m guessing it’s failing because the AS variable thePath doesn’t correspond with the structure of your document. Which, if it’s my file, would be odd.

Let us know and we’ll figure it out.

Thanks for chiming in!

I’ll have a proper look at it tomorrow in the morning.
I’m using Tinderbox 10 allright, but I think I have tried to port the script to a new file of my own. I’ll see if I can figure out the the AS variable thePath and adjust it to my file.

I’ll let you know, thanks again!

1 Like

The script you are trying to adapt is looking for a container named ‘Captain’s Log’ and within that a specific note. If it can’t find those in your document it will throw an error.

To get started you might try something simple like this. Have your document open and run this:

tell front document of application "Tinderbox 10" to make new note

That’s all there is to it! Tinderbox creates a note. But maybe not where you want it.

Let’s say you have a container at the root level named “My New Notes.” You want AppleScript to tell Tinderbox to make a new note and put it in there.

All you need to do is this:

tell front document of application "Tinderbox 10" to make new note in note "My New Notes"

Let’s say you want Tinderbox to name the note “A Brilliant Thought” at the same time that it creates it.

This will do that:

tell front document of application "Tinderbox 10" to make new note in note "My New Notes" with properties {name:"My Brilliant Thought"}

Now, suppose you want to get little fancier. You want to have AppleScript tell Tinderbox to create a new note at your specified location, give it a name, set the value of $MyString to “8888”, a lucky number for the Lunar New Year, and show MyString (and for good measure MyNumber) in DisplayedAttributes.

tell front document of application "Tinderbox 10"
	set newNote to make new note in note "My New Notes" with properties {name:"My Brilliant Thought"}
	tell newNote
		set value of attribute "MyString" to "8888"
		set value of attribute "DisplayedAttributes" to "MyString;MyNumber"
	end tell
end tell

Now let’s say you get more ambitious (or more lazy about doing things yourself). You want AppleScript to tell Tinderbox to create the note and link it to a note named “My Target Note” in the same container and label the link “agree.”

You can do that by telling AppleScript to tell Tinderbox to run Tinderbox action code, much easier than it sounds:

tell front document of application "Tinderbox 10"
	set newNote to make new note in note "My New Notes" with properties {name:"My Brilliant Thought"}
	set targetNote to note "My Target Note" in note "My New Notes"
	tell newNote
		set value of attribute "MyString" to "8888"
		set value of attribute "DisplayedAttributes" to "MyString;MyNumber"
	end tell
	my linkFromNoteToNote("agree", newNote, targetNote)
end tell

on linkFromNoteToNote(linkTypeName, fromNote, toNote)
	tell application "Tinderbox 10"
		if linkTypeName ≠ "" then
			set strType to linkTypeName
		else
			set strType to "*untitled"
		end if
		set strID to value of (attribute "ID" of toNote)
		evaluate fromNote with "linkTo(" & strID & "," & strType & ")"
	end tell
end linkFromNoteToNote

If you decide, say, to move your “My New Notes” container within a “My Notes” container (which is still at root level) you don’t have to worry about with path and the like. Unless you have deep nesting, it may be easier to use the more common AppleScript-type syntax like this:

set newNote to make new note in note "My New Notes" in note "My Notes"
6 Likes

This is a wonderful tutorial intro, Sumner! Well done!

@iPanini, I want to add a link to what @dominiquerenauld was working on that may have prompted your effort.

What Dominique was looking for was a way to add a note to a Tinderbox file while working in another app. That’s what the first part of the script is for. If you call it by means of the AppleScript Menu, or the FastScripts Menu, or by assigning it a keyboard shortcut, you can remain in DevonThink or Mail or some other app, enter your note name and the $Text by means of AppleScript variables, and the script will then run in the background, creating the note in Tinderbox while you remain in the app (and context) you were working in already.

Sumner’s post is a thorough look at creating a note (and a link!) through AppleScript. What makes that especially powerful is the bridging (or piping) capability of AppleScript, which allows you to add notes to your Tinderbox document while working in another app.

The structure of Captain’s Log was specifically created to facilitate a kind of “daily notes” outline, wherein all of the outline structure is created automatically by Tinderbox, and I just have to add notes, confident that they’ll be filed in the appropriate container.

That may not be appropriate for your use case, and in fact it may be much simpler to add notes as Sumner has described without essentially “computing” thePath as is the case in Captain’s Log.

I believe Dominique planned to use an “Inbox” container, essentially a fixed location within the document, to capture the notes; and rely on Action Code to then move them to a more appropriate container, or to process them manually. That may be a much simpler approach for what you’re trying to do.

Replying to myself, I realized that the script that I linked to in Dominque’s thread only created the note’s title. Here’s a complete script that works within Apple Mail to capture a link to the email and create a new note in Captain’s Log with a link to that email.

use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

set entryTitle to text returned of (display dialog "Entry Title?" default answer "")
set entryText to text returned of (display dialog "Entry Text?" default answer "")

tell application "Mail"
	--	if not it is running then activate
	
	if not (get selection) is {} then
		set theMsg to item 1 of (get selection)
	else
		return
	end if
	
	tell theMsg
		set {msgID} to {message id}
		set msgURL to "message://%3C" & msgID & "%3E"
	end tell
end tell

tell application "Tinderbox 10"
	set this_moment to (the current date)
	set nmMonth to (month of this_moment) as string
	set nmYear to (year of this_moment) as string
	set thePath to "Captain's Log/" & nmYear & "/" & nmMonth & " " & nmYear & "/" & date string of this_moment
	tell document "Captain's Log.tbx" -- suffix .tbx required on my machine
		-- this is how to specify a note down in the hierarchy:
		set theContainer to find note in it with path thePath
		set newNote to make new note at theContainer
		tell newNote
			if entryTitle is not missing value then set value of attribute "Name" to entryTitle
			set value of attribute "Text" to entryText
			set value of attribute "Prototype" to "p_Entry"
			set value of attribute "URL" to msgURL
		end tell
	end tell
end tell

So the “workflow” here is that you have an email you wish to note in your Tinderbox file, with a link to the original email in Mail. With that email selected, invoke the script and the script asks for the Note’s title, and then the text of the note. (The input UI is a single line, but you can paste a lot of text in there if you want.) So these can be brief reminders of what the email is about, or what action you wish to take.

The script then captures the message id for that email within Mail’s store. We need this to create a URL, a clickable link item. The “tell theMsg” block then creates a msgURL variable and then assembles the URL. (Looking at this now, I’m not sure why I have curly brackets in that set {msgID} line. Oy.)

The rest of the script works in Tinderbox to create the note. I took the lazy way out and just used the System Attribute URL for this note, because it has the little globe icon that makes it clickable. There may be a better way to do it.

You could extend this by adding additional front-end queries for things like “priority” or “category” or “tag” and then use additional AS to set the values of those attributes in your note.

To be clear, in what can be a somewhat murky area, this script works with Mail and Tinderbox specifically, because I need to pull data from Mail, the link to the email.

You can create a generic AS that can work from any app, where you can create a note with a title and some text, perhaps copied from the app you’re in and then pasted into the AS input field.

I hope that was helpful and not more than you cared to know! :grinning:

4 Likes

Thanks a ton @sumnerg and @dmrogers for your effort!
I’m investigating and learning, learning, learning a lot :wink:
Hugely appreciated!!

The mail example will definetely come in handy. I know that this will be tedious if possible at all, but would there be a way to interact with webmail (Fastmail)? Reason I ask is because mail interaction will definetely become an issue further down the road, but I prefer to do as much as possible in the html interface of Fastmail instead of loading mail in Apple Mail. I know that Fastmail has an API but that’s about all I know about it…

I do remember from the Meetups, that @satikusala has interacted with Mail multiple times, I guess it will be best to have a look at those tutorials.

1 Like

I really have no idea. But others likely know better than I do.

Tinderbox, using the integration with the $Email attribute, if the email client supports it (e.g., macMail does, SparkMail DOES NOT), will trigger an email (including formatted CSS if you set it up right). I don’t believe this will trigger a webmail. As you point out, you could interact via the API, possibly with a curl via the command line. I’ve not tried this myself.

1 Like

The Fastmail API is “above my pay grade” but I think it would be hard to “interact” with it from Tinderbox or via AppleScript.

By “interact” with it do you mean get stuff from Fastmail into Tinderbox? Or compose messages in Fastmail using information you have in Tinderbox?

If the former, and you don’t mind configuring Apple Mail to work with Fastmail (they claim it’s standard IMAP and that Apple Mail handles that well) then you may find the following script useful. A few years ago I used a variation of it to bring hundreds of emails into Tinderbox, organize them, and export to Pages, making a nice book.

In general I’ve found a tradeoff between “generalizing” a script to handle many possible situations and edge cases (as a developer must) and striving for something reasonably concise and straightforward that works reliably for the specific job at hand and can be modified easily if it doesn’t do quite what was wanted.

This one works with Apple Mail, and Apple Mail only.

Script here

--------------------------------------------------------------------------------
# Bulk imports messages selected in Apple Mail into front Tinderbox document
# Clickable link back to message in Mail -- URL attribute
# TO USE: Select messages in Mail, and with Tinderbox doc open, click run
--------------------------------------------------------------------------------

set containerName to "Imported Emails"

# NOTE: Use only existing Tinderbox attributes; add attributes manually to TBX as needed
set keyAttributesStr to "URL;MyDate;MyString;MyBoolean" --<<<-- these are in any Tbx 8+ doc by default

# Initialize list variables to hold Apple Mail message properties
set {subjectLst, contentLst, datesentLst, senderLst, msgurlLst, attachLst} to {{}, {}, {}, {}, {}, {}}

set importCounter to 0

tell application "Mail"
	set selectedMessages to selection
	set selectedMsgsCount to selectedMessages's length
	
	# place each Mail message 'property' in an AppleScript list
	repeat with aMessage in selectedMessages
		tell aMessage
			set end of subjectLst to subject
			set end of contentLst to content
			set end of datesentLst to my dateToStr(date sent)
			set end of senderLst to sender
			set end of msgurlLst to "message://%3C" & message id & "%3E" --> clickable link
			set end of attachLst to exists mail attachments --> boolean	
		end tell
	end repeat
end tell

tell application "Tinderbox 10"
	tell front document
		if not (exists) then error "No Tinderbox document open."
		
		#  create container for imported messages
		if not (exists note containerName) then
			set newNote to make new note at before first note
			tell newNote to set name to containerName
		end if
		
		# create a note for each selected Mail message in designated container
		repeat with i from 1 to selectedMsgsCount
			set newNote to make new note at note containerName
			tell newNote
				## Map Tinderbox 'attributes' to Apple Mail message 'properties':
				set value of attribute "Name" to item i of subjectLst
				set value of attribute "Text" to item i of contentLst
				set value of attribute "MyDate" to item i of datesentLst
				set value of attribute "MyString" to item i of senderLst
				set value of attribute "URL" to item i of msgurlLst
				set value of attribute "MyBoolean" to item i of attachLst
				## Assign values to non-Mail-related attributes:
				set value of attribute "KeyAttributes" to keyAttributesStr
				set value of attribute "Width" to 8
			end tell
			set importCounter to importCounter + 1
		end repeat
		
	end tell
end tell

display notification "Imported " & importCounter & " messages of " & selectedMsgsCount & " selected"

## ----------------- handlers (=subroutines) -----------------------

to dateToStr(aDate) --> convert AppleScript date to string format that Tinderbox recognizes
	tell aDate to return short date string & ", " & time string
end dateToStr
3 Likes

What, you’re on a pay grade? :rofl: Thanks for all that you do.