Skip to content

BitRancher/notebook-export-manager

Repository files navigation

Notebook Export Manager

This describes an AppleScript program that helps create and maintain HTML and ENEX exports of Evernote® notebooks in macOS. Evernote is a trademark of Evernote Corporation. The AppleScript described here is not a part of Evernote and is not endorsed or supported by them.

Copyright and License

Copyright © 2021 William C Jacob Jr

MIT License

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Contents

[toc]

Overview

The Notebook Export Manager uses Evernote's built-in export features to extract notebooks in HTML or ENEX format and store them in folders of your choice. You can use several selection criteria to determine which notebooks and which notes are included in the export. Most of the selection criteria from Evernote's search syntax can be used to select notes for export.

Installation

This software is distributed as a single text file containing AppleScript source code. If you've stored it with the default file type of applescript, then it will open in the Script Editor app (i.e., AppleScript) when you double-click the file or select it and type command-O (⌘-O).

Once you've opened the file in the Script Editor, you can edit it and/or run it immediately. To run the script, select Script > Run, type command-R (⌘-R), or click the run icon (►).

When you first run the script, the Script Editor will convert it to binary format. You can save this binary, along with the source code, in a single script file by exporting it (File > Export) and selecting File Format: Script. The file extension for this combined format is scpt. Most AppleScript users would typically store scripts in this format, as opposed to the text-only file format used to distribute this script.

When you first run the script, you may be prompted by macOS to permit the script to access the folders where the exported file will be stored.

Settings

When you first run the script, you will be prompted to choose runtime options, or settings. On subsequent runs, you can always choose to modify settings before running the main export functions of the script.

Unfortunately, AppleScript does not natively provide the ability to create complex dialog boxes. So each of the customization options is presented in sequence as a separate dialog box.

As you are stepping through these dialog boxes, you can modify any setting. Your changes are only saved if you step through all the settings. If you cancel at any point, your changes are discarded.

Choose Export Types

The first setting allows you to choose which export types will be created. The choices are: HTML, ENEX, or both.

When notebooks are exported as HTML, they will be stored on your computer as HTML files, one per note. Attachments will be stored in subfolders and will be linked from the note HTML file. You can view the note files using only a browser. No other software, including Evernote, is needed to view them, except whatever specialized program, if any, might be needed for attachments.

The HTML files have been tested, at least basically, in Safari, Chrome, and Firefox. HTML format is useful as archival storage for exported notes, but is not particularly good as a means of transferring notes into another program. The HTML export generated by Evernote is not necessarily visually identical to the note as rendered inside Evernote. Some notes exported as HTML fail to render at all (in Safari). This is an Evernote issue; the script does not alter the contents of exported notes.

The other export format is ENEX, an Evernote-proprietary, XML-based format. All the notes for a single notebook will be stored in one ENEX file, which includes all the file attachments for each note.

ENEX files can, in principle, be imported back into Evernote or imported into other note-taking products, such as Apple Notes. If you plan to take advantage of this, you should thoroughly test the import functionality to ensure that note content is faithfully carried forward to the other product.

Select or Create Folder for HTML Exports

If you've chosen HTML output, you'll be prompted to select a folder where that output is to be stored. Initially, the folder selection dialog will open to your Documents folder. This is probably not a good location for the exports, as they should be placed into a dedicated folder, rather than being intermixed with other folders and files.

The standard system folder selection dialog box allows you to choose an existing folder or create a new one (using the New Folder button in the lower left).

This script has been tested with external volumes (e.g., USB thumb drive). If you select an export folder on a removeable volume, then each time the script runs, it will check to be sure the volume is mounted. If not, you'll be prompted to mount it (or to cancel execution of the script).

Select or Create Folder for ENEX Exports

If you've chosen ENEX output, you'll be asked to choose the output folder for those files.

The ENEX folder can be a subfolder of the HTML output folder, if you like. Other combinations have not been tested, but will probably work.

As with the HTML folder, the ENEX folder can be placed on a removeable volume.

Export All Notebooks or only Selected Ones

You can choose which of your Evernote notebooks will be considered for export. If you choose Selected, the script will show you a list of your notebooks. Hold down the command key (⌘) to select several, if you wish. You must select at least one.

If you select all notebooks, your selection will include notebooks that you created plus notebooks that have been shared with you.

The first time you run the script, you might want to test it with one or two notebooks, rather than your entire Evernote repository.

Optional Search Terms

You can limit the notes that will be included in each export by entering optional search terms. By default, this string is blank and all notes will be exported for each selected notebook.

You can enter any search terms that would be valid in the Search field in the upper right of the Evernote window. More information is available online. However, please do not use these terms:

  • notebook:
  • updated:
  • any:

The notebook: and updated: terms are used internally by the script to select notes for export. And the any: keyword will "break" the script by sweeping too many notes into each export. (There's a special case relating to use of updated:. Please see Archive Old Notes)

Other than those three terms, you should be able to use most of the others. For example, you could specify

tag:important

to include only notes that are tagged with important. Or you could use:

-tag:obsolete

to exclude notes tagged with obsolete.

Processing of these optional search terms is handled entirely inside Evernote. So, you can test your terms using the search box in the Evernote program. When the script applies your search terms during export processing, those terms will be prefixed with the notebook name and -- except for the first export of a notebook -- the modification date of the notes, for example:

notebook:travel updated:20201123T135216Z tag:important

For more information about selection by modification date (updated:), see the section Date-Based Export.

Specify Timeout

By default, AppleScript limits the run time of a script (that's elapsed time, not processor time). This may not provide enough time to export all your selected notebooks. You can supply a different timeout value, if you wish. The default is 30 minutes.

In test runs on a Macbook Pro from 2014, it took about 7 to 8 minutes to export 1,530 notes comprising 1.6GB of HTML plus 2.0GB of ENEX files. The export files were written to the internal SSD hard drive. Exports to slower USB thumb drives would likely be slower.

Start Export

Once you have established your settings -- or immediately, on subsequent executions of the script -- you'll be presented with the choice to Export Now, to Change Settings, or to Cancel. This dialog box also summarizes the current settings for the impending export.

You can change settings repeatedly if you wish. If you have made changes, your settings will be saved and restored the next time you run the script. See Property List File below.

As the script runs, progress messages will appear as each notebook is processed. When the script completes, an alert message appears showing summary statistics for the export.

Permissions

The first time you run an export, you may be prompted by macOS for various permissions, depending on whether you've run Script Editor before and what scripts you may have run in the past. For example, you'll be prompted to allow control of System Events, Finder, and Evernote. And you'll be prompted to allow System Events access to the folder (perhaps your Documents) where you've placed the export folders.

Accessing Exported ENEX Files

Once the export process completes, in the folder you specified there will be one ENEX file for each notebook that was selected. Generally speaking, these files can be re-imported back in to Evernote or imported into other applications.

Accessing Exported HTML Files

The export process creates a collection of HTML files linked through a set of index.html files. They should be viewable in a browser. The top level index page contains a table with one row per exported notebook. It is located a [your-html-folder]/index.html. For example, if you choose to set the output folder to Documents/Evernote Exports, then the top level index would be at Documents/Evernote Exports/index.html.

You can open this file directly from Finder by double-clicking it or by selecting it and then pressing ⌘-O. You shouldn't move this file because it would break the links to all the underlying notebook indexes. But you can create an alias that can be moved around the file system as you wish. For example, you could create an alias and move it to your desktop. To create an alias, select the top level index.html file, then choose File > Make Alias, or right click and choose Make Alias. Move the alias wherever you want. When you open the alias, you'll be opening the top level index.

Each exported notebook is stored in its own folder which contains an index.html file that lists the notes in that notebook. You can open any of these index files or an individual note file directly.

Export Processing

The script processes notebooks in turn, choosing notes for export and directing Evernote to create the export files and folders.

Notebooks

Notebooks are processed alphabetically, whether you have selected specific notebooks for export or are exporting all of them.

For each notebook, the ENEX export takes place followed by the HTML export. After each HTML notebook export, the HTML index page for that notebook is rebuilt.

If any HTML export was requested or if the top-level HTML index page does not exist, then after all exports have taken place, the top-level HTML index page is rebuilt. There is also an internal switch, alwaysBuildIndex, that can be used to force rebuilding of the top level index (by setting the switch to true).

Note Selection

Notes are selected for export one notebook at a time. All notes will be included unless you've provided Optional Search Terms. In that case, only notes matching the search terms will be included in the export for that notebook.

Date-Based Export

After the first export of a notebook in a particular format (i.e., HTML or ENEX), subsequent exports will occur only if the notebook contains changed notes. The script will examine the existing exported files and compare the date when they were exported to the modification dates of notes within the notebook. An export will occur only if Evernote holds notes that have been updated since the previous export.

For ENEX files, the date of the latest export is stored (by Evernote) in an XML attribute named export-date inside the ENEX file. The script reads that attribute to determine when the export was created.

For HTML files, the date of the last export from a notebook is stored in an HTML comment field within the index.html file for the notebook. The script reads that value.

The export dates for each individual notebook and for each of the two formats are all stored independently. So, subsequent export choices are made individually for every notebook. This means you can safely export subsets of your Evernote notes without compromising the ability to later export all updated notes.

Known Limitations

There are some limitations in the operation of this AppleScript, including at least those described here. There are almost certainly other limitations that we are not yet aware of.

Notebook Names with Quotes

If the name of a notebook includes the quote " character, it is subject to special processing. The result should be the same as normal notebooks, but the script uses different logic to select the notes for export.

This limitation arises from the apparent fact that Evernote search syntax does not seem to allow quotes to be escaped in the search syntax. Although blanks and most special characters can be included in a notebook name (for example,notebook:"My 😀 ' happy book"), there doesn't appear to be any way to specify a name with a quote.

In order to select notes from a notebook containing a quote in its name, the script may have to examine many (or all) notes in Evernote. This may cause it to run very slowly for those notebook(s).

Empty Notebooks

Empty notebooks in Evernote -- that is, those that contain no notes -- are not processed by this script.

Stacks Not Supported

The exported notebooks do not include any information about stacks. The Evernote interface to Applescript does provide contain any information about whether a notebook is stored within a stack. All exported notebooks are stored together in one directory (one for ENEX and one for HTML).

Evernote Software Version

This script has been tested with Evernote version 7.14 installed directly from the Evernote website, running on macOS 10.15.7 (Catalina) and macOS 11.1 (Big Sur). It will almost certainly not run with the Evernote application installed from Apple's Mac App Store.

At this writing, Evernote version 10 is a new and evolving product. At this time -- February 2021 -- version 10 does not support Applescript.

ENEX File Size

There have been reports online suggesting that Evernote has a limitation on the size of an ENEX file that will be accepted for import. Some say it will not accomodate ENEX files larger than 200MB. So, if you are depending on this script to provide backups for Evernote that you might want to import back into Evernote, you should determine if this limitation does, in fact, exist.

The same concern might arise if you intend to import these ENEX files into other applications. If you have large notebooks, please test the import functionality before you rely on it.

Duplicate Note Titles

Apparently, Evernote supports duplicate note titles within a notebook. When this script invokes Evernote to export a notebook, Evernote uses the Note Title to construct the file name (e.g., MyNote.html) for HTML exports. The operating system does not support duplicate file names within a folder. The Evernote export function does not appear to handle this unusual situation and results are unpredictable.

Character Sets

This script has been written and tested with a locale of en-US using UTF-8. Several unusual notebook names and note titles were used as test cases, with emojis, punctuation and other symbols in the names. They appear to be handled successfully.

No attempt has been made to test with other language or locale settings.

The notebook names are used by this script to generate the ENEX export file names and the HTML export folder names. Evernote uses note titles to generate the HTML file names for each exported note. Most unusual characters (e.g., emojis, punctuation, etc) seem to process successfully. The only known exceptions are the forward slash (/) and the colon (:). Evernote replaces a slash with an underscore and replaces a colon with a slash.

Dates, Timestamps and Time Zones

Internally, Evernote appears to use GMT date/time values to record notebook creation and modification dates. However, the Evernote app shows dates and times in the user's timezone.

This script follows that convention. Export date/time stamps in the HTML index files are recorded as GMT times. But for the most part, those times are shown in local time when the user views the index pages. When the user loads an index page, a javascript function updates the displayed dates and times to match the user's local time zone.

At least, that's how it is designed to work. However, it has only been tested in one time zone (US Eastern). So, further testing, in multiple time zones, would be helpful.

Serialization

This script makes no attempt to serialize access to the Evernote data store during export operations. In other words, if someone else is updating a note while the export is taking place or if the Evernote app on your computer is syncing with the online repository, results are unpredictable.

Accordingly, it is good practice to click the Evernote sync button before running an export, to help ensure that the export gets the most recent version of each note.

HTML Format

When notes are exported by Evernote, there are some compromises in formatting. Not all exported notes appear the same as when viewed in Evernote. Indeed, some notes created from clipped web pages do not display at all in Safari. These exported HTML files are created directly from Evernote. The script has no role in determining the HTML content.

If visual fidelity is important to you, please take a careful look at the exported versions.

Evernote Export Limit

There are comments online about an export limit of 50 notes. This limit is apparently imposed on free Evernote accounts. I have a paid account, so I don't know if the limit applies to exports triggered via AppleScript calls to Evernote. In other words, I don't know how the script will behave when accessing a free Evernote account.

Known Errors

Evernote Got An Error

On rare occasions, Evernote is unable to export a notebook in HTML format due to some internal problem with the resources (i.e., attachments) for a particular note. This manifests in the Notebook Export Manager script as a failure in line 254 of the script, inside the exportNotes handler (a few lines from the end of that handler):

if oType = "HTML" then tell application "Evernote" to export selectedNotes to oFile format HTML

The reported error is too vague ("Evernote got an error") to narrow the problem down to a particular note. No further information is returned to AppleScript to allow it to be diagnosed by the script. The recommended recovery is to go back to Evernote and manually attempt to export the offending notebook:

  1. Look at the export output directory for HTML. It will contain some notebooks, but not all. The notebook that caused the failure, and all those after it (in alphabetical order) will be missing. If you were exporting ENEX files at the same time, you'll find a successful ENEX export file, but not an HTML output folder for the failing notebook.
  2. Go to Evernote. Click on View > Notebooks (or ⌥⌘1). Scroll down to the failing notebook, right-click (or click the three dots to the right) and select Export Notes from "notebook" and choose HTML format.
  3. Evernote will begin processing the notebook for HTML export and will stop on the note that's causing the problem.
  4. Manually resolve the problem by deleting the offending note or copying and pasting its content into a new note (then delete the offending note). It's not obvious why these few notes fail. The attachments seem to be accessible within the Evernote app, but they fail during export.
  5. Retry the export from Notebook Export Manager. Typically, you do not need to reset the Settings to start with the previously failed notebook. The script will skip past the notebooks that were successfully exported at the rate of about 1 per second.

In a full export of about 2,500 notes across about 60 notebooks, three notes had this problem. Once they were resolved, the export completed successfully.

Use Cases

This section discusses considerations for using this script.

Backup

This script could be used to create a backup, on your computer, of data stored in Evernote. However, the script does not keep multiple versions of notes as they are changed in Evernote. Only the most recently exported version is available in the HTML or ENEX files.

The script makes no attempt to synchronize changes made in Evernote with the HTML and ENEX output files, except to export notebooks that contain newly changed notes. Other changes are not reflected in the exported files. Here are some examples of changes that are not handled by the script:

  • Changing tags: If you change the tags assigned to a note, it does not appear that the modification date for the note gets updated. In other words, the note appears to be unchanged. This script does not detect the tag change and thus will not re-export the note or update its tag listings in the HTML export files.
  • Deleting notes: When Evernote is called to export a notebook, the target location is first erased. For an ENEX export, the target .enex file is overwritten. For an HTML export, the target folder for the notebook is emptied before the export takes place. So, if a note is exported and is later deleted in Evernote, following a later export, it will no longer exist within the exported copies. However, the deletion of a note -- by itself -- will not trigger an export. Only a change to some other note in the same notebook would trigger an export.

Depending on your folder configuration, exported ENEX and HTML notebooks could be included in your local backup solution, such as Time Machine or an internet-based backup service. As noted elsewhere in this document, you can also direct the script to export to a removeable device, such as a USB thumb drive.

Archive Old Notes

This script could be used to archive older notes, using a special Optional Search Term. It can be used to export only those notes updated before a user-specified date. This techique will work only the first time a particular notebook is exported into a folder.

The user would change the settings and set an Optional Search Term such as -updated:20180101, for example (note the leading dash). This would restrict the export to notes not updated since January 1, 2018.

This technique only works the first time a notebook is exported into a particular folder. In subsequent exports into the same folder, the date-based export will find the previously exported search and insert a updated:[date] term into the search string. This will cause a conflict in the search, with unpredictable results. So, if you create an archive of old notes, you should probably take steps to prevent those notebook(s) from being re-exported into the same HTML or ENEX files and folders.

This archiving technique could use additional search terms. For example: -updated:20170401 tag:history would select notes not updated since April 2017 that are tagged history. You can test your optional search strings using the search box in the Evernote app.

Export for Web

The notebooks and notes exported as HTML have been cursorily tested with a browser. It's possible that this script could be used to generate HTML folders that could be placed on a web server on an intranet or the Internet.

Exported Folders and Files

This section describes the folders and files created by the script.

ENEX

Within the ENEX export folder selected by the user, this script creates one ENEX file for each exported notebook. The script invokes Evernote to create each file, using the notebook name to derive the file name. The internal format of these files is set solely by Evernote.

HTML Folder Structure

Within the HTML export folder selected by the user, this script creates several files in the top folder and creates a subfolder for each exported notebook.

These files are created in the top level folder:

  • index.html is the top level web page for all exported notebooks. It can be opened in your default browser (double-click or select and ⌘-O). This file is regenerated on each run of the script, so long as at least one HTML export occurred or if it does not already exist.
  • entags.html is the top level list of tags found in all exported notes. It is linked from index.html and from the index pages for every exported notebook.
  • enscripts.js contains the javascript that powers initialization and sorting functionality on all the index pages. This javascript file is created by the script the first time it runs. The source for the file is stored in the script as a text constant. If the script finds this file already in place, it does not overwrite it. So, if the user chooses to edit it, the changes will not be overwritten.
  • enstyles.css contains CSS to format the index pages created by the script. As with the javascript file, this CSS file is created on the first run of the script and will not subsequently be overwritten.

Notebook Subfolders

Each exported notebook is placed in its own subfolder, which is created by Evernote when that notebook is first exported. A notebook subfolder contains:

  • An index.html file, originally created by Evernote during the notebook export, and then replaced with a more functional version by this script, after Evernote has completed the export. This index file contains a link to every exported note and a table of tags used within the notebook.
  • An html file for each exported note, with a file name derived from the note title.
  • If a note contains file attachments, they are exported into a lower level folder unique to that note.

Notebook Index Pages

When Evernote is called to export a notebook as HTML, it creates a very simple index.html page for the notebook, providing links to each exported note. This script replaces that index page with a more complete index showing note titles, creation and modification dates, size (on disk), number of attached files, author, and associated tags. The header in each colunn can be clicked to sort the table.

Each notebook index page also contains a sortable table showing any tags assigned to the notes in that notebook.

Embedded within HTML comments in the notebook index page is the following information:

  • the date and time this notebook was last exported from Evernote
  • some descriptive information about the environment when the export occurred, such as the version of Evernote, the locale (e.g, en-US), etc.
  • the data (one table row) needed to create this notebook's entry in the top-level index.
  • the tag section, if any, of the notebook index page, which is wrapped with comments that allow it to be extracted and added to the top-level tag page.

If these comments are altered, the script probably will not function correctly.

Most fields in the table are self-explanatory. The date fields will show a tooltip with the date and time of day. If the Author field included an email address, that address is displayed as a tooltip and the display author name includes an envelope icon (✉️).

The notebook index page is rebuilt every time the notebook is exported as HTML.

Top Level Index Page

The top level index.html file contains a web page with links to each exported notebook index page. This page is rebuilt whenever an export operation results in an HTML export or if the user has set the alwaysBuildIndex to true in the script. The page is built entirely by extracting hidden comment fields from the individual notebook index pages. So, it reflects the contents of the exported file, rather than the live contents in the Evernote repository.

All exported notebooks will be reflected in the top level index page, even if they were not exported in the current run of the script. For example, assume you export all 10 of your notebooks. The next day, you run the script again, but you change the settings to only export 2 notebooks. When the top level index is rebuilt during that second run, it will reflect the two notebooks just exported plus the other 8 that are still present on disk from the day before.

Javascript file

The first time a notebook is exported as HTML, the script creates a file, enscript.js, containing javascript that is invoked on each notebook index page and on the top-level index and tag pages. The code for this file originates from a text constant within the script. This method of distribution was chosen so that the user doesn't have to place the file in the output directory; it happens automatically.

On subsequent executions of the script, the file is not overwritten. So, if the user makes any changes to the javascript, those changes remain in place.

The javascript file contains several functions that are invoked on the index pages:

  • setLocalDates is used to adjust displayed dates to the user's locale. Dates, such as the modification date of a note, are stored as GMT values in the data-gmtdate attribute of tags. This script, called via the onload event, calculates the local date and updates the displayed value for the table cell and a title for each cell showing local date and time (i.e., a tool-tip).
  • sortTable is used to sort tables when a user clicks on a table heading cell.
  • hideNBnames hides selected columns in a table by dynamically creating a specified class with the display:none attribute. This is used because the same basic Tag table appears in each notebook index page and, in aggregate form, in the top-level tag index page.
  • settarget implements the open in new tab functionality, as controlled by the checkbox in the upper right corner of each index page.

CSS File

The enstyles.css file is created on the first run of the script to provide formatting instructions for the index pages. Changes to this file will be reflected in the top-level pages (index and tags) and in each notebook index page. Like the javascript file, the CSS file is not overwritten by the script after it's first created.

Moving or Renaming

If you move the HTML folder structure, all the internal links on the index.html pages should continue to work, because they are relative to the top-level index page.

However, renaming subfolders or html pages is more complicated and will probably create useability problems.

Customization

Property List File

The script stores its settings in a standard macOS Property List File or plist. The name and full path to this file are stored in a variable named myPListFullPath early in the script.

By convention, the plist files are stored in ~/Library/Preferences. The filename is also set in the script, on the same line as the path. The user could alter the name or location, if desired.

Rebuild Top Index

The top-level HTML index page is rebuilt in these situations:

  • If it does not exist
  • If any notebook has been exported in HTML format
  • If the variable alwaysBuildIndex is set to true. It is set that way in the current version of the script. To suppress this behavior, set it to false.

Rebuild Notebook Indexes

Normally, the index.html page is build only when a notebook is exported in HTML format. However, there is a switch in the script that will force these pages to be rebuilt for any notebook examined during the run. This might be useful if the content of these index pages needs to be updated, but it is otherwise not necessary to re-export the notebooks from Evernote.

To force rebuilding, set the variable alwaysBuildBookIndexes to true. The index for every notebook or for the notebooks you've selected will be rebuilt even if the script does not find it necessary to re-export that notebook.

In this mode, if an index.html file is being rebuilt for a notebook that was not just exported, the script will read the existing index and retain the Export Date from the previous export.

Diagnostic Logging

A switch named logProgress can be set to true to cause the script to log various diagnostic information to the Script Editor log during execution.

About

Manage HTML and ENEX exports from Evernote on macOS

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published