# notmuch-sync




mbsync-compatible syncing of notmuch databases and mail files.
[PyPI page](https://pypi.org/project/notmuch-sync/)
## Installation and Quickstart
Assumes that you have [notmuch](https://notmuchmail.org) installed and working.
Install with e.g. `pip install notmuch-sync`. No configuration is necessary;
everything is picked up from notmuch. You may however need to install your OS'
packages for xapian.
Before you run `notmuch-sync` for the first time, make sure that notmuch is set
up correctly (in particular with the correct database path). It is not necessary
to copy mails and tags; this will be done automatically by `notmuch-sync` on
first run if one of the sides is a new, empty notmuch database.
Run as e.g. `notmuch-sync --verbose --delete --remote my.mail.server --user
user`. This assumes that you can connect to `my.mail.server` using SSH with user
`user` and that `notmuch-sync` is in the $PATH of that user on the remote
machine. See `notmuch-sync --help` for commandline flags. Notmuch databases need
to be set up on both sides; notmuch-sync does not run `notmuch new`.
In a nutshell, here are the steps you would take if you have notmuch set up on
one machine and wish to sync it with another:
1. Copy your notmuch configuration to the new machine (this may be just `.notmuch-config`).
2. Adjust the configuration as necessary, in particular any paths.
3. Run `notmuch new` on the new machine (no need to copy any mail files).
4. Run `notmuch-sync --verbose --delete --remote other.machine`. Add `--mbsync`
if you're using mbsync.
If you're starting with an empty notmuch database on one side, the first sync
might take a long time. Subsequent syncs should be much faster, unless there are
a lot of changes.
## Commandline Flags
````
usage: notmuch-sync [-h] [-r REMOTE] [-u USER] [-v] [-q] [-s SSH_CMD] [-m] [-p PATH] [-c REMOTE_CMD] [-d] [-x]
options:
-h, --help show this help message and exit
-r, --remote REMOTE remote host to connect to
-u, --user USER SSH user to use
-v, --verbose increases verbosity, up to twice (ignored on remote)
-q, --quiet do not print any output, overrides --verbose
-s, --ssh-cmd SSH_CMD
SSH command to use (default 'ssh -CTaxq')
-m, --mbsync sync mbsync files (.mbsyncstate, .uidvalidity)
-p, --path PATH path to notmuch-sync on remote server
-c, --remote-cmd REMOTE_CMD
command to run to sync; overrides --remote, --user, --ssh-cmd, --path; mostly used for testing
-d, --delete sync deleted messages (requires listing all messages in notmuch database, potentially expensive)
-x, --delete-no-check
delete missing messages even if they don't have the 'deleted' tag (requires --delete) -- potentially unsafe
````
## Main Features
- sync arbitrary pairs of notmuch databases over SSH or through arbitrary custom
commands
- leverage notmuch database revision numbers for efficient changeset
determination
- asynchronous IO for efficient data transfer over networks
- sync state stored as version number and UUID of notmuch database, does not
depend on size of notmuch database
- compatible with [mbsync](https://isync.sourceforge.io/mbsync.html) and works
around some of its quirks (X-TUID...)
- extensive unit and integration tests, with the entire archive of the
[notmuch mailing list](https://nmbug.notmuchmail.org/list/) and a real IMAP
server and mbsync
### Sync Procedure
notmuch-sync uses the revision number of the notmuch database (`lastmod` search
term) to record the last sync and efficiently determine what has changed since
then. The sync process works as follows:
- The notmuch database is opened in write mode to lock it.
- Both sides get the changes since the last sync, or all changes if there has
been no sync with the database UUID on the other side.
- Tags are synced on both sides.
- If a message shows up in the changeset for the other side, its tags are
applied to the message on this side.
- If a message shows up in the changesets for both sides, the union of the
tags of the message from both sides is applied to the message on both sides.
- Files of existing messages are synced as follows, on both local and remote
sides:
- Files missing on this side are determined as the file names the other side
has, but are missing on this side.
- We try to find these missing files locally by comparing the SHA256
digests from the other side with the SHA256 digests for the local files.
Computing the digest does not consider lines starting with "X-TUID: " to
identify identical files that only differ in the mbsync run (e.g. if
mbsync was run separately on both sides).
- Files that are thus identified as the same with different filenames are
- copied if both filenames are also present on the other side and in the
other changeset since the last sync,
- moved from the filename on this side to the filename on the other side if
they are not in our changeset or the `move_on_change` flag is set,
- skipped if none of the above applies and the `move_on_change` flag is not
set.
The `move_on_change` flag is true on the local machine and false on the
remote. It is used to disambiguate which changes to adopt and avoids
creating duplicate messages unnecessarily. This comes up in particular if
both sides independently run mbsync, which creates the same message with
different filenames (and different X-TUID headers) and the same UID. Simply
copying those messages when syncing would create duplicate files, but more
importantly duplicate UIDs (which mbsync stores in the filenames), which
would cause an error on the next mbsync run.
- Duplicate files for the same message that are not present on the other side
are deleted and removed from the notmuch database. There is a check that
this does not accidentally remove messages.
- Any files that are actually missing (don't have files with the same SHA256)
are transferred between the two sides.
- The sync is recorded with notmuch database version and UUID.
- The notmuch database is closed in write mode -- this unlocks it so that any
other processes trying to access it should only have to wait for a short time.
- If `--delete` is given, all notmuch message IDs are listed on both sides and
the messages to be deleted determined by taking the differences between those
sets. Messages are only deleted if they have the "deleted" tag (see the
"Deleting Mails" section for further details).
- If `--mbsync` is given, sync mbsync state files (`.uidvalidity`,
`.mbsyncstate`). The files are listed on both sides and ones with later
modification dates transferred to the other side. This assumes that both
machines have (at least somewhat) synchronized clocks.
### Sync State
The sync state for a remote host is saved in the `.notmuch` directory of your
notmuch mail directory in a file of the form `notmuch-sync-<UUID>` where
`<UUID>` is the UUID of the database synced with (not the UUID of the local
notmuch database). The contents of the file are the revision number of the
local notmuch database after the last tag sync followed by a space and the UUID
of the local notmuch database.
This allows for syncs between any number of arbitrary pairs, even if host
names/IP addresses change, only the UUIDs of the notmuch databases have to
remain the same.
Removing a sync state file starts the sync from scratch the next time
notmuch-sync is run. This should generally be safe (i.e. end up with the two
notmuch databases synced as you would expect), but will do a lot of unnecessary
work and communication.
### Differences to [muchsync](https://www.muchsync.org/)
- syncs filenames and mbsync metadata
- does not rely on shadow copy of notmuch database -- more space efficient and
no sqlite dependency
- probably slower and more memory-hungry
- does not sync notmuch configuration
- no special handling of "unread" tag required as only changes are considered
- does not run `notmuch new` automatically, neither on the local nor the remote
side
- [glorious](https://github.com/larskotthoff/notmuch-sync/blob/main/test/test.py),
[glorious](https://github.com/larskotthoff/notmuch-sync/blob/main/test/test-integration.py),
[glorious](https://github.com/larskotthoff/notmuch-sync/blob/main/.github/workflows/notmuch-ml.yml)
[tests](https://github.com/larskotthoff/notmuch-sync/blob/main/.github/workflows/imap.yml)
### mbsync Compatibility
notmuch-sync syncs mbsync state under the notmuch mail directory, which requires
`SyncState *` for all channels and synchronized clocks. It should be safe to run
mbsync on any of the synced copies at any time; messages that are retrieved
through mbsync on multiple copies will be synced automatically by moving files
accordingly.
### Deleting Mails
notmuch-sync is very careful about deleting mails. While duplicate *files* for
the same email are always cleaned up as part of the sync (i.e. if duplicates
have been deleted on one side, they will also be deleted on the other side),
*messages* are never deleted unless the user explicitly requests it. To do this,
the `--delete` flag must be given, and even then only messages that have been
tagged "deleted" are actually deleted. To delete messages that do not have the
"deleted" tag, you can specify `--delete-no-check` in addition to `--delete`
(not recommended, use at your own risk).
If `--delete` is given, all message IDs in the notmuch database are listed on
both sides (this is potentially expensive). Then the difference between those
lists is taken to determine what messages should be deleted on the local and
remote sides. If a message ID is slated for deletion but the message does *not*
have the "deleted" tag (on either side), notmuch-sync assumes that something has
gone wrong and creates a dummy transaction for the message that changes nothing,
but will make it appear in the next changeset. This will cause the message to be
added on the side where it's missing the next time sync is run.
This should work well with workflows where messages that have been tagged
"deleted" are kept for a while and only then actually deleted by removing the
files. Note that if the interval between tagging messages "deleted" and actually
deleting them is smaller than the interval between syncs (e.g. one side hasn't
been synced in a long time), deleted messages will reappear when synced. This is
because one side will have no record of the "deleted" tag and will only see
messages not present that are not tagged "deleted".
## Limitations
The size limit for most things that are communicated between hosts is $2^{32}$
bytes, i.e. about 4GB. This includes the size of individual mail files, the
length of changesets (message IDs, tags, files, and SHA256 checksums), and the
length of all message IDs. This is not a fundamental limitation but simply to
avoid additional communication overhead and should be sufficient for most use
cases.
The folder structure under the notmuch mail directory is assumed to be the same
on all copies, in particular this means that the mbsync configuration should be
the same as well.
Changes to the notmuch database and mail files while notmuch-sync is running,
e.g. moving files, will result in error messages. It is safe to simply rerun
notmuch-sync when this happens.
Running `notmuch compact` changes the UUID of the database. This means that
subsequent syncs will abort with an error message.
Like muchsync, notmuch-sync uses xapian directly for some operations for
efficiency reasons. This means in particular that notmuch-sync assumes that
value 1 of a xapian document is the message ID and the term "Tghost" is used to
identify ghost messages.
notmuch-sync assumes that the remote command does not produce any output except
for the output produced by the remote notmuch-sync. If you're running a wrapper
script on the remote or have an SSH banner, make sure to silence/redirect all
respective output.
There are extensive tests, but there is no guarantee that notmuch-sync will
always do the right thing.
## Wire Protocol
The communication protocol is binary. This is what the script produces on stdout and expects on stdin.
- 36 bytes UUID of notmuch database
- 4 bytes unsigned int length of JSON-encoded changes
- JSON-encoded changes
- 4 bytes unsigned int length of JSON-encoded files requested hashes for from other side
- JSON-encoded files requested hashes for from other side
- 4 bytes unsigned int length of JSON-encoded hashes to be sent back
- JSON-encoded hashes to be sent back
- 4 bytes unsigned int length of JSON-encoded file names requested from the other side
- JSON-encoded file names requested from the other side
- for each of the files requested by the other side:
- 4 bytes unsigned int length of requested file
- requested file
- if --delete is given:
- remote to local:
- 4 bytes unsigned int length of JSON-encoded IDs in the DB
- JSON-encoded IDs in the DB
- local to remote:
- 4 bytes unsigned int length of JSON-encoded IDs to be deleted
- JSON-encoded IDs to be deleted
- if --mbsync is given:
- remote to local:
- 4 bytes unsigned int length of JSON-encoded stat (name and mtime) of
all .mbsyncstate/.uidvalidity files
- JSON-encoded stat of all .mbsyncstate/.uidvalidity files
- 4 bytes unsigned int length of JSON-encoded files to send from remote to local
- JSON-encoded files to send from remote to local
- for each file to send from remote to local:
- 8 bytes last mtime of requested file
- 4 bytes unsigned int length of requested file
- requested file
- local to remote:
- 4 bytes unsigned int length of JSON-encoded list of files for remote
to send to local
- JSON-encoded list of files for remote to send to local
- 4 bytes unsigned int length of JSON-encoded list of files for local
to send to remote
- JSON-encoded list of files for local to send to remote
- for each file to send from local to remote:
- 8 bytes last mtime of requested file
- 4 bytes unsigned int length of requested file
- requested file
- from remote only: 6 x 4 bytes with number of tag changes, copied/moved files, deleted files, new messages, deleted messages, new files
Raw data
{
"_id": null,
"home_page": null,
"name": "notmuch-sync",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.6",
"maintainer_email": null,
"keywords": null,
"author": null,
"author_email": "Lars Kotthoff <lars@larsko.org>",
"download_url": "https://files.pythonhosted.org/packages/1a/22/c003dd4b5051260058d6af81b696ca810d47d95500a89d7f937eb5165e0f/notmuch_sync-0.0.2.tar.gz",
"platform": null,
"description": "# notmuch-sync\n\n\n\n\n\n\nmbsync-compatible syncing of notmuch databases and mail files.\n\n[PyPI page](https://pypi.org/project/notmuch-sync/)\n\n## Installation and Quickstart\n\nAssumes that you have [notmuch](https://notmuchmail.org) installed and working.\nInstall with e.g. `pip install notmuch-sync`. No configuration is necessary;\neverything is picked up from notmuch. You may however need to install your OS'\npackages for xapian.\n\nBefore you run `notmuch-sync` for the first time, make sure that notmuch is set\nup correctly (in particular with the correct database path). It is not necessary\nto copy mails and tags; this will be done automatically by `notmuch-sync` on\nfirst run if one of the sides is a new, empty notmuch database.\n\nRun as e.g. `notmuch-sync --verbose --delete --remote my.mail.server --user\nuser`. This assumes that you can connect to `my.mail.server` using SSH with user\n`user` and that `notmuch-sync` is in the $PATH of that user on the remote\nmachine. See `notmuch-sync --help` for commandline flags. Notmuch databases need\nto be set up on both sides; notmuch-sync does not run `notmuch new`.\n\nIn a nutshell, here are the steps you would take if you have notmuch set up on\none machine and wish to sync it with another:\n1. Copy your notmuch configuration to the new machine (this may be just `.notmuch-config`).\n2. Adjust the configuration as necessary, in particular any paths.\n3. Run `notmuch new` on the new machine (no need to copy any mail files).\n4. Run `notmuch-sync --verbose --delete --remote other.machine`. Add `--mbsync`\n if you're using mbsync.\n\nIf you're starting with an empty notmuch database on one side, the first sync\nmight take a long time. Subsequent syncs should be much faster, unless there are\na lot of changes.\n\n\n## Commandline Flags\n\n````\nusage: notmuch-sync [-h] [-r REMOTE] [-u USER] [-v] [-q] [-s SSH_CMD] [-m] [-p PATH] [-c REMOTE_CMD] [-d] [-x]\n\noptions:\n -h, --help show this help message and exit\n -r, --remote REMOTE remote host to connect to\n -u, --user USER SSH user to use\n -v, --verbose increases verbosity, up to twice (ignored on remote)\n -q, --quiet do not print any output, overrides --verbose\n -s, --ssh-cmd SSH_CMD\n SSH command to use (default 'ssh -CTaxq')\n -m, --mbsync sync mbsync files (.mbsyncstate, .uidvalidity)\n -p, --path PATH path to notmuch-sync on remote server\n -c, --remote-cmd REMOTE_CMD\n command to run to sync; overrides --remote, --user, --ssh-cmd, --path; mostly used for testing\n -d, --delete sync deleted messages (requires listing all messages in notmuch database, potentially expensive)\n -x, --delete-no-check\n delete missing messages even if they don't have the 'deleted' tag (requires --delete) -- potentially unsafe\n````\n\n\n## Main Features\n\n- sync arbitrary pairs of notmuch databases over SSH or through arbitrary custom\n commands\n- leverage notmuch database revision numbers for efficient changeset\n determination\n- asynchronous IO for efficient data transfer over networks\n- sync state stored as version number and UUID of notmuch database, does not\n depend on size of notmuch database\n- compatible with [mbsync](https://isync.sourceforge.io/mbsync.html) and works\n around some of its quirks (X-TUID...)\n- extensive unit and integration tests, with the entire archive of the\n [notmuch mailing list](https://nmbug.notmuchmail.org/list/) and a real IMAP\n server and mbsync\n\n\n### Sync Procedure\n\nnotmuch-sync uses the revision number of the notmuch database (`lastmod` search\nterm) to record the last sync and efficiently determine what has changed since\nthen. The sync process works as follows:\n- The notmuch database is opened in write mode to lock it.\n- Both sides get the changes since the last sync, or all changes if there has\n been no sync with the database UUID on the other side.\n- Tags are synced on both sides.\n - If a message shows up in the changeset for the other side, its tags are\n applied to the message on this side.\n - If a message shows up in the changesets for both sides, the union of the\n tags of the message from both sides is applied to the message on both sides.\n- Files of existing messages are synced as follows, on both local and remote\n sides:\n - Files missing on this side are determined as the file names the other side\n has, but are missing on this side.\n - We try to find these missing files locally by comparing the SHA256\n digests from the other side with the SHA256 digests for the local files.\n Computing the digest does not consider lines starting with \"X-TUID: \" to\n identify identical files that only differ in the mbsync run (e.g. if\n mbsync was run separately on both sides).\n - Files that are thus identified as the same with different filenames are\n - copied if both filenames are also present on the other side and in the\n other changeset since the last sync,\n - moved from the filename on this side to the filename on the other side if\n they are not in our changeset or the `move_on_change` flag is set,\n - skipped if none of the above applies and the `move_on_change` flag is not\n set.\n The `move_on_change` flag is true on the local machine and false on the\n remote. It is used to disambiguate which changes to adopt and avoids\n creating duplicate messages unnecessarily. This comes up in particular if\n both sides independently run mbsync, which creates the same message with\n different filenames (and different X-TUID headers) and the same UID. Simply\n copying those messages when syncing would create duplicate files, but more\n importantly duplicate UIDs (which mbsync stores in the filenames), which\n would cause an error on the next mbsync run.\n - Duplicate files for the same message that are not present on the other side\n are deleted and removed from the notmuch database. There is a check that\n this does not accidentally remove messages.\n - Any files that are actually missing (don't have files with the same SHA256)\n are transferred between the two sides.\n- The sync is recorded with notmuch database version and UUID.\n- The notmuch database is closed in write mode -- this unlocks it so that any\n other processes trying to access it should only have to wait for a short time.\n- If `--delete` is given, all notmuch message IDs are listed on both sides and\n the messages to be deleted determined by taking the differences between those\n sets. Messages are only deleted if they have the \"deleted\" tag (see the\n \"Deleting Mails\" section for further details).\n- If `--mbsync` is given, sync mbsync state files (`.uidvalidity`,\n `.mbsyncstate`). The files are listed on both sides and ones with later\n modification dates transferred to the other side. This assumes that both\n machines have (at least somewhat) synchronized clocks.\n\n\n### Sync State\n\nThe sync state for a remote host is saved in the `.notmuch` directory of your\nnotmuch mail directory in a file of the form `notmuch-sync-<UUID>` where\n`<UUID>` is the UUID of the database synced with (not the UUID of the local\nnotmuch database). The contents of the file are the revision number of the\nlocal notmuch database after the last tag sync followed by a space and the UUID\nof the local notmuch database.\n\nThis allows for syncs between any number of arbitrary pairs, even if host\nnames/IP addresses change, only the UUIDs of the notmuch databases have to\nremain the same.\n\nRemoving a sync state file starts the sync from scratch the next time\nnotmuch-sync is run. This should generally be safe (i.e. end up with the two\nnotmuch databases synced as you would expect), but will do a lot of unnecessary\nwork and communication.\n\n\n### Differences to [muchsync](https://www.muchsync.org/)\n\n- syncs filenames and mbsync metadata\n- does not rely on shadow copy of notmuch database -- more space efficient and\n no sqlite dependency\n- probably slower and more memory-hungry\n- does not sync notmuch configuration\n- no special handling of \"unread\" tag required as only changes are considered\n- does not run `notmuch new` automatically, neither on the local nor the remote\n side\n- [glorious](https://github.com/larskotthoff/notmuch-sync/blob/main/test/test.py),\n [glorious](https://github.com/larskotthoff/notmuch-sync/blob/main/test/test-integration.py),\n [glorious](https://github.com/larskotthoff/notmuch-sync/blob/main/.github/workflows/notmuch-ml.yml)\n [tests](https://github.com/larskotthoff/notmuch-sync/blob/main/.github/workflows/imap.yml)\n\n\n### mbsync Compatibility\n\nnotmuch-sync syncs mbsync state under the notmuch mail directory, which requires\n`SyncState *` for all channels and synchronized clocks. It should be safe to run\nmbsync on any of the synced copies at any time; messages that are retrieved\nthrough mbsync on multiple copies will be synced automatically by moving files\naccordingly.\n\n\n### Deleting Mails\n\nnotmuch-sync is very careful about deleting mails. While duplicate *files* for\nthe same email are always cleaned up as part of the sync (i.e. if duplicates\nhave been deleted on one side, they will also be deleted on the other side),\n*messages* are never deleted unless the user explicitly requests it. To do this,\nthe `--delete` flag must be given, and even then only messages that have been\ntagged \"deleted\" are actually deleted. To delete messages that do not have the\n\"deleted\" tag, you can specify `--delete-no-check` in addition to `--delete`\n(not recommended, use at your own risk).\n\nIf `--delete` is given, all message IDs in the notmuch database are listed on\nboth sides (this is potentially expensive). Then the difference between those\nlists is taken to determine what messages should be deleted on the local and\nremote sides. If a message ID is slated for deletion but the message does *not*\nhave the \"deleted\" tag (on either side), notmuch-sync assumes that something has\ngone wrong and creates a dummy transaction for the message that changes nothing,\nbut will make it appear in the next changeset. This will cause the message to be\nadded on the side where it's missing the next time sync is run.\n\nThis should work well with workflows where messages that have been tagged\n\"deleted\" are kept for a while and only then actually deleted by removing the\nfiles. Note that if the interval between tagging messages \"deleted\" and actually\ndeleting them is smaller than the interval between syncs (e.g. one side hasn't\nbeen synced in a long time), deleted messages will reappear when synced. This is\nbecause one side will have no record of the \"deleted\" tag and will only see\nmessages not present that are not tagged \"deleted\".\n\n\n## Limitations\n\nThe size limit for most things that are communicated between hosts is $2^{32}$\nbytes, i.e. about 4GB. This includes the size of individual mail files, the\nlength of changesets (message IDs, tags, files, and SHA256 checksums), and the\nlength of all message IDs. This is not a fundamental limitation but simply to\navoid additional communication overhead and should be sufficient for most use\ncases.\n\nThe folder structure under the notmuch mail directory is assumed to be the same\non all copies, in particular this means that the mbsync configuration should be\nthe same as well.\n\nChanges to the notmuch database and mail files while notmuch-sync is running,\ne.g. moving files, will result in error messages. It is safe to simply rerun\nnotmuch-sync when this happens.\n\nRunning `notmuch compact` changes the UUID of the database. This means that\nsubsequent syncs will abort with an error message.\n\nLike muchsync, notmuch-sync uses xapian directly for some operations for\nefficiency reasons. This means in particular that notmuch-sync assumes that\nvalue 1 of a xapian document is the message ID and the term \"Tghost\" is used to\nidentify ghost messages.\n\nnotmuch-sync assumes that the remote command does not produce any output except\nfor the output produced by the remote notmuch-sync. If you're running a wrapper\nscript on the remote or have an SSH banner, make sure to silence/redirect all\nrespective output.\n\nThere are extensive tests, but there is no guarantee that notmuch-sync will\nalways do the right thing.\n\n\n## Wire Protocol\n\nThe communication protocol is binary. This is what the script produces on stdout and expects on stdin.\n\n- 36 bytes UUID of notmuch database\n- 4 bytes unsigned int length of JSON-encoded changes\n- JSON-encoded changes\n- 4 bytes unsigned int length of JSON-encoded files requested hashes for from other side\n- JSON-encoded files requested hashes for from other side\n- 4 bytes unsigned int length of JSON-encoded hashes to be sent back\n- JSON-encoded hashes to be sent back\n- 4 bytes unsigned int length of JSON-encoded file names requested from the other side\n- JSON-encoded file names requested from the other side\n- for each of the files requested by the other side:\n - 4 bytes unsigned int length of requested file\n - requested file\n- if --delete is given:\n - remote to local:\n - 4 bytes unsigned int length of JSON-encoded IDs in the DB\n - JSON-encoded IDs in the DB\n - local to remote:\n - 4 bytes unsigned int length of JSON-encoded IDs to be deleted\n - JSON-encoded IDs to be deleted\n- if --mbsync is given:\n - remote to local:\n - 4 bytes unsigned int length of JSON-encoded stat (name and mtime) of\n all .mbsyncstate/.uidvalidity files\n - JSON-encoded stat of all .mbsyncstate/.uidvalidity files\n - 4 bytes unsigned int length of JSON-encoded files to send from remote to local\n - JSON-encoded files to send from remote to local\n - for each file to send from remote to local:\n - 8 bytes last mtime of requested file\n - 4 bytes unsigned int length of requested file\n - requested file\n - local to remote:\n - 4 bytes unsigned int length of JSON-encoded list of files for remote\n to send to local\n - JSON-encoded list of files for remote to send to local\n - 4 bytes unsigned int length of JSON-encoded list of files for local\n to send to remote\n - JSON-encoded list of files for local to send to remote\n - for each file to send from local to remote:\n - 8 bytes last mtime of requested file\n - 4 bytes unsigned int length of requested file\n - requested file\n- from remote only: 6 x 4 bytes with number of tag changes, copied/moved files, deleted files, new messages, deleted messages, new files\n",
"bugtrack_url": null,
"license": null,
"summary": "Synchronize notmuch email databases and message files between local and remote systems, compatible with mbsync.",
"version": "0.0.2",
"project_urls": {
"Homepage": "https://github.com/larskotthoff/notmuch-sync",
"Issues": "https://github.com/larskotthoff/notmuch-sync/issues"
},
"split_keywords": [],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "cc4e8be2f7fd84c8abacda555c45e8ce9b13d9e7c324c06e102fb9a27e8904b1",
"md5": "fc4d51bf0b5f71ec764b6cc8afb6b6e5",
"sha256": "6de630e815cb79b498eda9ca325c4ca16d81b59438fbc60b5a2d990773dd6446"
},
"downloads": -1,
"filename": "notmuch_sync-0.0.2-py3-none-any.whl",
"has_sig": false,
"md5_digest": "fc4d51bf0b5f71ec764b6cc8afb6b6e5",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.6",
"size": 15347,
"upload_time": "2025-07-25T02:15:42",
"upload_time_iso_8601": "2025-07-25T02:15:42.633907Z",
"url": "https://files.pythonhosted.org/packages/cc/4e/8be2f7fd84c8abacda555c45e8ce9b13d9e7c324c06e102fb9a27e8904b1/notmuch_sync-0.0.2-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "1a22c003dd4b5051260058d6af81b696ca810d47d95500a89d7f937eb5165e0f",
"md5": "d61515aad6738308e0d9125331c3bde4",
"sha256": "0eaa858958b82b025b41697d21422591390ecba8521170d417cd634bfe17c607"
},
"downloads": -1,
"filename": "notmuch_sync-0.0.2.tar.gz",
"has_sig": false,
"md5_digest": "d61515aad6738308e0d9125331c3bde4",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.6",
"size": 14245,
"upload_time": "2025-07-25T02:15:43",
"upload_time_iso_8601": "2025-07-25T02:15:43.806847Z",
"url": "https://files.pythonhosted.org/packages/1a/22/c003dd4b5051260058d6af81b696ca810d47d95500a89d7f937eb5165e0f/notmuch_sync-0.0.2.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-07-25 02:15:43",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "larskotthoff",
"github_project": "notmuch-sync",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"requirements": [
{
"name": "notmuch2",
"specs": []
},
{
"name": "xapian-bindings",
"specs": []
},
{
"name": "pytest",
"specs": []
},
{
"name": "pytest-shell-utilities",
"specs": []
}
],
"lcname": "notmuch-sync"
}