Yi's Blog

不图新奇,但问优劣

Breaking Up with Evernote: Building a Custom Migration Tool for Apple Notes

After 15+ years of note-taking, I finally said goodbye to Evernote. Here’s the technical journey of migrating 4,330 notes—with all their attachments, tables, and formatting—to Apple Notes.

The Problem

Evernote had been my digital brain since the late 2000s. But with each passing version, the app became slower, more bloated, and increasingly expensive. Apple Notes, meanwhile, has quietly evolved into a capable, fast, and free alternative that syncs seamlessly across my devices.

The catch? There’s no official migration path. Evernote’s export format (ENEX) doesn’t preserve everything, and Apple Notes doesn’t have any bulk import feature. Manual copy-paste wasn’t an option.

So I built my own migration tool.

What Made This Hard

This wasn’t a simple file conversion:

  • Rich text formatting including tables, checklists, and styled text
  • Embedded attachments (images, PDFs, documents) referenced by MD5 hashes in Evernote’s proprietary ENML format
  • Creation and modification dates that needed to be preserved
  • Duplicate detection to allow resumable, interruptible migrations
  • Apple Notes’ limitations—no public API, only AppleScript access

Evernote v10 made things even more complicated. Unlike older versions that stored everything in a straightforward SQLite database, v10 uses a hybrid system with:

  • A SQLite database for metadata
  • Separate .dat files containing rich text content (tables/formatting)
  • Protobuf-encoded binary structures
  • Server-side attachment storage requiring authenticated downloads

The Solution: A Two-Phase Migration System

I built a Python-based migration pipeline that handles all of this complexity.

Phase 1: Parallel Preparation

The first phase downloads attachments and generates PDFs in parallel using 10 worker threads. For notes with embedded images or files, I render the complete content (HTML + attachments) into a PDF using headless Chrome. This preserves formatting perfectly.

Phase 2: Sequential Import

The second phase imports to Apple Notes via AppleScript—sequentially, because Apple Notes doesn’t handle concurrent modifications well.

Solving the Attachment Problem

Evernote embeds attachments using <en-media> tags with MD5 hashes. To resolve these to actual files, I:

  1. Query Evernote’s local database for attachment metadata
  2. Download from Evernote’s servers using captured auth tokens
  3. Embed them as base64 in generated PDFs
  4. Attach the PDF to the Apple Notes entry

Deduplication Done Right

My initial attempt at duplicate detection was fragile—comparing dates via AppleScript often failed. The fix was simple: track Evernote note IDs in a log file. This makes the migration fully resumable.

Bonus: AI-Powered Organization

Once notes were in Apple Notes, I used Gemini AI to automatically categorize them into folders based on content.

Lessons Learned

  1. AppleScript is slow but reliable — Building a cache at startup dropped duplicate checks from 0.5s to 0.001s per note.

  2. Parallelism for I/O, sequential for mutations — Downloading attachments scales linearly with workers. Writing to Apple Notes must be sequential.

  3. Auth tokens expire — Evernote’s tokens last about an hour. I kept Proxyman ready to capture fresh tokens.

  4. PDF is a universal container — When your target doesn’t support rich formatting or attachments, bundle everything into a PDF.

The Code

The entire migration toolkit is available on GitHub: apple-notes-toolkit

⚠️ Note: This repo is fully vibe coded. Use with caution.

Final Thoughts

What started as a weekend project turned into a deep dive into Evernote’s internals, Apple’s Scripting Bridge, and the art of data migration. But the result is worth it: my 15 years of notes are now in Apple Notes, fully searchable, syncing across devices, and—most importantly—mine to keep.

If you’re considering leaving Evernote, know that it’s possible. It just takes a bit of engineering.