Barebones script for creating new notes in TB8

In this forum I’ve found a barebones script for reading and extracting information from a TB8.0 document. To me the new script capabilities of TB8 can also be very useful to import information into TB8 in a more automatic way.

As an example take an Apple Mail document and directly create a new note in a Inbox container inside TB with

  1. a copy of the text in $Text
  2. $Name set to the subject and
  3. backlink in $RefURL to the original mail.
    Similar considerations work for DEVONthink documents such as annotations.

I’m a complete newcomer to scripting so it would be helpful to have a barebones script to work with and build on. This for instance as a test to create a new document does not work:

tell application "Tinderbox 8"
	set myNote to make new note in document "Temp.tbx"
end tell

The new Tinderbox support for scripting is quite robust, more robust than the Help suggests. More scripts are bound to show up over time so you will have examples to study.

To create a new document you can do something like this:

tell application "Tinderbox 8"
	set newDoc to make new document with properties {name:"MyNewDoc"}
	save newDoc
end tell

To create a new note at the top level at the end of the document you can do something like this:

createNote("My New Note", "I added this text by script", "Cat A", "MyString;MySet")

to createNote(theName, theText, theCat, keyAttr)
	tell application "Tinderbox 8"
		tell front document
			set newNote to make new note at last note's parent
			tell newNote
				set name to theName
				set attribute "Text"'s value to theText
				set attribute "MyString"'s value to theCat
				set attribute "KeyAttributes"'s value to keyAttr
			end tell
		end tell
	end tell
end createNote

Getting information into Tinderbox is often efficient without a script. You can, for example, just drag in or copy-paste columns of data from a spreadsheet. If you take care to have proper column headers then Tinderbox will automatically bring those in as Key Attributes. And you may have discovered you can just drag an email from Apple Mail into Tinderbox and Tinderbox will do 1. and 2. for you, though it doesn’t seem to do 3. (bring over the link). Will look into a script for doing that.

Here’s a bare bones script for bringing one selected message in Apple Mail into Tinderbox. It includes the message URL, which is included in Key Attributes where the link is active and takes you back to the message in Mail. Sender is placed in the sandbox attribute MyString and the date into MyDate but of course you might want to set up attributes with more specific names.

tell application "Mail"
	tell item 1 of (get selection)
		set messageID to message id
		set co to content
		set re to first to recipient's address
		set se to sender
		set su to subject
		set da to date received
	end tell
end tell

set {year:y, month:m, day:d, weekday:wd} to da
set da to m & " " & d & ", " & y as string --> mmm dd, yyyy
set tbxURL to "message://%3C" & messageID & "%3E"

tell application "Tinderbox 8"
	tell front document
		set newNote to make new note at note "Inbox"
		tell newNote
			set name to su
			set attribute "Text"'s value to co
			set attribute "URL"'s value to tbxURL
			set attribute "MyString"'s value to se
			set attribute "MyDate"'s value to da
			set attribute "KeyAttributes"'s value to "URL;MyString;MyDate"
		end tell
	end tell
end tell

This could easily be extended to include more than one message at a time. But for multiple messages you might find a script like the following more efficient. It places the information on the clipboard for pasting into Tinderbox.

set pasteStr to ¬
	"Recipient" & tab & "Sender" & tab & "Subject" & tab & "Date" & tab & "Text" & return
tell application "Mail"
	try	
		repeat with aMessage in (get selection)
			tell aMessage
				set re to its first to recipient's address
				set se to its sender
				set su to its subject
				set da to its date received --as rich text
				set {year:y, month:m, day:d, weekday:wd} to da
				set da to m & " " & d & ", " & y as string --> mmm dd, yyyy
				set co to my substitute({linefeed, return, tab}, {" ", " ", "  "}, content)
				set pasteStr to pasteStr & ¬
					re & tab & se & tab & su & tab & da & tab & co & return
			end tell
		end repeat
	end try
end tell

on substitute(s, r, t) -- for removing linefeeds, tabs in message content
	repeat with i from 1 to count s
		set text item delimiters to s's item i
		set t to t's text items
		set text item delimiters to r's item i
		set t to t as text
	end repeat
	return t
end substitute

set the clipboard to pasteStr
return pasteStr -- optional to view results in Script Editor Results Pane

I’ve had good luck with the following script for importing multiple messages from Apple Mail. Best used first on a new Tinderbox document to avoid messing up an old one. Because of so many Apple Events it’s (much) slower than “spreadsheet import” pasting csv but (in my experience) less fiddly. It demonstrates some possible approaches to using the new scripting support. I hope it will attract improvement suggestions and other scripting examples.

--------------------------------------------------------------------------------
# Imports messages selected in Apple Mail into front Tinderbox 8 document
# Automates setting up container and prototype
# Skips messages already present in designated Tinderbox container
# Slow (lots of Apple Events) so watch progress indicator
--------------------------------------------------------------------------------

set containerName to "Imported Emails"
set prototypeName to "pEmail"
set keyAttributesStr to "URL;MyDate;MyString;MyBoolean"

##  Other user attributes must first be added manually to Tinderbox. See comment below.

global existingURLs -- used to skip duplicate imports

tell application "Tinderbox 8"
	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
		#  list URLs of notes already in Tinderbox container (used to skip duplicates)
		set existingURLs to value of attribute "URL" of note containerName's notes
		#  create prototype with key attributes imported message notes will inherit
		if not (exists note prototypeName) then
			set newPrototype to make new note
			tell newPrototype
				set value of attribute "Name" to prototypeName
				set value of attribute "KeyAttributes" to keyAttributesStr
				set value of attribute "badge" to "mail"
				set value of attribute "IsPrototype" to true
			end tell
		end if
	end tell
end tell

tell application "Mail"
	try
		set selectedMessages to selection ## list of references to messages selected in Mail
		set selectedMsgsCount to length of selectedMessages
		if selectedMsgsCount is less than 1 then error "No messages selected in Mail."
		set processedMsgsCount to 0
		my initProgress(selectedMsgsCount) # initialize progress reporter
		repeat with aMessage in selectedMessages
			my importMessage(aMessage, containerName, prototypeName)
			set processedMsgsCount to processedMsgsCount + 1
			my showProgress(selectedMsgsCount, processedMsgsCount) # report progress
		end repeat
	on error error_message number error_number
		if error_number is not -128 then display alert "Mail" message error_message as warning
	end try
end tell
display notification "Done processing " & processedMsgsCount & " messages"

to importMessage(aMessage, containerName, prototypeName)
	try -- used to fake a 'continue' to prevent import of message already in Tinderbox
		tell application "Mail"
			tell aMessage
				set {msgSubj, msgSender, msgContent, msgID} to {subject, sender, content, message id}
				set msgURL to "message://%3C" & msgID & "%3E" --> active link to message
				set dateSentStr to my dateToStr(date sent)
				set existsAttach to exists mail attachments --> boolean
			end tell
			if msgURL is in existingURLs then error "Duplicate" # skip, "continue" to next message
			if msgSubj is equal to "" then set msgSubj to "(no subject)"
			tell application "Tinderbox 8"
				tell front document
					set theContainer to note containerName --> a reference
					set newNote to make new note at theContainer
					tell newNote
						##  Map EXISTING Tinderbox 'attributes' to Mail Message 'properties' here ##
						##  Other user attributes must first be added manually to Tinderbox ##
						set value of attribute "Name" to msgSubj
						set value of attribute "Text" to msgContent
						set value of attribute "MyDate" to dateSentStr
						set value of attribute "MyString" to msgSender
						set value of attribute "URL" to msgURL
						set value of attribute "MyBoolean" to existsAttach
						set value of attribute "Prototype" to prototypeName
						## Assign any non-Mail-related attribute values not inherited from prototype
						set value of attribute "Width" to 8
					end tell
				end tell
			end tell
		end tell
	on error errorMsg number errorNum
		display notification errorMsg & " " & msgURL
	end try
end importMessage

to initProgress(selectedMsgsCount)
	set progress total steps to selectedMsgsCount
	set progress description to "Importing messages ..."
end initProgress

to showProgress(selectedMsgsCount, n)
	set progress additional description to "Processing message " & n & " of" & selectedMsgsCount
	set progress completed steps to n
end showProgress

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

EDIT:

Here’s a faster, less convoluted, bare-bones Apple Mail to Tinderbox scrip with clickable links back to Mail.


--------------------------------------------------------------------------------
# Imports messages selected in Apple Mail into front Tinderbox 8 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 manually to TBX as needed
set keyAttributesStr to "URL;MyDate;MyString;MyBoolean" --<<<-- these 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 8"
	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

And here’s one that adds some bells and whistles like creating a prototype for the imported messages and checking to avoid overwriting messages already in the Tinderbox container (from a previous import), as well as reporting progress.

-------------------------------------------------------------------------------
# Imports messages selected in Apple Mail into front Tinderbox 8 document
# Creates container and prototype (if they don't already exist)
# Skips messages already in container -- so no duplicates
# Links back to message in Mail -- URL attribute

# TO USE: Select messages in Mail, and with Tinderbox doc open, click run
--------------------------------------------------------------------------------

# Name these whatever:
set containerName to "Imported Emails"
set prototypeName to "pEmail"

# NOTE: Use only existing Tinderbox attributes; add manually to TBX as needed
set keyAttributesStr to "URL;MyDate;MyString;MyBoolean" --<<<-- these 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, processedCounter} to {0, 0}

tell application "Mail"
	set selectedMessages to selection
	set selectedMsgsCount to length of selectedMessages
	
	my initProgress(selectedMsgsCount) # initialize progress reporter
	
	# 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 -- or: (extract name from 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 8"
	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 prototype with key attributes, appearance for imported message notes to inherit
		if not (exists note prototypeName) then
			set newPrototype to make new note
			tell newPrototype
				set value of attribute "Name" to prototypeName
				set value of attribute "KeyAttributes" to keyAttributesStr
				set value of attribute "badge" to "mail"
				set value of attribute "IsPrototype" to true
			end tell
		end if
		
		#  list URLs of notes already in Tinderbox container -- used to skip duplicate imports
		set existingURLs to value of attribute "URL" of notes of note containerName
		
		# create a note for each selected Mail message not already in Tinderbox container
		repeat with i from 1 to selectedMsgsCount
			set alreadyInTbxContainer to item i of msgurlLst is in existingURLs --> boolean
			if not alreadyInTbxContainer then
				set newNote to make new note at note containerName
				tell newNote
					# Use only existing Tinderbox attributes; add manually to TBX as needed
					## 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 prototype:
					set value of attribute "Prototype" to prototypeName
					## Assign any non-Mail attribute values not inherited from prototype:
					set value of attribute "Width" to 8
				end tell
				set importCounter to importCounter + 1
			end if
			set processedCounter to processedCounter + 1
			my showProgress(selectedMsgsCount, processedCounter) # report progress
		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

to initProgress(selectedMsgsCount)
	set progress total steps to selectedMsgsCount
	set progress description to "Processing messages ..."
end initProgress

to showProgress(selectedMsgsCount, processedCounter)
	set progress additional description to "Importing message " & processedCounter & " of " & selectedMsgsCount
	set progress completed steps to processedCounter
end showProgress

2 Likes

Liking this script Sumner - thanks for sharing. Is this still your favored approach? And for the case of an extended email thread, are you exploding the new TBX note to create separate Notes?

Glad to hear script is working for you. I used it to bring hundreds of emails into Tinderbox, where I organized them (by date, sender, topic., etc) and then exported them to a word processor to pretty up and publish in book form.

I didn’t use the explode feature in Tinderbox, but instead manually “chopped off the tail” of each thread, leaving the “head” messages. (Each entire thread was captured in the “head” messages.)

But depending on what you are doing, exploding might be more efficient for you, especially if your threads are orderly. (My threads involved a dozen or more people, and formed an unruly mess that I was able to tame reasonably well in Tinderbox.)

I’ve been recenlty using Hookmark to link my emails to my notes, as I found most of the time, there is no need to actually have the email content in my Tinderbox file.

If it’s super-important I will copy over the contents into my relevant Tbx project. Otherwise it works for me to paste the email’s specific URL into the $URL Attribute of a Note, margin for loss/relocation notwithstanding.

I’d like to remind everyone that there is NOT just one $URL attribute for a note. True, there is a “system” URL attribute, but don’t forget that you can create as many “user generated” URL attributes as you like. I have tones. $URLEvent, $URLEmail, $URLLinkedIn, $URLScheduler and many contextually relevant other URLs. When and where appropriate, I can make this to one spot with action and anchor them in output with export code.

1 Like

I think this was about using external scripting to create new notes in Tinderbox. (I needed the email content and header information in Tinderbox notes for my “publishing” project.)

However, if the goal is just to have a clickable link from Tinderbox to a specific email in Apple Mail, then this script will place the message id of the first selected email on the clipboard in proper form for pasting into a Tinderbox url type attribute, where it will immediately be clickable.

tell application "Mail"
	set selectedMessages to selection
	tell first item of selectedMessages
		set the clipboard to "message://%3C" & its message id & "%3E" --> clickable link
	end tell
end tell

Here it is in a Shortcut that is pinned in the Menu Bar.

Mail Message URL to Clipboard

(Click link in Safari to inspect/install the Shortcut)

I assume Hookmark links go both ways, but this one-way linking may be good enough for many purposes.

2 Likes

Hi sorry for the hijack, @sumnerg ! Realized after posting :slight_smile:

Thanks for the code! I will surely use it :pray:

The absolutely quickest way to do this is to use Hookmark. We reviewed this a couple meetups ago.

No worries! I sometimes find it faster to paste a clickable “rtf” link to an email right into the text of a Tinderbox note. (Or into Pages or Numbers or another app that accepts rtf.)

tell application "Mail"
	tell first item of (get selection)
		set theHTMLLink to "<a href=\"" & "message://%3C" & its message id & "%3E" & "\">" & its subject & "</a>"
	end tell
end tell
-- convert html to "rtf" link and place on clipboard for pasting wherever
do shell script "echo " & quoted form of theHTMLLink & " | textutil -format html -encoding UTF-8 -convert rtf  -stdin -stdout | pbcopy -encoding UTF-8 -Prefer rtf "

Here it is in a Shortcut pinned in the Menu Bar.

Mail message RTF link to Clipboard

2 Likes

Brilliant!

I like Hookmark, too; however, my workflows do find value in capturing the body of an incoming email into my Tinderbox daily journaling system. Lots of good info for building atomic notes that later turn into ideas or, more likely, tasks.