Retain link formatting on Apple Notes export

Using an AppleScript, I have managed to export my Apple Notes to HTML, from which I can make other conversions. However, this removes all the inline links. Is there a way of bulk exporting them while retaining formatting?

RTF seems the obvious way to go here, because that seems to be the format Apple Notes uses under the hood. I have confirmed link formatting is preserved by copy pasting a note into TextEdit, so it’s clearly possible. But I haven’t been able to figure out how to export to RTF using AppleScript. Another way might be by using Shortcuts to go through each note, copy and paste it into TextEdit, and save all the files in a folder somewhere. But I don’t know how to do this.

Does anyone know how to do this, or know another way inline links might be maintained?

This is a duplicate of an Ask Different question. I’ll paste the comments here for easier reading:

1 What is the script doing to export the notes?

2 It’s a slightly modified version of Bear’s export AppleScript bear.app/faq/migrate-from-apple-notes

2 It works perfectly apart from removing link formatting (as well as newlines not working, but I can fix that in another script afterwards).

1 That script gets the body of the note (kinda crappy HTML content, with just about everything in a division), but it doesn’t look like any of the note properties include links.

2 How do you know the note properties don’t include links, is there Apple documentation on this? (I struggled to find any.) Yes, the problem is that inline links aren’t exported, do you know of any way to do this beyond manually copying each individual note into TextEdit?

1 There is no terminology in the scripting dictionary for links, and the body (HTML) doesn’t include them, so if it isn’t a bug then they are just not provided. While hunting around I came across a few topics that go back a few years, so it looks like the issue has been around for a while.

2 Is there any way, that you know of, of automating copy paste from one app to another (in this case, Notes to TextEdit or Pages) on Mac?

Hi @applescripter17. Welcome to MacScripter.

It’s possible to simulate the keystrokes for copying and pasting using GUI Scripting. But you’d need to select the text manually (or at least click in the note) first, so it’s only really sensible for doing one note at a time. To get you started, this saves the RTF data for the currently focused note to a file on the desktop:

tell application "Notes" to activate

tell application "System Events"
	-- Make sure Notes is frontmost.
	set frontmost of application process "Notes" to true
	-- Copy all the text of the currently focused note.
	keystroke "ac" using {command down}
end tell

-- Wait for the keystrokes to take effect.
delay 0.5
-- Retrieve the RTF data from the clipboard.
set RTFData to (the clipboard as «class RTF »)

-- Save the data to file.
set filePath to (path to desktop as text) & "Saved note.rtf" -- Edit as required.
set fRef to (open for access file filePath with write permission)
try
	write RTFData to fRef
	close access fRef
on error msg
	close access fRef
	display dialog msg buttons {"OK"}
end try

Alternatively, this pastes into a new TextEdit document:

tell application "Notes" to activate

tell application "System Events"
	-- Make sure Notes is frontmost.
	set frontmost of application process "Notes" to true
	-- Copy all the text of the currently focused note.
	keystroke "ac" using {command down}
end tell

-- Wait for the keystrokes to take effect.
delay 0.5

tell application "TextEdit"
	activate
	make new document -- Assuming new documents are in RTF format.
end tell

tell application "System Events"
	-- Paste into the frontmost TextEdit document.
	set frontmost of application process "TextEdit" to true
	keystroke "v" using {command down}
end tell

applescripter17. The shortcut included below appears to do what you want. A few comments:

  • You need to set the destination folder at the top of the shortcut where indicated.

  • The shortcut saves each note as a separate RTF file, but I suspect the notes could all be placed in one file if that’s desired.

  • Because of a bug in the Shortcuts app, it’s advisable but not absolutely essential that the Notes app be open when the shortcut is run.

  • I tested this shortcut on my Sequoia computer, and links and other formatting were retained in the created RTF files.

  • The following screenshot only shows a portion of the shortcut.

Save Notes.shortcut (23.7 KB)

Apologies for the late response, thank you both for such detailed responses. I will try out that shortcut and report back on whether it works for me, it looks to be exactly what I need.

I have modified this shortcut to add other text to the body, such as the title of the note.

To do this I first use “Set Variable” then “Add to Variable” and finally “Combine Text”.

The combination of text works, however it is no longer RTF, but TXT.

Only the Body, or whole Note, appears to be in RTF format. But I want to do some additional processing on it before saving.

Do you know if there is a way of keeping text RTF in Shortcuts?

I tried “Get File of Type” with “public.rtf” type, and “Make Rich Text from Markdown/HTML” to make the other text RTF before combining it with the Body, but a TXT file is still outputted.

Perhaps “Combine Text” itself outputs TXT, and removes RTF formatting in the process. If so, would there be any way around this?

applescripter17. I don’t understand precisely what you mean by additional processing. FWIW, I’ve included below some miscellaneous thoughts on a few issues you raise.

  • Adding a note body to a variable retains the RTF formatting. Adding any other note property to a variable results in a variable with a type that is appropriate to that item (e.g. text or date).

  • Adding several note bodies to a variable creates a list, and each list item retains the RTF formatting. Merging the items in such a list with the Combine Text action creates a plain-text object. There is not a Combine RTF action (or an equivalent) that I’m aware of.

  • I thought a possible workaround might be to create a temporary note and to add the note bodies to that note. However, the resulting note contained text only.

  • The Get File of Type action allows you to create an RTF file from a note body, but I was unable to append another note body to that RTF file. Doing this with a variable that contains two note bodies creates two RTF files.

So, I don’t have an answer to your question. Perhaps another forum member will have an idea.

I don’t know if this will be any help to applescripter17, but the following shortcut merges all note bodies returned by the Find Notes action in a temporary note created by the Create Note action. This note is then saved as an RTF file, and RTF formatting is retained.

Combine Notes.shortcut (23.0 KB)

Unfortunately this is not what I want to do, they have to all be separate notes. I’ll try and see if I can get it working.

By ‘additional processing’ I just mean adding more text, eg putting the folder name at the bottom of the exported file.

Applescripter17. I’m sure you’ll find a good solution. It’s fun to experiment with stuff like this and to find new ways of doing things.

I played around with my earlier shortcut in which individual notes are specified in the Find Notes action and instead got all notes in a particular folder:

Combine Notes.shortcut (23.1 KB)

The following screenshot is a resulting RTF which was compiled from four notes in the specified folder. The RTF formatting is bold text, a bulleted list, and links.

You gave me a clue, so thank you. For some reason Combine Text always outputs TXT not RTF, so I have figured out that for each note I have to create another temporary note, use “Append to Note” to add text, then save that temporary note to a file, and delete it. I will post Shortcut when I have finally finished it.

Here, largely for my own amusement on a slack Sunday, is an AppleScript solution which I think addresses what’s wanted. It’s not particularly fast, but it works. The information about each note’s container is edited into the file after the RTF’s saved and is necessarily in the same style as the end of the note text. But this may be fixable (if not wanted) by someone with greater RTF skills than mine. :slightly_smiling_face:

main()

on main()
	-- Settings. Adjust to taste:
	-- Destination folder for RTF files.
	set folderPath to (path to desktop as text) & "Saved notes:"
	-- HFS-compatible {date component delimiter, separator, time component delimiter} for use in file names.
	set ISODateDelimiters to {"/", " at ", "."}
	-- Two linefeeds in each file between end of note text and note container insert.
	set RTFLinefeeds to "\\" & linefeed & "\\" & linefeed
	
	-- Create the destination folder if it doesn't already exist.
	do shell script ("mkdir -p " & folderPath's POSIX path's quoted form)
	if (folderPath does not end with ":") then set folderPath to folderPath & ":"
	
	-- Get all the notes in the application.
	tell application "Notes"
		activate
		set theNotes to notes
	end tell
	
	repeat with thisNote in theNotes
		-- "Select" each note and derive an insert and file name from its relevant properties.
		tell application "Notes"
			show thisNote
			set {container:thisContainer, name:noteName, creation date:noteDate} to thisNote
			set insert to thisContainer's name
			repeat while (thisContainer's class is folder)
				set thisContainer to thisContainer's container
				set insert to thisContainer's name & "->" & insert
			end repeat
		end tell
		set insert to RTFLinefeeds & insert & "}" -- This will replace the "}" at the end of the file.
		set noteDate to ISODate(noteDate, ISODateDelimiters)
		set fileName to replaceText(noteName, {":"}, "-") & " (" & noteDate & ").rtf"
		
		-- Set the clipboard to a non-text value.
		set the clipboard to missing value
		-- Focus the note text pane, select and copy the text.
		tell application "System Events"
			set application process "Notes"'s front window's first splitter group's third scroll area's first text area's focused to true
			keystroke "ac" using {command down}
		end tell
		-- Wait if necessary for the text to replace the non-text on the clipboard.
		repeat until ((the clipboard)'s class is text)
			delay 0.2
		end repeat
		-- Get the RTF data from the clipboard.
		set RTFData to (the clipboard as «class RTF »)
		
		-- Save the RTF data to file, then edit the note container info into the file.
		set fRef to (open for access file (folderPath & fileName) with write permission)
		try
			set eof fRef to 0
			write RTFData to fRef
			write insert to fRef starting at (get eof fRef) -- Overwrite the last byte.
			close access fRef
		on error msg
			close access fRef
			display dialog msg buttons {"OK"}
		end try
	end repeat
end main

on replaceText(txt, |search|, replace)
	set astid to AppleScript's text item delimiters
	set AppleScript's text item delimiters to |search|
	set txt to txt's text items
	set AppleScript's text item delimiters to replace
	set txt to txt as text
	set AppleScript's text item delimiters to astid
	return txt
end replaceText

on ISODate(theDate, {dateDelimiter, separator, timeDelimiter})
	set {year:y, month:m, day:d, hours:h, minutes:min, seconds:s} to theDate
	tell (y * 10000 + m * 100 + d) as text to set dateBits to {text 1 thru 4, text 5 thru 6, text 7 thru 8}
	tell (1000000 + h * 10000 + min * 100 + s) as text to set timeBits to {text 2 thru 3, text 4 thru 5, text 6 thru 7}
	return join(dateBits, dateDelimiter) & separator & join(timeBits, timeDelimiter)
end ISODate

on join(lst, delim)
	set astid to AppleScript's text item delimiters
	set AppleScript's text item delimiters to delim
	set txt to lst as text
	set AppleScript's text item delimiters to astid
	return txt
end join

Edits: Found a way to focus Notes’s note text pane instead of having to open new windows. Variable label barred for compatibility with Script Debugger.

1 Like

Nigel. I tested your script, and it worked great. I encountered one minor issue in that the script would not compile in Script Debugger, returning the error message shown below. The fix was to change the names of the first two parameters of the replaceText handler. This error did not occur with Script Editor.

«event asDBfiNd» is illegal as a formal parameter.
1 Like

Hi peavine. Thanks for trying the script and for the feedback about the Script Debugger problem. I’ve now changed the offending label in that handler.