# enex2notion
[![PyPI version](https://img.shields.io/pypi/v/enex2notion?label=version)](https://pypi.python.org/pypi/enex2notion)
[![Python Version](https://img.shields.io/pypi/pyversions/enex2notion.svg)](https://pypi.org/project/enex2notion/)
[![tests](https://github.com/vzhd1701/enex2notion/actions/workflows/test.yml/badge.svg)](https://github.com/vzhd1701/enex2notion/actions/workflows/test.yml)
[![codecov](https://codecov.io/gh/vzhd1701/enex2notion/branch/master/graph/badge.svg)](https://codecov.io/gh/vzhd1701/enex2notion)
Easy way to import [Evernote's](https://www.evernote.com/) `*.enex` files to [Notion.so](https://notion.so)
Notion's native Evernote importer doesn't do it for me, so I decided to write my own. Thanks to **Cobertos** and [md2notion](https://github.com/Cobertos/md2notion) for inspiration and **Jamie Alexandre** for [notion-py](https://github.com/jamalex/notion-py).
You can either use Evernote native export or try out my other tool, [evernote-backup](https://github.com/vzhd1701/evernote-backup), to export `*.enex` files from Evernote.
### What is preserved
- Embedded files and images are uploaded to Notion
- nested images will appear after paragraph
- Text formatting (**bold**, _italic_, etc) and colors
- Tables are converted to the new format (no colspans though)
- Web Clips
- as plain text or PDFs, see [below](#web-clips)
- Everything else basically
### What is lost
- Paragraph alignment
- Subscript and superscript formatting
- Custom fonts and font sizes
- Tasks
- Encrypted blocks
- just decrypt them before export
## Installation
If you are not familiar with command line programs, take a look at these step-by-step guides:
### [Step-by-step guide for Windows](https://vzhd1701.notion.site/How-to-use-enex2notion-on-Windows-6fa980b489ab4414a5317e631e7f6bc6)
### [Step-by-step guide for macOS](https://vzhd1701.notion.site/How-to-use-enex2notion-on-macOS-a912dd63e3d14da886a413d3f83efb67)
### Using portable binary
[**Download the latest binary release**](https://github.com/vzhd1701/enex2notion/releases/latest) for your OS.
### With [Homebrew](https://brew.sh/) (Recommended for macOS)
```bash
$ brew install enex2notion
```
### With [**PIPX**](https://github.com/pipxproject/pipx) (Recommended for Linux & Windows)
```shell
$ pipx install enex2notion
```
### With [**Docker**](https://docs.docker.com/)
[![Docker Image Size (amd64)](<https://img.shields.io/docker/image-size/vzhd1701/enex2notion?arch=amd64&label=image%20size%20(amd64)>)](https://hub.docker.com/r/vzhd1701/enex2notion)
[![Docker Image Size (arm64)](<https://img.shields.io/docker/image-size/vzhd1701/enex2notion?arch=arm64&label=image%20size%20(arm64)>)](https://hub.docker.com/r/vzhd1701/enex2notion)
This command maps current directory `$PWD` to the `/input` directory in the container. You can replace `$PWD` with a directory that contains your `*.enex` files. When running commands like `enex2notion /input` refer to your local mapped directory as `/input`.
```shell
$ docker run --rm -t -v "$PWD":/input vzhd1701/enex2notion:latest
```
### With PIP
```bash
$ pip install --user enex2notion
```
**Python 3.8 or later required.**
### From source
This project uses [poetry](https://python-poetry.org/) for dependency management and packaging. You will have to install it first. See [poetry official documentation](https://python-poetry.org/docs/) for instructions.
```shell
$ git clone https://github.com/vzhd1701/enex2notion.git
$ cd enex2notion/
$ poetry install
$ poetry run enex2notion
```
## Usage
```shell
$ enex2notion --help
usage: enex2notion [-h] [--token TOKEN] [OPTION ...] FILE/DIR [FILE/DIR ...]
Uploads ENEX files to Notion
positional arguments:
FILE/DIR ENEX files or directories to upload
optional arguments:
-h, --help show this help message and exit
--token TOKEN Notion token, stored in token_v2 cookie for notion.so [NEEDED FOR UPLOAD]
--root-page NAME root page name for the imported notebooks, it will be created if it does not exist (default: "Evernote ENEX Import")
--mode {DB,PAGE} upload each ENEX as database (DB) or page with children (PAGE) (default: DB)
--mode-webclips {TXT,PDF} convert web clips to text (TXT) or pdf (PDF) before upload (default: TXT)
--retry N retry N times on note upload error before giving up, 0 for infinite retries (default: 5)
--skip-failed skip notes that failed to upload (after exhausting --retry attempts), by default the program will crash on upload error
--keep-failed keep partial pages at Notion with '[UNFINISHED UPLOAD]' in title if they fail to upload completely, by default the program will try to delete them on upload fail
--add-pdf-preview include preview image with PDF webclips for gallery view thumbnail (works only with --mode-webclips=PDF)
--add-meta include metadata (created, tags, etc) in notes, makes sense only with PAGE mode
--tag TAG add custom tag to uploaded notes
--condense-lines condense text lines together into paragraphs to avoid making block per line
--condense-lines-sparse like --condense-lines but leaves gaps between paragraphs
--done-file FILE file for uploaded notes hashes to resume interrupted upload
--log FILE file to store program log
--verbose output debug information
--version show program's version number and exit
```
### Input
You can pass single `*.enex` files or directories. The program will recursively scan directories for `*.enex` files.
### Token & dry run mode
The upload requires you to have a `token_v2` cookie for the Notion website. For information on how to get it, see [this article](https://vzhd1701.notion.site/Find-Your-Notion-Token-5f57951434c1414d84ac72f88226eede).
The program can run without `--token` provided though. It will not make any network requests without it. Executing a dry run with `--verbose` is an excellent way to check if your `*.enex` files are parsed correctly before uploading.
### Upload continuation
The upload will take some time since each note is uploaded block-by-block, so you'll probably need some way of resuming it. `--done-file` is precisely for that. All uploaded note hashes will be stored there, so the next time you start, the upload will continue from where you left off.
All uploaded notebooks will appear under the automatically created `Evernote ENEX Import` page. You can change that name with the `--root-page` option. The program will mark unfinished notes with `[UNFINISHED UPLOAD]` text in the title. After successful upload, the mark will be removed.
### Upload modes
The `--mode` option allows you to choose how to upload your notebooks: as databases or pages. `DB` mode is the default since Notion itself uses this mode when importing from Evernote. `PAGE` mode makes the tree feel like the original Evernote notebooks hierarchy.
Since `PAGE` mode does not benefit from having separate space for metadata, you can still preserve the note's original meta with the `--add-meta` option. It will attach a callout block with all meta info as a first block in each note [like this](https://imgur.com/a/lJTbprH).
### Web Clips
Due to Notion's limitations Evernote web clips cannot be uploaded as-is. `enex2notion` provides two modes with the `--mode-webclips` option:
- `TXT`, converting them to text, stripping all HTML formatting \[Default\]
- similar to Evernote's "Simplify & Make Editable"
- `PDF`, converting them to PDF, keeping HTML formatting as close as possible
- web clips are converted using [wkhtmltopdf](https://wkhtmltopdf.org/), see [this page](https://github.com/JazzCore/python-pdfkit/wiki/Installing-wkhtmltopdf) on how to install it
Since Notion's gallery view does not provide thumbnails for embedded PDFs, you have the `--add-pdf-preview` option to extract the first page of generated PDF as a preview for the web clip page.
### Banned file extensions
Notion prohibits uploading files with certain extensions. The list consists of extensions for executable binaries, supposedly to prevent spreading malware. `enex2notion` will automatically add a `bin` extension to those files to circumvent this limitation. List of banned extensions: `apk`, `app`, `com`, `ear`, `elf`, `exe`, `ipa`, `jar`, `js`, `xap`, `xbe`, `xex`, `xpi`.
### Misc
The `--condense-lines` option is helpful if you want to save up some space and make notes look more compact. [Example](https://imgur.com/a/sV0X8z7).
The `--condense-lines-sparse` does the same thing as `--condense-lines`, but leaves gaps between paragraphs. [Example](https://imgur.com/a/OBzeqn7).
The `--tag` option allows you to add a custom tag to all uploaded notes. It will add this tag to existing tags if the note already has any.
## Examples
### Checking notes before upload
```shell
$ enex2notion --verbose my_notebooks/
```
### Uploading notes from a single notebook
```shell
$ enex2notion --token <YOUR_TOKEN_HERE> "notebook.enex"
```
### Uploading with the option to continue later
```shell
$ enex2notion --token <YOUR_TOKEN_HERE> --done-file done.txt "notebook.enex"
```
## Getting help
If you found a bug or have a feature request, please [open a new issue](https://github.com/vzhd1701/enex2notion/issues/new/choose).
If you have a question about the program or have difficulty using it, you are welcome to [the discussions page](https://github.com/vzhd1701/enex2notion/discussions). You can also mail me directly, I'm always happy to help.
Raw data
{
"_id": null,
"home_page": "https://github.com/vzhd1701/enex2notion",
"name": "enex2notion",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.8,<4.0",
"maintainer_email": "",
"keywords": "evernote,enex,notion,import",
"author": "vzhd1701",
"author_email": "vzhd1701@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/de/5c/c0ce22d810226345411b03177f9b43c35b82c3a671d5d73f56fc43b0858e/enex2notion-0.3.1.tar.gz",
"platform": null,
"description": "# enex2notion\n\n[![PyPI version](https://img.shields.io/pypi/v/enex2notion?label=version)](https://pypi.python.org/pypi/enex2notion)\n[![Python Version](https://img.shields.io/pypi/pyversions/enex2notion.svg)](https://pypi.org/project/enex2notion/)\n[![tests](https://github.com/vzhd1701/enex2notion/actions/workflows/test.yml/badge.svg)](https://github.com/vzhd1701/enex2notion/actions/workflows/test.yml)\n[![codecov](https://codecov.io/gh/vzhd1701/enex2notion/branch/master/graph/badge.svg)](https://codecov.io/gh/vzhd1701/enex2notion)\n\nEasy way to import [Evernote's](https://www.evernote.com/) `*.enex` files to [Notion.so](https://notion.so)\n\nNotion's native Evernote importer doesn't do it for me, so I decided to write my own. Thanks to **Cobertos** and [md2notion](https://github.com/Cobertos/md2notion) for inspiration and **Jamie Alexandre** for [notion-py](https://github.com/jamalex/notion-py).\n\nYou can either use Evernote native export or try out my other tool, [evernote-backup](https://github.com/vzhd1701/evernote-backup), to export `*.enex` files from Evernote.\n\n### What is preserved\n\n- Embedded files and images are uploaded to Notion\n - nested images will appear after paragraph\n- Text formatting (**bold**, _italic_, etc) and colors\n- Tables are converted to the new format (no colspans though)\n- Web Clips\n - as plain text or PDFs, see [below](#web-clips)\n- Everything else basically\n\n### What is lost\n\n- Paragraph alignment\n- Subscript and superscript formatting\n- Custom fonts and font sizes\n- Tasks\n- Encrypted blocks\n - just decrypt them before export\n\n## Installation\n\nIf you are not familiar with command line programs, take a look at these step-by-step guides:\n\n### [Step-by-step guide for Windows](https://vzhd1701.notion.site/How-to-use-enex2notion-on-Windows-6fa980b489ab4414a5317e631e7f6bc6)\n\n### [Step-by-step guide for macOS](https://vzhd1701.notion.site/How-to-use-enex2notion-on-macOS-a912dd63e3d14da886a413d3f83efb67)\n\n### Using portable binary\n\n[**Download the latest binary release**](https://github.com/vzhd1701/enex2notion/releases/latest) for your OS.\n\n### With [Homebrew](https://brew.sh/) (Recommended for macOS)\n\n```bash\n$ brew install enex2notion\n```\n\n### With [**PIPX**](https://github.com/pipxproject/pipx) (Recommended for Linux & Windows)\n\n```shell\n$ pipx install enex2notion\n```\n\n### With [**Docker**](https://docs.docker.com/)\n\n[![Docker Image Size (amd64)](<https://img.shields.io/docker/image-size/vzhd1701/enex2notion?arch=amd64&label=image%20size%20(amd64)>)](https://hub.docker.com/r/vzhd1701/enex2notion)\n[![Docker Image Size (arm64)](<https://img.shields.io/docker/image-size/vzhd1701/enex2notion?arch=arm64&label=image%20size%20(arm64)>)](https://hub.docker.com/r/vzhd1701/enex2notion)\n\nThis command maps current directory `$PWD` to the `/input` directory in the container. You can replace `$PWD` with a directory that contains your `*.enex` files. When running commands like `enex2notion /input` refer to your local mapped directory as `/input`.\n\n```shell\n$ docker run --rm -t -v \"$PWD\":/input vzhd1701/enex2notion:latest\n```\n\n### With PIP\n\n```bash\n$ pip install --user enex2notion\n```\n\n**Python 3.8 or later required.**\n\n### From source\n\nThis project uses [poetry](https://python-poetry.org/) for dependency management and packaging. You will have to install it first. See [poetry official documentation](https://python-poetry.org/docs/) for instructions.\n\n```shell\n$ git clone https://github.com/vzhd1701/enex2notion.git\n$ cd enex2notion/\n$ poetry install\n$ poetry run enex2notion\n```\n\n## Usage\n\n```shell\n$ enex2notion --help\nusage: enex2notion [-h] [--token TOKEN] [OPTION ...] FILE/DIR [FILE/DIR ...]\n\nUploads ENEX files to Notion\n\npositional arguments:\n FILE/DIR ENEX files or directories to upload\n\noptional arguments:\n -h, --help show this help message and exit\n --token TOKEN Notion token, stored in token_v2 cookie for notion.so [NEEDED FOR UPLOAD]\n --root-page NAME root page name for the imported notebooks, it will be created if it does not exist (default: \"Evernote ENEX Import\")\n --mode {DB,PAGE} upload each ENEX as database (DB) or page with children (PAGE) (default: DB)\n --mode-webclips {TXT,PDF} convert web clips to text (TXT) or pdf (PDF) before upload (default: TXT)\n --retry N retry N times on note upload error before giving up, 0 for infinite retries (default: 5)\n --skip-failed skip notes that failed to upload (after exhausting --retry attempts), by default the program will crash on upload error\n --keep-failed keep partial pages at Notion with '[UNFINISHED UPLOAD]' in title if they fail to upload completely, by default the program will try to delete them on upload fail\n --add-pdf-preview include preview image with PDF webclips for gallery view thumbnail (works only with --mode-webclips=PDF)\n --add-meta include metadata (created, tags, etc) in notes, makes sense only with PAGE mode\n --tag TAG add custom tag to uploaded notes\n --condense-lines condense text lines together into paragraphs to avoid making block per line\n --condense-lines-sparse like --condense-lines but leaves gaps between paragraphs\n --done-file FILE file for uploaded notes hashes to resume interrupted upload\n --log FILE file to store program log\n --verbose output debug information\n --version show program's version number and exit\n```\n\n### Input\n\nYou can pass single `*.enex` files or directories. The program will recursively scan directories for `*.enex` files.\n\n### Token & dry run mode\n\nThe upload requires you to have a `token_v2` cookie for the Notion website. For information on how to get it, see [this article](https://vzhd1701.notion.site/Find-Your-Notion-Token-5f57951434c1414d84ac72f88226eede).\n\nThe program can run without `--token` provided though. It will not make any network requests without it. Executing a dry run with `--verbose` is an excellent way to check if your `*.enex` files are parsed correctly before uploading.\n\n### Upload continuation\n\nThe upload will take some time since each note is uploaded block-by-block, so you'll probably need some way of resuming it. `--done-file` is precisely for that. All uploaded note hashes will be stored there, so the next time you start, the upload will continue from where you left off.\n\nAll uploaded notebooks will appear under the automatically created `Evernote ENEX Import` page. You can change that name with the `--root-page` option. The program will mark unfinished notes with `[UNFINISHED UPLOAD]` text in the title. After successful upload, the mark will be removed.\n\n### Upload modes\n\nThe `--mode` option allows you to choose how to upload your notebooks: as databases or pages. `DB` mode is the default since Notion itself uses this mode when importing from Evernote. `PAGE` mode makes the tree feel like the original Evernote notebooks hierarchy.\n\nSince `PAGE` mode does not benefit from having separate space for metadata, you can still preserve the note's original meta with the `--add-meta` option. It will attach a callout block with all meta info as a first block in each note [like this](https://imgur.com/a/lJTbprH).\n\n### Web Clips\n\nDue to Notion's limitations Evernote web clips cannot be uploaded as-is. `enex2notion` provides two modes with the `--mode-webclips` option:\n\n- `TXT`, converting them to text, stripping all HTML formatting \\[Default\\]\n\n - similar to Evernote's \"Simplify & Make Editable\"\n\n- `PDF`, converting them to PDF, keeping HTML formatting as close as possible\n\n - web clips are converted using [wkhtmltopdf](https://wkhtmltopdf.org/), see [this page](https://github.com/JazzCore/python-pdfkit/wiki/Installing-wkhtmltopdf) on how to install it\n\nSince Notion's gallery view does not provide thumbnails for embedded PDFs, you have the `--add-pdf-preview` option to extract the first page of generated PDF as a preview for the web clip page.\n\n### Banned file extensions\n\nNotion prohibits uploading files with certain extensions. The list consists of extensions for executable binaries, supposedly to prevent spreading malware. `enex2notion` will automatically add a `bin` extension to those files to circumvent this limitation. List of banned extensions: `apk`, `app`, `com`, `ear`, `elf`, `exe`, `ipa`, `jar`, `js`, `xap`, `xbe`, `xex`, `xpi`.\n\n### Misc\n\nThe `--condense-lines` option is helpful if you want to save up some space and make notes look more compact. [Example](https://imgur.com/a/sV0X8z7).\n\nThe `--condense-lines-sparse` does the same thing as `--condense-lines`, but leaves gaps between paragraphs. [Example](https://imgur.com/a/OBzeqn7).\n\nThe `--tag` option allows you to add a custom tag to all uploaded notes. It will add this tag to existing tags if the note already has any.\n\n## Examples\n\n### Checking notes before upload\n\n```shell\n$ enex2notion --verbose my_notebooks/\n```\n\n### Uploading notes from a single notebook\n\n```shell\n$ enex2notion --token <YOUR_TOKEN_HERE> \"notebook.enex\"\n```\n\n### Uploading with the option to continue later\n\n```shell\n$ enex2notion --token <YOUR_TOKEN_HERE> --done-file done.txt \"notebook.enex\"\n```\n\n## Getting help\n\nIf you found a bug or have a feature request, please [open a new issue](https://github.com/vzhd1701/enex2notion/issues/new/choose).\n\nIf you have a question about the program or have difficulty using it, you are welcome to [the discussions page](https://github.com/vzhd1701/enex2notion/discussions). You can also mail me directly, I'm always happy to help.\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Import Evernote ENEX files to Notion",
"version": "0.3.1",
"project_urls": {
"Changelog": "https://github.com/vzhd1701/enex2notion/blob/master/CHANGELOG.md",
"Homepage": "https://github.com/vzhd1701/enex2notion",
"Repository": "https://github.com/vzhd1701/enex2notion"
},
"split_keywords": [
"evernote",
"enex",
"notion",
"import"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "25dbb947f0b2b5ec27256ca781779fff385fc524d8dcf3a56375b82469fa5071",
"md5": "652b54cfd3b05c6bb7723a490e96892d",
"sha256": "4a9ed8240dd7b5c8acf233df285cf0c8a0ec476e0a1844b215ce0720e8e790bd"
},
"downloads": -1,
"filename": "enex2notion-0.3.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "652b54cfd3b05c6bb7723a490e96892d",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8,<4.0",
"size": 50483,
"upload_time": "2023-10-27T12:19:00",
"upload_time_iso_8601": "2023-10-27T12:19:00.957167Z",
"url": "https://files.pythonhosted.org/packages/25/db/b947f0b2b5ec27256ca781779fff385fc524d8dcf3a56375b82469fa5071/enex2notion-0.3.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "de5cc0ce22d810226345411b03177f9b43c35b82c3a671d5d73f56fc43b0858e",
"md5": "ee44cf1fd2ff6f2a6e2a188d6016feca",
"sha256": "f11d8a7b6c135b4d08c63e1256279d56b3798cdd48ad3b6e39c0770dc3bd82e6"
},
"downloads": -1,
"filename": "enex2notion-0.3.1.tar.gz",
"has_sig": false,
"md5_digest": "ee44cf1fd2ff6f2a6e2a188d6016feca",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8,<4.0",
"size": 38290,
"upload_time": "2023-10-27T12:19:02",
"upload_time_iso_8601": "2023-10-27T12:19:02.875002Z",
"url": "https://files.pythonhosted.org/packages/de/5c/c0ce22d810226345411b03177f9b43c35b82c3a671d5d73f56fc43b0858e/enex2notion-0.3.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-10-27 12:19:02",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "vzhd1701",
"github_project": "enex2notion",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "enex2notion"
}