I tried doing this via sqlite and some other ways. Eventually settled on AppleScript. The script below lets you pick one or all Notes folders, and a place to save their notes. Then it puts them there in one big HTML file, with each one a <div> with a bunch of attributes for mod time, id, etc. Attachments become links within lists items of a list placed at the end of the note (at least in the version I've been looking at, images are stored in a folder near the sqlite file).
This is a slightly awkward way to export, but works pretty well for some purposes.
-- Export Notes.scpt: 2018-09-18.
-- Save all Apple Notes, or one category of them, to HTML.
-- The notes all go to one file; split later if desired.
--
tell application "Notes"
activate
set folderNum to my pickFolderNum()
display dialog "Chose: " & (folderNum as string)
set resp to choose file name with prompt "Where should I save the Notes?" default name "NotesExport.htm" default location (the path to the desktop)
set tgtFile to (POSIX path of resp)
set fh to open for access file resp with write permission
set eof of the fh to 0
set foldersDone to 0
set totalNotesDone to 0
if (folderNum > 0) then
set nWritten to my doOneFolder(folderNum, fh)
set totalNotesDone to totalNotesDone + nWritten
set foldersDone to 1
else
repeat with folderNum from 1 to the number of folders
set nWritten to my doOneFolder(folderNum, fh)
set totalNotesDone to totalNotesDone + nWritten
set foldersDone to foldersDone + 1
-- exit repeat -- for testing
end repeat
end if
close access fh
display dialog ("Done with " & foldersDone & " folders, " & totalNotesDone & " notes.")
end tell
on doOneFolder(folderNum, fh)
tell application "Notes"
set f to folder folderNum
set fname to (the name of f) as string
set fcount to the number of notes of f
display dialog ("Exporting Notes folder '" & fname & "', notes: " & fcount)
set buf to "<!DOCTYPE html>" & return & ¬
"<html><head><title>Exported Notes: " & fname & "</title></head>" & return & ¬
"<body>" & return
write buf to fh
set notesDone to 0
repeat with j from 1 to fcount
set the cursor to busy
set theNote to note j of f
set atts to ""
if (the number of attachments of theNote > 0) then
set atts to "<ul class='attachments'>" & return
repeat with k from 1 to the number of attachments of theNote
set att to (attachment k of theNote)
set aname to the name of att
set aurl to the content identifier of att
set atts to atts & "<li><a href='" & aurl & "'>" & aname & "</a></li>" & return
end repeat
set atts to atts & "</ul>" & return
end if
set nm to (the name of theNote) as string
set idv to the id of theNote as string
set idVal to my makeAttr("id", idv)
-- display dialog ("id: " & idVal)
-- set cont to (the container of theNote) as string -- a folder
set bod to (the body of theNote) as string
-- display dialog "Note #" & j & ": " & bod
set cdate to the creation date of theNote
set mdate to the modification date of theNote
set cdates to my makeAttr("cdate", my isoDate(cdate))
set mdates to my makeAttr("mdate", my isoDate(mdate))
set clas to my makeAttr("class", "note")
-- set hasPW to (the password protected of theNote) as string
--
-- copy/paste into TextEdit, then save as HTML?
--
set buf to return & "<div" & idVal & cdates & mdates & clas & ">" & return & ¬
"<h1>" & nm & "</h1>" & return & ¬
bod & return & atts & "</div>" & return
write buf to fh
set notesDone to notesDone + 1
end repeat
end tell
return notesDone
end doOneFolder
-- Escape, quote, and assemble as needed for an attribute.
on makeAttr(nam, val)
set s to ""
try
if val is "" then
return ""
end if
set s to " " & nam & "=" & quote & val & quote
end try
return s
end makeAttr
-- Turn chars not allowed inside attributes, into character refs.
--
on escapeAttr(s)
set s2 to ""
repeat with i from 1 to length of theName
set c to character i of s
if (c is "<") then
set s2 to s2 & "<"
else if (c is "&") then
set s2 to s2 & "&"
else if (c is quote) then
set s2 to s2 & """
else
set s2 to s2 & c
end if
end repeat
return s2
end escapeAttr
-- Make a yyyy-mm-ddThh:mm:ss ISO date/time string.
--
on isoDate(dat)
-- display dialog "Date is: " & (dat as string)
set {year:y, month:m, day:d} to dat
set {hours:hr, minutes:mn, seconds:sc} to dat
set d2 to (y * 10000 + m * 100 + d) as string
set d3 to (text 1 thru 4 of d2) & "-" & (text 5 thru 6 of d2) & "-" & (text 7 thru 8 of d2)
set t2 to (hr * 10000 + mn * 100 + d) as string
set t3 to (text 1 thru 2 of t2) & ":" & (text 3 thru 4 of t2)
if (length of t2 ≥ 6) then
set t3 to t3 & ":" & (text 5 thru 6 of t2)
end if
return d3 & "T" & t3
end isoDate
on pickFolderNum()
set buf to my getFolderList()
set buf2 to "Enter the folder number you want, or 0 for all:" & return & buf
set theResponse to display dialog buf2 default answer "" buttons {"Cancel", "Continue"} default button "Continue"
--> {button returned:"Continue", text returned:"Jen"}
return (text returned of theResponse) as integer
end pickFolderNum
on getFolderList()
tell application "Notes"
activate
set buf to ""
repeat with i from 1 to the number of folders
set fname to the name of folder i as string
set buf to buf & (i as string) & ": " & fname & return
end repeat
return buf
end tell
end getFolderList
osascript -e 'tell application "Notes"' -e 'get get the body of the note "Thingamajigs" of the folder "Notes"' -e 'end tell'
), but unfortunately even though the result is nominally in HTML format, it doesn't seem to contain the full format/link/etc info. But give it a shot and see if you get anything useful.