Dynamically configure template placeholders


I have created a template the purpose of which is to link attachments and a mail message. the workflow is thus:

In mail with a message that has attachments selected, I select a script that that moves the attachments into DTP. Then the script opens a template and copies the body of the email into the template.

I have a section in the template called documents where a list of DTP links should appear that link to the documents that were previously attached to the email message.

If I have a defined number of attachments, of course I can structure the template placeholders accordingly.

What I need to do is to create a dynamic list of links that will be put into the place holder.

For example, the current AppleScript line is

set theRecord to import theTemplateFiles placeholders {|%documentName%|:theSubject, |%documentLink%|:{|URL|:docLink, |name|:theDocName}, |%messageLink%|:{|URL|:messageURL, |name|:pMessageLinkText}, |%bodyText%|:theText, |%messageSubject%|:theSubject}

What I need is for %documentLink% to be replaced with a list of clickable links to the related documents. So something like

|%documentLink%|:{|URL|:docLink1, |name|:theDocName1, |URL|:docLink2, |name|:theDocName2, |URL|:docLink3, |name|:theDocName3}

I’m not sure if that’s the way to do it, but that’s the general idea.

Any thoughts on how this might be accomplished through AppleScript?

Much thanks in advance
Judi Smith

1 Like

I believe you would need

|%documentLink1%|:{|URL|:docLink1, |name|:theDocName1}, %documentLink2%:{|URL|:docLink2, |name|:theDocName2}, %documentLink3%:{|URL|:docLink3, |name|:theDocName3}

and so forth. You would construct this structure on the fly (say in a repeat with … end repeat loop) depending on how many documents you’ve linked to. That is %documentLink1% … to %documentLinkN% And then construct the set statement.

This would be an interesting and useful template. Would you post it when it is finished?

I agree-I would be interested in seeing the finished template also.

Korm, thank you for the reply. I will be happy to post the template when complete.

Since multiple placeholders are required, one part that has been eluding me is how to dynamically adjust the number of placeholders in the template. So far my efforts in trying to edit the template on the fly with AppleScript have resulted in the loss of the RTF formatting - OK but ugly.

Basically I look for the original placeholder and replace it with the generated list of placeholders.

Any suggestions on how I might edit the template with AppleScript and keep the formatting?

Judi, the “real” template is an RTF file embedded in the .templatescriptd package. Look at

~/Library/Application Support/DEVONthink Pro 2/Templates

Right click one of the .templatescriptd “files” in Finder, and select Show Package Contents. The template “file” is actually a type of folder, and with the contents revealed you’ll be able to find the RTF file which the script you are working on uses as the basis for each new document. You’ll see how it works as soon as you look at the RTF file.

I’d suggest you place your links at the end of the document because you do not know in advance how many links any given file will have.


I think I’ve not been clear in my description. I created the template and know where it is. I’m looking for some help with the AppleScript to achieve the dynamic update without ruining the RTF formatting. Any thoughts?

While this topic has seen no activity for some time, I recently had a similar problem that required creating a template at run time, and thought the solution would be of general interest.

Here is a solution for the OP’s specific need to dynamically create a template at runtime. It can easily be modified for other needs.

  1. Create a template such as (based on the information the OP gave):
    sample template.jpg
    Format it as you wish with fonts, indentations, etc. Save it to your desktop as “sample.rtf.”

  2. Run “rewrite template example.scpt” (included at the end of this post). It will create on your desktop a new template, named “rewritten template.rtf,” based on sample.rtf, with “@here” replaced with the list of 1 - n new placeholders:
    rewritten template.jpg
    This solves the initial problem of dynamically creating a template at runtime. Note also that in the original “sample remplate.rtf,” “@here” was indented and italicized, and this formatting is retained in the text that replaced it; presumably, any text that replaces these placeholders will also have this formatting.


I’m not getting two things though:

  1. Specifically concerning this use case: Where do the URL and name for the attachment come from, how in general is this link constructed, and what do the “|” represent? I’ve seen these used in working with files’ properties in DT scripts, but I’m still confused by their use.

  2. In general when using this approach: How in script to construct the placeholder list dynamically at runtime?

In this specific use case (importing a mail message that has attachments), we can assume that we’d know the details of the message(s) and each of their attachments. For example:

tell application "Mail"
	set messageDetails to {}
	set theMessages to selection
	repeat with msg in theMessages
		set msgDetails to {subj:subject of msg, msgLink:sender of msg, bodytext:content of msg}
		set attach to {}
		repeat with theAttachment in mail attachments of msg
			set listItem to {attachName:name of attach}
		end repeat
		(*	the template calls for: |%documentLink1%|:|URL|:docLink1, |name|:theDocName1 ... |%documentLink-n%|: etc...
			- how are these derived from the message and attachments?
			- how to prepare the list of placeholders from 1 to n at runtime to pass the placeholders to import?
	end repeat
end tell

Granted, the placeholders parameter to import is just a list, and would include (based on the information the OP gave):

set thePlaceholders to {|%documentName%|:subj of msg, |%messageLink%|:msgLink of msg, |%bodytext%|:content of msg}

But, how to construct the list elements to accommodate from 1 to n of:

|%documentLinkn%|:|URL|:docLinkn, |name|:theDocNamen

I expect the script would have to add placeholders to the list, in some way such as:

repeat with ctr from 1 to (count of attach)
	set a to item ctr of attach
	set listItem to {}
	-- set list item to what?
	-- we want the URL of the attachment (which is stored in docLink1, and the name from the attachment (which is stored in theDocName1): {|%documentLink1%|:|URL|:docLink1, |name|:theDocName1}
	-- how are these extracted from the attachment?
	-- generating the text itself it not a problem:
	set theString to "|%documentName" & (ctr as string) & "%|:" -- but what else?
	set listItem to {} -- set it to what?
	copy listItem to end of thePlaceholders
end repeat

So that the script can import the template and have DT do the replacements:

set pathToRewrittenTemplate to "/Users/Me/Desktop/rewritten template.rtf"
tell application id "com.devon-technologies.thinkpro2"
	set theRec to import pathToRewrittenTemplate name "New Record" placeholders thePlaceholders
end tell

But the problems are adding the rest of the information about the link, and adding this to the placeholders list. It almost seems that this problem requires somehow modifying the script itself at runtime, or creating an AppleScript at runtime and loading and executing the dynamically-created script at runtime.

Having said all this, I wonder if it’s simpler to just open the template file, find @here, and instead of replacing it with placeholders, inserting the needed actual content into the rtf document, saving it, and importing it into DT, without using any placeholders in the call to import.

(But I sure would like to know how to create those clickable links to emails, and clickable links in general!)

rewrite template example.scpt follows

(* rewrite template example
	create a set of 1-n placeholders and write them to an rtf template file to be used with DT's "import" verb.
	to use, create an rtf template file and save it to your desktop as "sample.rtf". in this template, place the templateFileToken defined below where you want the placeholders to be.
	the script wil generate numAttachments sets of placeholders, replace the templateFileToken with them, and write the new template to your desktop named "rewritten template.rtf".
	script assumes one message and "numAttachments" attachments.

-- --------------------
-- set these as appropriate.
-- pathToTemplateFile and pathToNewTemplateFile must be POSIX paths.
set pathToTemplateFile to "/Users/<<YourUserName>>/Desktop/sample template.rtf"
set pathToNewTemplateFile to "/Users/<<YourUserName>>/Desktop/rewritten template.rtf"

-- the script looks for this token in the template file and replaces it with the new placeholders.
set templateFileToken to "@here"

-- for how many attachments do you want the new placeholders to be generated?
set numAttachments to 3

-- used in generating the new placeholders.
set counterPlaceholder to "@"

-- used to separate the new placeholders in the new template file (consider this like the rtf equivalent of html's <p>)
-- (the actual markup is \par, but AppleScript requires \\par because it uses \ as an escape character)
set rtfNewPar to "\\par"

-- the instances of counterPlaceHolder will be replaced with a number.
set myPlaceholders to "|%documentLink" & counterPlaceholder & "%|:{|URL|:docLink" & counterPlaceholder & ", |name|:theDocName" & counterPlaceholder & "}" & rtfNewPar

set templateData to ""

-- ====================
-- generate numAttachments instances of placeholders, unsing myPlaceholders as the template, and replacing counterPlaceholder with the instance number.
set newPlaceholders to generatePlaceholders(myPlaceholders, counterPlaceholder, numAttachments)

-- read the original template.
set templateData to readFile(pathToTemplateFile)

-- replace templateFileToken with the new placeholders.
set newTemplateData to replaceText(templateFileToken, newPlaceholders, templateData)

-- write the new template file.
writeNewTemplate(newTemplateData, pathToNewTemplateFile)

-- uncomment if you're curious about what the rtf markup looks like
-- set the clipboard to newTemplateData


-- ====================
on generatePlaceholders(placeholders, replaceWhat, numAttachments)
	set rtnText to ""
	repeat with ctr from 1 to numAttachments
		set rtnText to rtnText & replaceText(replaceWhat, (ctr as string), placeholders)
	end repeat
	return rtnText
end generatePlaceholders

-- --------------------
on replaceText(find, replace, inWhat)
	set delims to AppleScript's text item delimiters
	set AppleScript's text item delimiters to find
	set txt to text items of inWhat
	set AppleScript's text item delimiters to replace
	set txt to "" & txt
	set AppleScript's text item delimiters to delims
	return txt
end replaceText

-- --------------------
on readFile(pathToFile)
		set siz to getFileSize(pathToFile)
		set f to open for access pathToFile
		set txt to read f from 1 to siz
		close access f
	on error errMsg
		display dialog errMsg
	end try
	return txt
end readFile

-- --------------------
on getFileSize(pathToFile)
	-- simply using read file of read from 1 to eof does not read the entire file, only 1,199 bytes.
	-- perhaps applescript chokes on some sequence of characters that it believes represents end of file?
	-- using this command line seems a fast way to get the size of the file so that it can be completely read.
	set cmdLine to "ls -l " & quoted form of pathToFile & " | awk '{print $5m}'"
	set fileSize to ((do shell script cmdLine) as integer)
	return fileSize
end getFileSize

-- --------------------
on writeNewTemplate(theData, pathToFile)
		set f to open for access pathToFile with write permission
		write theData to f
		close access f
	on error errMsg
		display dialog errMsg
	end try
end writeNewTemplate