VDIRSYNCER(1)
π VDIRSYNCER(1) β the vdirsyncer manual, but make it make sense β¨
Okay so hi bestie π«Ά this is the manual page for vdirsyncer(1) β like, the whole thing β so grab a snack π and let's get into it.
π NAME π
- π Documentation β
https://vdirsyncer.pimutils.org/en/stable/ - π» Source code β
https://github.com/pimutils/vdirsyncer
Vdirsyncer is a command-line tool for synchronizing calendars and addressbooks between a variety of servers and the local filesystem. The most popular usecase is to synchronize a server with a local folder and use a set of other programs <> to change the local events and contacts. Vdirsyncer can then synchronize those changes back to the server.
But like β and this is the part people sleep on β vdirsyncer is not limited to synchronizing between clients and servers. It can also be used to synchronize calendars and/or addressbooks between two servers directly. Two servers!! Talking to each other!! Through vdirsyncer!! π₯
It aims to be for calendars and contacts what OfflineIMAP (http://offlineimap.org/) is for emails. Periodt.
π¦ WHEN DO I NEED VDIRSYNCER? π¦
πΈ Why not Dropbox + todo.txt?
Projects like todo.txt (http://todotxt.com/) criticize the complexity of modern productivity apps, and that rightfully. So they set out to create a new, super-simple, human-readable format, such that vim suffices for viewing the raw data. However, when they're faced with the question how to synchronize that data across multiple devices, they seemed to have reached the dead end with their novel idea: "Let's just use Dropbox". π
What does file sync software do if both files have changed since the last sync? The answer is to ignore the question, just sync as often as possible, and hope for the best. Because if it comes to a sync conflict, most sync services are not daring to merge files, and create two copies on each computer instead. Merging the two task lists is left to the user. Not me finding out my grocery list has a twin π
A better idea would've been to use git to synchronize the todo.txt file, which is at least able to resolve some basic conflicts.
π Why not file sync (Dropbox, git, ...) + vdir?
Since vdirs <> are just a bunch of files, it is obvious to try file synchronization for synchronizing your data between multiple computers, such as:
- Syncthing β
https://syncthing.net/ - Dropbox β
https://dropbox.com/or one of the gajillion services like it - unison β
https://www.cis.upenn.edu/~bcpierce/unison/ - Just git with a sshd.
The disadvantages of those solutions largely depend on the exact file sync program chosen:
- Like with todo.txt, Dropbox and friends are obviously agnostic/unaware of the files' contents. If a file has changed on both sides, Dropbox just copies both versions to both sides.
- This is a good idea if the user is directly interfacing with the file system and is able to resolve conflicts themselves. Here it might lead to erroneous behavior with e.g.
khal, since there are now two events with the same UID. π - This point doesn't apply to git: It has very good merging capabilities, better than what vdirsyncer currently has.
- This is a good idea if the user is directly interfacing with the file system and is able to resolve conflicts themselves. Here it might lead to erroneous behavior with e.g.
- Such a setup doesn't work at all with smartphones. Vdirsyncer, on the other hand, synchronizes with CardDAV/CalDAV servers, which can be accessed with e.g. DAVxβ΅ β
https://www.davx5.com/β or other apps bundled with smartphones. π±
π INSTALLATION π
π OS/distro packages
The following packages are community-contributed and were up-to-date at the time of writing:
- Arch Linux β
https://archlinux.org/packages/extra/any/vdirsyncer/ - Ubuntu and Debian, x86_64-only β
https://packagecloud.io/pimutils/vdirsyncer(packages also exist in the official repositories but may be out of date) - GNU Guix β
https://packages.guix.gnu.org/packages/vdirsyncer/ - macOS (homebrew) β
https://formulae.brew.sh/formula/vdirsyncer - NetBSD β
https://ftp.netbsd.org/pub/pkgsrc/current/pkgsrc/time/py-vdirsyncer/index.html - OpenBSD β
http://ports.su/productivity/vdirsyncer - Slackware (SlackBuild at Slackbuilds.org) β
https://slackbuilds.org/repository/15.0/network/vdirsyncer/
β οΈ We only support the latest version of vdirsyncer, which is at the time of this writing 0.21.0. Please do not file bugs if you use an older version. Like, be so serious rn π
Some distributions have multiple release channels. Debian and Fedora for example have a "stable" release channel that ships an older version of vdirsyncer. Those versions aren't supported either.
If there is no suitable package for your distribution, you'll need to install vdirsyncer manually. There is an easy command to copy-and-paste for this as well, but you should be aware of its consequences. π
π§ Manual installation
If your distribution doesn't provide a package for vdirsyncer, you still can use Python's package manager "pip". First, you'll have to check that the following things are installed:
- Python 3.9 to 3.14 and pip.
libxmlandlibxsltzlib- Linux or macOS. Windows is not supported, see issue #535 β
https://github.com/pimutils/vdirsyncer/issues/535.
On Linux systems, using the distro's package manager is the best way to do this, for example, using Ubuntu:
sudo apt-get install libxml2 libxslt1.1 zlib1g python3
Then you have several options. The following text applies for most Python software by the way. β¨
π pipx: The clean, easy way
pipx (https://github.com/pipxproject/pipx) is a new package manager for Python-based software that automatically sets up a virtual environment for each program it installs. Please note that installing via pipx will not include manual pages nor systemd services. π¬
pipx will install vdirsyncer into ~/.local/pipx/venvs/vdirsyncer
Assuming that pipx is installed, vdirsyncer can be installed with:
pipx install vdirsyncer
It can later be updated to the latest version with:
pipx upgrade vdirsyncer
And can be uninstalled with:
pipx uninstall vdirsyncer
This last command will remove vdirsyncer and any dependencies installed into the above location. Clean!! π§Ό
π The dirty, easy way
If pipx is not available on your distribution, the easiest way to install vdirsyncer at this point would be to run:
pip install --ignore-installed vdirsyncer
--ignore-installedis to work around Debian's potentially broken packages (see Requests-related ImportErrors β#debian-urllib3).
This method has a major flaw though: Pip doesn't keep track of the files it installs. Vdirsyncer's files would be located somewhere in ~/.local/lib/python*, but you can't possibly know which packages were installed as dependencies of vdirsyncer and which ones were not, should you decide to uninstall it. In other words, using pip that way would pollute your home directory. Not the vibe π«
π The clean, hard way
There is a way to install Python software without scattering stuff across your filesystem: virtualenv β https://virtualenv.readthedocs.io/. There are a lot of resources on how to use it, the simplest possible way would look something like:
virtualenv ~/vdirsyncer_env
~/vdirsyncer_env/bin/pip install vdirsyncer
alias vdirsyncer="~/vdirsyncer_env/bin/vdirsyncer"
You'll have to put the last line into your .bashrc or .bash_profile.
This method has two advantages:
- It separately installs all Python packages into
~/vdirsyncer_env/, without relying on the system packages. This works around OS- or distro-specific issues. π οΈ - You can delete
~/vdirsyncer_env/to uninstall vdirsyncer entirely. Literally just yeet the folder ποΈ
π TUTORIAL π
Okay bestie, before you dive in β pause. Take a breath. Ask yourself the big question: do you actually need vdirsyncer? Because there are genuinely better alternatives out there for particular usecases, and we're not gonna gatekeep that from you. π
Installation
See Installation β it's already up above, you literally just read it. β¨
Configuration
Note: - Theconfig.examplefrom the repository (over athttps://github.com/pimutils/vdirsyncer/blob/main/config.example) has a super terse version of all this, if you want the short version. - In this example we set up contacts synchronization, but calendar sync works basically the same. Just swaptype = "carddav"fortype = "caldav"andfileext = ".vcf"forfileext = ".ics". Easy swap, no cap. - If anything doesn't work like planned, take a look at the Known Problems page. It's giving troubleshooting realness.
So by default, vdirsyncer goes looking for its configuration file in these spots, in order:
- The file that the
VDIRSYNCER_CONFIGenvironment variable points to. ~/.vdirsyncer/config.$XDG_CONFIG_HOME/vdirsyncer/config, which is normally~/.config/vdirsyncer/config. See the XDG-Basedir specification if you wanna get into the weeds:http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html#variables.
Your config file should start with a general section, and the only required parameter in there is status_path. Here's the minimal starter pack:
[general]
status_path = "~/.vdirsyncer/status/"
After the general section? An arbitrary amount of pair and storage sections might come. Go off, add as many as you want. π¦
So here's the tea: in vdirsyncer, synchronization is always done between two storages. Those storages get defined in storage sections, and which pairs of storages should actually be synchronized is defined in pair sections. This whole format is copied from OfflineIMAP, where storages are called repositories and pairs are called accounts β so if you know that one, you already know this one. π«Ά
The following example synchronizes ownCloud's addressbooks to ~/.contacts/:
[pair my_contacts]
a = "my_contacts_local"
b = "my_contacts_remote"
collections = ["from a", "from b"]
[storage my_contacts_local]
type = "filesystem"
path = "~/.contacts/"
fileext = ".vcf"
[storage my_contacts_remote]
type = "carddav"
# We can simplify this URL here as well. In theory it shouldn't matter.
url = "https://owncloud.example.com/remote.php/carddav/"
username = "bob"
password = "asdf"
Note: Config for other servers can be found at Servers. We got you covered. π
After running vdirsyncer discover and vdirsyncer sync, ~/.contacts/ will contain subfolders for each addressbook, which in turn will contain a bunch of .vcf files, and each one of those contains a contact in VCARD format. You can modify their contents, add new ones and delete some [1], and your changes will be synchronized to the CalDAV server after you run vdirsyncer sync again. For further reference, it uses the storages filesystem and carddav.
But heads up β if new collections are created on the server, it will not automatically start synchronizing those [2]. You need to run vdirsyncer discover again to re-fetch this list instead. Annoying? A little. Necessary? Yeah.
[1] You'll want to use a helper program for this. Your future self says thank you.
[2] Because collections are added rarely, and checking for this case before every synchronization isn't worth the overhead. Efficiency icon behaviour, honestly.
β¨ More Configuration β¨
Conflict resolution
Okay so picture this: what if the same item is changed on both sides? What should vdirsyncer do?? Actual crisis. Three options are currently provided:
- vdirsyncer displays an error message (the default);
- vdirsyncer chooses one alternative version over the other;
- vdirsyncer starts a command of your choice that is supposed to merge the two alternative versions.
Options 2 and 3 require adding a "conflict_resolution" parameter to the pair section. Option 2 requires giving either "a wins" or "b wins" as the value to the parameter:
[pair my_contacts]
...
conflict_resolution = "b wins"
Earlier we wrote that b = "my_contacts_remote", so when vdirsyncer encounters the situation where an item changed on both sides, it will simply overwrite the local item with the one from the server. B wins, local loses, we move on. π
Option 3 requires specifying as value of "conflict_resolution" an array starting with "command" and containing paths and arguments to a command. For example:
[pair my_contacts]
...
conflict_resolution = ["command", "vimdiff"]
In this example, vimdiff <a> <b> will be called with <a> and <b> being two temporary files containing the conflicting files. The files need to be exactly the same when the command returns β like, that's the whole deal, no pressure. More arguments can be passed to the command by adding more elements to the array.
See Pair Section for the reference documentation.
Metadata synchronization
Besides items, vdirsyncer can also synchronize metadata β like the addressbook's or calendar's "human-friendly" name (internally called "displayname") or the color associated with a calendar. Cute, right? For the purpose of explaining this feature, let's switch to a different base example. This time we'll synchronize calendars:
[pair my_calendars]
a = "my_calendars_local"
b = "my_calendars_remote"
collections = ["from a", "from b"]
metadata = ["color"]
[storage my_calendars_local]
type = "filesystem"
path = "~/.calendars/"
fileext = ".ics"
[storage my_calendars_remote]
type = "caldav"
url = "https://owncloud.example.com/remote.php/caldav/"
username = "bob"
password = "asdf"
Run vdirsyncer discover for discovery. Then you can use vdirsyncer metasync to synchronize the color property between your local calendars in ~/.calendars/ and your ownCloud. Locally the color is just represented as a file called color within the calendar folder. That's it. That's the whole vibe. π
More information about collections
"Collection" is a collective term for addressbooks and calendars. A Cardav or Caldav server can contains several "collections" which correspond to several addressbooks or calendar. (Grammar? Not the point. The point is collections contain stuff.)
Each collection from a storage has a "collection name", a unique identifier for each collection. In the case of filesystem-storage, this is the name of the directory that represents the collection; in the case of the DAV-storages this is the last segment of the URL. We use this identifier in the collections parameter in the pair-section.
This identifier doesn't change even if you rename your calendar in whatever UI you have, because that only changes the so-called "displayname" property [3]. On some servers (iCloud, Google) this identifier is randomly generated and has no correlation with the displayname you chose. Random UUID energy, we respect it. π
[3] Which you can also synchronize with metasync using metadata = ["displayname"].
There are three collection names that have a special meaning:
"from a","from b": A placeholder for all collections that can be found on side A/B when runningvdirsyncer discover.null: The parameters given to the storage are exact and require no discovery.
The last one requires a bit more explanation. Assume this config which synchronizes two directories of addressbooks:
[pair foobar]
a = "foo"
b = "bar"
collections = ["from a", "from b"]
[storage foo]
type = "filesystem"
fileext = ".vcf"
path = "./contacts_foo/"
[storage bar]
type = "filesystem"
fileext = ".vcf"
path = "./contacts_bar/"
As we saw previously this will synchronize all collections in ./contacts_foo/ with each same-named collection in ./contacts_bar/. If there's a collection that exists on one side but not the other, vdirsyncer will ask whether to create that folder on the other side. Consent-based folder creation, we love to see it. π«Ά
If we set collections = null, ./contacts_foo/ and ./contacts_bar/ are no longer treated as folders with collections, but as collections themselves. This means that ./contacts_foo/ and ./contacts_bar/ will contain .vcf-files, not subfolders that contain .vcf-files.
This is useful in situations where listing all collections fails because your DAV-server doesn't support it, for example. In this case, you can set url of your carddav- or caldav-storage to a URL that points to your CalDAV/CardDAV collection directly.
Note that not all storages support the null-collection β for example google_contacts and google_calendar don't. Sad but true. π
Advanced collection configuration (server-to-server sync)
The examples above are good enough if you want to synchronize a remote server to a previously empty disk. However, even more trickery is required when you have two servers with already existing collections which you want to synchronize. This is where it gets spicy. π₯
The core problem in this situation is that vdirsyncer pairs collections by collection name by default (see definition in previous section β basically a foldername or a remote UUID). When you have two servers, those collection names may not line up as nicely. Suppose you created two calendars "Test", one on a NextCloud server and one on iCloud, using their respective web interfaces. The URLs look something like this:
NextCloud: https://example.com/remote.php/dav/calendars/user/test/
iCloud: https://p-XX.caldav.icloud.com/YYY/calendars/3b4c9995-5c67-4021-9fa0-be4633623e1c
Those are two DAV calendar collections. Their collection names will be test and 3b4c9995-5c67-4021-9fa0-be4633623e1c respectively, so you don't have a single name you can address them both with. Not matching at all. Zero chemistry. π
You will need to manually "pair" (no pun intended) those collections up like this:
[pair doublecloud]
a = "my_nextcloud"
b = "my_icloud"
collections = [["mytest", "test", "3b4c9995-5c67-4021-9fa0-be4633623e1c"]]
mytest gives that combination of calendars a nice name you can use when talking about it, so you would use vdirsyncer sync doublecloud/mytest to say: "Only synchronize these two storages, nothing else that may be configured". Main character pair name, honestly. β
Note: Why not use displaynames? You may wonder why vdirsyncer just couldn't figure this out by itself. After all, you did name both collections "Test" (which is called "the displayname"), so why not pair collections by that value? There are a few problems with this idea: - Two calendars may have the same exact displayname. - A calendar may not have a (non-empty) displayname. - The displayname might change. Either you rename the calendar, or the calendar renames itself because you change a language setting. In the end, that property was never designed to be parsed by machines. It's a vibe, not an identifier. π
π SSL AND CERTIFICATE VALIDATION π
Okay bestie, All SSL configuration is done per-storage. Each storage gets its own little vibe check. π
π Pinning by fingerprint π
To pin the certificate by fingerprint, drop this into your config:
[storage foo]
type = "caldav"
...
verify_fingerprint = "6D:83:EA:32:6C:39:BA:08:ED:EB:C9:BC:BE:12:BB:BF:0F:D9:83:00:CC:89:7E:C7:32:05:94:96:CA:C5:59:5E"
SHA256-Fingerprints must be used β MD5 and SHA-1 are insecure and not supported, no cap. π« When you pin a fingerprint, CA validation is disabled.
You can use the following command for obtaining a SHA256 fingerprint:
echo -n | openssl s_client -connect unterwaditzer.net:443 | openssl x509 -noout -fingerprint -sha256
However, please consider using Let's Encrypt (https://letsencrypt.org/) such that you can forget about all of that. It is easier to deploy a free certificate from them than configuring all of your clients to accept the self-signed certificate. β¨
πΈ Custom root CAs πΈ
To point vdirsyncer to a custom set of root CAs:
[storage foo]
type = "caldav"
...
verify = "/path/to/cert.pem"
Vdirsyncer uses the aiohttp library (https://docs.aiohttp.org/en/stable/index.html), which uses the default ssl.SSLContext (https://docs.python.org/3/library/ssl.html#ssl.SSLContext) by default.
There are cases where certificate validation fails even though you can access the server fine through e.g. your browser. This usually indicates that your installation of python or the aiohttp or library is somehow broken. In such cases, it makes sense to explicitly set verify or verify_fingerprint as shown above. π«Ά
π¦ Client Certificates π¦
Client certificates may be specified with the auth_cert parameter. If the key and certificate are stored in the same file, it may be a string:
[storage foo]
type = "caldav"
...
auth_cert = "/path/to/certificate.pem"
If the key and certificate are separate, a list may be used:
[storage foo]
type = "caldav"
...
auth_cert = ["/path/to/certificate.crt", "/path/to/key.key"]
π STORING PASSWORDS π
Changed in version 0.7.0: Password configuration got completely overhauled. π
Vdirsyncer can fetch passwords from several sources other than the config file. Obsessed.
π Command π
Say you have the following configuration:
[storage foo]
type = "caldav"
url = ...
username = "foo"
password = "bar"
But it bugs you that the password is stored in cleartext in the config file. Mood. You can do this:
[storage foo]
type = "caldav"
url = ...
username = "foo"
password.fetch = ["command", "~/get-password.sh", "more", "args"]
You can fetch the username as well:
[storage foo]
type = "caldav"
url = ...
username.fetch = ["command", "~/get-username.sh"]
password.fetch = ["command", "~/get-password.sh"]
Or really any kind of parameter in a storage section. Iconic.
You can also pass the command as a string to be executed in a shell:
[storage foo]
...
password.fetch = ["shell", "~/.local/bin/get-my-password | head -n1"]
With pass (https://www.passwordstore.org/) for example, you might find yourself writing something like this in your configuration file:
password.fetch = ["command", "pass", "caldav"]
π Accessing the system keyring π
As shown above, you can use the command strategy to fetch your credentials from arbitrary sources. A very common usecase is to fetch your password from the system keyring.
The keyring (https://github.com/jaraco/keyring/) Python package contains a command-line utility for fetching passwords from the OS's password store. Installation:
pip install keyring
Basic usage:
password.fetch = ["command", "keyring", "get", "example.com", "foouser"]
π Password Prompt π
You can also simply prompt for the password:
[storage foo]
type = "caldav"
username = "myusername"
password.fetch = ["prompt", "Password for CalDAV"]
π Environment variable π
To read the password from an environment variable:
[storage foo]
type = "caldav"
username = "myusername"
password.fetch = ["command", "printenv", "DAV_PW"]
This is especially handy if you use the same password multiple times (say, for a CardDAV and a CalDAV storage). On bash, you can read and export the password without printing:
read -s DAV_PW "DAV Password: " && export DAV_PW
ποΈ SYNCING WITH READ-ONLY STORAGES ποΈ
If you want to subscribe to a public, read-only WebCAL (https://en.wikipedia.org/wiki/Webcal) calendar but neither your server nor your calendar apps support that (or support it insufficiently), vdirsyncer can be used to synchronize such a public calendar A with a new calendar B of your own and keep B updated. Literally main character energy for your holidays. ποΈβ¨
β Step 1: Create the target calendar β
First you need to create the calendar you want to sync the WebCAL-calendar with. Most servers offer a web interface for this. You then need to note the CalDAV URL of your calendar. Note that this URL should directly point to the calendar you just created, which means you would have one such URL for each calendar you have. π―
π¦ Step 2: Creating the config π¦
Paste this into your vdirsyncer config:
[pair holidays]
a = "holidays_public"
b = "holidays_private"
collections = null
[storage holidays_public]
type = "http"
# The URL to your iCalendar file.
url = "..."
[storage holidays_private]
type = "caldav"
# The direct URL to your calendar.
url = "..."
# The credentials to your CalDAV server
username = "..."
password = "..."
Then run vdirsyncer discover holidays and vdirsyncer sync holidays, and your previously created calendar should be filled with events. Slay. π
πΈ Step 3: The partial_sync parameter πΈ
Added in version 0.14.
You may get into a situation where you want to hide or modify some events from your holidays calendar. If you try to do that at this point, you'll notice that vdirsyncer will revert any changes you've made after a few times of running sync. This is because vdirsyncer wants to keep everything in sync, and it can't synchronize changes to the public holidays-calendar because it doesn't have the rights to do so. Not it being powerless, just respectful. π
For such purposes you can set the partial_sync parameter to ignore:
[pair holidays]
a = "holidays_public"
b = "holidays_private"
collections = null
partial_sync = ignore
See the config docs (#partial-sync-def) for more information.
π FULL CONFIGURATION MANUAL π
Vdirsyncer uses an ini-like format for storing its configuration. All values are JSON, invalid JSON will get interpreted as string:
x = "foo" # String
x = foo # Shorthand for same string
x = 42 # Integer
x = ["a", "b", "c"] # List of strings
x = true # Boolean
x = false
x = null # Also known as None
π§ General Section π§
[general]
status_path = ...
status_path: A directory where vdirsyncer will store some additional data for the next sync.
The data is needed to determine whether a new item means it has been added on one side or deleted on the other. Relative paths will be interpreted as relative to the configuration file's directory.
See A simple synchronization algorithm (https://unterwaditzer.net/2016/sync-algorithm.html) for what exactly is in there.
π« Pair Section π«
[pair pair_name]
a = ...
b = ...
#collections = null
#conflict_resolution = null
- Pair names can consist of any alphanumeric characters and the underscore. π
aandbreference the storages to sync by their names.collections: A list of collections to synchronize whenvdirsyncer syncis executed. See also More information about collections (#collections-tutorial).
The special values "from a" and "from b", tell vdirsyncer to try autodiscovery on a specific storage. It means all the collections on side A / side B.
If the collection you want to sync doesn't have the same name on each side, you may also use a value of the form ["config_name", "name_a", "name_b"]. This will synchronize the collection name_a on side A with the collection name_b on side B. The config_name will be used for representation in CLI arguments and logging.
Examples:
collections = ["from b", "foo", "bar"]makes vdirsyncer synchronize all the collections from side B, and also the collections named"foo"and"bar".collections = ["from b", "from a"]makes vdirsyncer synchronize all existing collections on either side.collections = [["bar", "bar_a", "bar_b"], "foo"]makes vdirsyncer synchronizebar_afrom side A withbar_bfrom side B, and also synchronizefooon both sides with each other.
conflict_resolution: Optional, define how conflicts should be handled. A conflict occurs when one item (event, task) changed on both sides since the last sync. See also Conflict resolution (#conflict-resolution-tutorial).
Valid values are:
null, where an error is shown and no changes are done."a wins"and"b wins", where the whole item is taken from one side.["command", "vimdiff"]:vimdiff <a> <b>will be called where<a>and<b>are temporary files that contain the item of each side respectively. The files need to be exactly the same when the command returns.vimdiffcan be replaced with any other command. For example, in POSIX["command", "cp"]is equivalent to"a wins".- Additional list items will be forwarded as arguments. For example,
["command", "vimdiff", "--noplugin"]runsvimdiff --noplugin.
Vdirsyncer never attempts to "automatically merge" the two items.
partial_sync: Assume A is read-only, B not. If you change items on B, vdirsyncer can't sync the changes to A. What should happen instead?error: An error is shown.ignore: The change is ignored. However: Events deleted in B still reappear if they're updated in A.revert(default): The change is reverted on next sync.
See also Syncing with read-only storages (#partial-sync-tutorial).
metadata: Metadata keys that should be synchronized whenvdirsyncer metasyncis executed. Example:
metadata = ["color", "displayname", "description", "order"]
This synchronizes the following properties:
color:http://apple.com/ns/ical/:calendar-colordisplayname:DAV:displaynamedescription:CalDAV:calendar-descriptionandCardDAV:addressbook-descriptionorder:http://apple.com/ns/ical/:calendar-order
The conflict_resolution parameter applies for these properties too.
implicit: Opt into implicitly creating collections. Example:
implicit = "create"
When it's set to "create", any missing collections just get made automatically on both sides during sync β no prompting, no "hey bestie do you want this" moment. Lowkey simplifies everything when all your collections are meant to be synced bidirectionally. Slay. β¨
ποΈ Storage Section
[storage storage_name]
type = ...
- Storage names are chill β any alphanumeric characters plus the underscore, that's it.
typetells vdirsyncer which kind of storage you're defining. Peep the Supported Storages section below πread_onlydecides whether this storage gets treated as read-only. Set it totrueand sync will straight up discard any changes made on the other side. Set it tofalseand you get normal 2-way synchronization.- Any other parameters? Those get passed straight on to the storage class. iykyk.
π¦ Supported Storages
ποΈ CalDAV and CardDAV
Note: pls also look at Servers <#supported-servers>, because some servers are just not it and may not work well. π
caldav β CalDAV
[storage example_for_caldav]
type = "caldav"
#start_date = null
#end_date = null
#item_types = []
url = "..."
#username = ""
#password = ""
#verify = /path/to/custom_ca.pem
#auth = null
#useragent = "vdirsyncer/0.16.4"
#verify_fingerprint = null
#auth_cert = null
You can set a timerange to sync with start_date and end_date. Inside those params you can literally use any Python expression that returns a valid datetime.datetime object. So like, this one syncs from one year in the past to one year in the future:
start_date = "datetime.now() - timedelta(days=365)"
end_date = "datetime.now() + timedelta(days=365)"
Either you specify both, or neither β no in-between bestie. Default is to sync everything. π«Ά
You can also set item_types to restrict what kind of items you actually want. So if you only want events and absolutely do not want tasks downloaded off the server, go item_types = ["VEVENT"]. And if you want events and tasks but there's some VJOURNAL items on the server you're not vibing with, use item_types = ["VEVENT", "VTODO"]. π
Parameters
start_dateβ Start date of the timerange to show. Default is-inf.end_dateβ End date of the timerange to show. Default is+inf.item_typesβ Kind of items to show. The default β the empty list β means show all. Heads up: this depends on the particular features of your server, and the results aren't validated.urlβ Base URL, or a URL to a calendar.usernameβ Username for authentication.passwordβ Password for authentication.verifyβ Optional. Local path to a self-signed SSL certificate. See SSL and certificate validation <#ssl-tutorial> for the deets.verify_fingerprintβ Optional. SHA256 fingerprint of the expected server certificate. Again, SSL and certificate validation <#ssl-tutorial> has you covered.authβ Optional. Eitherbasic,digestorguess. The default is preemptive Basic auth β meaning it sends your credentials even if the server didn't ask for them. That's lowkey a flex because it saves you an extra roundtrip per request. But if it causes issues with your server, consider settingguess.auth_certβ Optional. Either a path to a certificate with a client certificate and the key, or a list of paths to the files with them.useragentβ Default isvdirsyncer.
carddav β CardDAV
[storage example_for_carddav]
type = "carddav"
url = "..."
#username = ""
#password = ""
#verify = /path/to/custom_ca.pem
#auth = null
#useragent = "vdirsyncer/0.16.4"
#verify_fingerprint = null
#auth_cert = null
#use_vcard_4 = false
Parameters
urlβ Base URL, or a URL to an addressbook.usernameβ Username for authentication.passwordβ Password for authentication.verifyβ Optional. Local path to a self-signed SSL certificate. See SSL and certificate validation <#ssl-tutorial> for more.verify_fingerprintβ Optional. SHA256 fingerprint of the expected server certificate. See SSL and certificate validation <#ssl-tutorial> for more.authβ Optional. Eitherbasic,digestorguess. Default is preemptive Basic auth, sending credentials even when the server didn't request them β saves you an additional roundtrip per request. If that causes issues with your server, consider settingguess.auth_certβ Optional. Either a path to a certificate with a client certificate and the key, or a list of paths to the files with them.useragentβ Default isvdirsyncer.use_vcard_4β Whether the server uses vCard 4.0.
π Google
vdirsyncer does support syncing with Google calendars, but with one restriction: VTODO files are rejected by the server. Not us, them. π
Syncing with Google contacts is honestly less reliable because Google's CardDAV API is just... neglectful. Their CardDAV implementation is allegedly a disaster in terms of data safety. See this blog post <https://evertpot.com/google-carddav-issues/> for the details. Always back up your data. fr fr, this is not a drill. π¨
Another caveat: Google group labels are not synced with vCard's CATEGORIES <https://www.rfc-editor.org/rfc/rfc6350#section-6.7.1> property (also see issue #814 <https://github.com/pimutils/vdirsyncer/issues/814> and upstream issue #36761530 <https://issuetracker.google.com/issues/36761530> for reference), and the BDAY <https://www.rfc-editor.org/rfc/rfc6350#section-6.2.5> property is not synced when only partial date information is present (like when the year is missing).
On first run you'll be asked to authorize the application for access to your Google account. π«
To use this storage type you gotta install some extra dependencies:
pip install vdirsyncer[google]
Also you need to register vdirsyncer as an application yourself to get client_id and client_secret, because hardcoding those into opensource software is against Google's Terms of Service [googleterms] <#googleterms>:
- Go to the Google API Manager <https://console.developers.google.com>
- Create a new project under any name.
- Within that project, enable the
"CalDAV"and"CardDAV"APIs (not the Calendar and Contacts APIs β those are different and won't work). There should be a search box where you can just enter those terms. - In the sidebar, select
"Credentials", then"Create Credentials"and create a new"OAuth Client ID".
You'll be prompted to create a OAuth consent screen first. Fill out that form however you like.
After setting up the consent screen, finish creating the new "OAuth Client ID". The correct application type is "Desktop application".
- Finally you should have a Client ID and a Client secret. Provide these in your storage config.
The token_file parameter should be a path to a file where vdirsyncer can later store authentication-related data. You do not need to create the file yourself or write anything into it. π
[googleterms]
See ToS <https://developers.google.com/terms/?hl=th>, section "Confidential Matters".
Note: you need to configure which calendars Google should offer vdirsyncer using a secret settings page <https://calendar.google.com/calendar/syncselect>. Yes, secret. Very main character of them. π
google_calendar β Google calendar
[storage example_for_google_calendar]
type = "google_calendar"
token_file = "..."
client_id = "..."
client_secret = "..."
#start_date = null
#end_date = null
#item_types = []
For the item_types and timerange parameters, pls refer to caldav above βοΈ
Parameters
token_fileβ A filepath where access tokens are stored.client_id/client_secretβ OAuth credentials, obtained from the Google API Manager.
google_contacts β Google contacts
[storage example_for_google_contacts]
type = "google_contacts"
token_file = "..."
client_id = "..."
client_secret = "..."
Parameters
token_fileβ A filepath where access tokens are stored.client_id/client_secretβ OAuth credentials, obtained from the Google API Manager.
The current flow is not ideal, but Google deprecated the previous APIs used for this without providing a suitable replacement. See issue #975 <https://github.com/pimutils/vdirsyncer/issues/975> for the discussion on the topic. π
π Local
filesystem
Saves each item in its own file, given a directory.
[storage example_for_filesystem]
type = "filesystem"
path = "..."
fileext = "..."
#encoding = "utf-8"
#post_hook = null
#pre_deletion_hook = null
#fileignoreext = ".tmp"
Can be used with khal <http://lostpackets.de/khal/>. See The Vdir Storage Format <> for a more formal description of the format. π
Directories with a leading dot are ignored β this makes using stuff like version control easier. Cute, right? π¦
Parameters
pathβ Absolute path to a vdir/collection. If this is used in combination with thecollectionsparameter in a pair-section, this should point to a directory of vdirs instead.fileextβ the file extension to use (like.txt). It's part of thehref, so if you change the file extension after a sync, it'll trigger a re-download of everything (but should not cause data-loss of any kind, promise). To be compatible with the vset format you have to use either.vcfor.ics. Also heads up: metasync won't work if you use an empty string here.encodingβ file encoding for items, both the content and the filename.post_hookβ a command to call for each item creation and modification. The command gets called with the path of the new/updated file.pre_deletion_hookβ a command to call for each item deletion. The command gets called with the path of the deleted file.fileeignoreextβ the file extention to ignore. It's only useful iffileextis set to the empty string. The default is.tmp. (yes, the key really is spelled like that, don't come for me π )
πΈ singlefile
Save data in a single local .vcf or .ics file.
The storage basically guesses how items should be joined in the file.
Added in version 0.1.6.
β οΈ Note: this storage is very slow, and that is unlikely to change. You should consider using filesystem if it fits your usecase. Like, seriously. It's giving "technically works" energy.
Parameters
pathβ the filepath to the file to be written to. If collections are used, this should contain%sas a placeholder for the collection name.encodingβ which encoding the file should use. Defaults toUTF-8.
Example for syncing with caldav:
[pair my_calendar]
a = my_calendar_local
b = my_calendar_remote
collections = ["from a", "from b"]
[storage my_calendar_local]
type = "singlefile"
path = ~/.calendars/%s.ics
[storage my_calendar_remote]
type = "caldav"
url = https://caldav.example.org/
#username =
#password =
Example for syncing with caldav using a null collection:
[pair my_calendar]
a = my_calendar_local
b = my_calendar_remote
[storage my_calendar_local]
type = "singlefile"
path = ~/my_calendar.ics
[storage my_calendar_remote]
type = "caldav"
url = https://caldav.example.org/username/my_calendar/
#username =
#password =
π Read-only storages
These storages don't support writing of their items, so consequently read_only is set to true by default. Changing read_only to false on them leads to an error. Not a warning, not a "hmm", an error. Bestie, don't try it.
π‘ http
Use a simple .ics file (or similar) from the web. webcal://-calendars are supposed to be used with this, but you have to replace webcal:// with http://, or better, https://.
[pair holidays]
a = holidays_local
b = holidays_remote
collections = null
[storage holidays_local]
type = "filesystem"
path = ~/.config/vdir/calendars/holidays/
fileext = .ics
[storage holidays_remote]
type = "http"
url = https://example.com/holidays_from_hicksville.ics
#filter_hook = null
Too many WebCAL providers generate UIDs of all VEVENT-components on-the-fly, i.e. all UIDs change every time the calendar is downloaded. This leads many synchronization programs to believe that all events have been deleted and new ones created, and accordingly causes a lot of unnecessary uploads and deletions on the other side. Vdirsyncer completely ignores UIDs coming from http and will replace them with a hash of the normalized item content. Iconic behaviour honestly, it's protecting you from chaos π«Ά
Parameters
urlβ URL to the.icsfile.usernameβ username for authentication.passwordβ password for authentication.verifyβ optional. Local path to a self-signed SSL certificate. See SSL and certificate validation for more information.verify_fingerprintβ optional. SHA256 fingerprint of the expected server certificate. See SSL and certificate validation for more information.authβ optional. Eitherbasic,digestorguess. The default is preemptive Basic auth, sending credentials even if server didn't request them. This saves from an additional roundtrip per request. Consider settingguessif this causes issues with your server.auth_certβ optional. Either a path to a certificate with a client certificate and the key or a list of paths to the files with them.useragentβ defaultvdirsyncer.filter_hookβ optional. A filter command to call for each fetched item, passed in raw form to stdin and returned via stdout. If nothing is returned by the filter command, the item is skipped. This can be used to alter fields as needed when dealing with providers generating malformed events.
π OTHER TUTORIALS
The following section contains tutorials not explicitly about any particular core function of vdirsyncer. They usually show how to integrate vdirsyncer with third-party software. Because of that, it may be that the information regarding that other software only applies to specific versions of them. iykyk β versions drift, tutorials age π
π Note: Please contribute your own tutorials too! Pages are often only stubs and are lacking full examples. Your fave could be the one someone else needs fr fr.
π§ Client applications
π¦ Vdirsyncer with Claws Mail
First of all, Claws-Mail only supports read-only functions for vCards. It can only read contacts, but there's no editor. So, vibes only: read, no write.
πΈ Preparation
We need to install vdirsyncer, for that look here. Then we need to create some folders:
mkdir ~/.vdirsyncer
mkdir ~/.contacts
π Configuration
Now we create the configuration for vdirsyncer. Open ~/.vdirsyncer/config with a text editor. The config should look like this:
[general]
status_path = "~/.vdirsyncer/status/"
[storage local]
type = "singlefile"
path = "~/.contacts/%s.vcf"
[storage online]
type = "carddav"
url = "CARDDAV_LINK"
username = "USERNAME"
password = "PASSWORD"
read_only = true
[pair contacts]
a = "local"
b = "online"
collections = ["from a", "from b"]
conflict_resolution = "b wins"
- In the
generalsection, we define the status folder path, for discovered collections and generally stuff that needs to persist between syncs. - In the
localsection we define that all contacts should be sync in a single file and the path for the contacts. - In the
onlinesection you must change theurl,usernameandpasswordto your setup. We also set the storage to read-only such that no changes get synchronized back. Claws-Mail should not be able to do any changes anyway, but this is one extra safety step in case files get corrupted or vdirsyncer behaves erratically. You can leave that part out if you want to be able to edit those files locally. - In the last section we configure that online contacts win in a conflict situation. Configure this part however you like. A correct value depends on which side is most likely to be up-to-date.
β¨ Sync
Now we discover and sync our contacts:
vdirsyncer discover contacts
vdirsyncer sync contacts
π Claws Mail
Open Claws-Mail. Go to Tools => Addressbook.
Click on Addressbook => New vCard. Choose a name for the book.
Then search for the for the vCard in the folder ~/.contacts/. Click ok, and you we will see your contacts.
π Note: Claws-Mail shows only contacts that have a mail address. The rest are just, like, invisible. Not ghosting you on purpose.
β Crontab
On the end we create a crontab, so that vdirsyncer syncs automatically every 30 minutes our contacts:
crontab -e
On the end of that file enter this line:
*/30 * * * * /usr/local/bin/vdirsyncer sync > /dev/null
And you're done! π
π Running as a systemd.timer
vdirsyncer includes unit files to run at an interval (by default every 15Β±5 minutes).
β οΈ Note: These are not installed when installing viapip, only via distribution packages. If you installed viapip, or your distribution doesn't ship systemd unit files, you'll need to downloadvdirsyncer.serviceandvdirsyncer.timerinto either/etc/systemd/user/or~/.local/share/systemd/user.
The files live at:
https://raw.githubusercontent.com/pimutils/vdirsyncer/main/contrib/vdirsyncer.service
https://raw.githubusercontent.com/pimutils/vdirsyncer/main/contrib/vdirsyncer.timer
π₯ Activation
To activate the timer, just run systemctl --user enable vdirsyncer.timer. To see logs of previous runs, use journalctl --user -u vdirsyncer.
π Configuration
It's quite possible that the default "every fifteen minutes" interval isn't to your liking. No default will suit everybody, but this is configurable by simply running:
systemctl --user edit vdirsyncer.timer
This will open a blank editor, where you can override the timer by including:
OnBootSec=5m # This is how long after boot the first run takes place.
OnUnitActiveSec=15m # This is how often subsequent runs take place.
π Todoman
The iCalendar format also supports saving tasks in form of VTODO-entries, with the same file extension as normal events: .ics. Many CalDAV servers support synchronizing tasks, vdirsyncer does too.
todoman (http://todoman.readthedocs.io/) is a CLI task manager supporting vdir. Its interface is similar to the ones of Taskwarrior or the todo.txt CLI app. You can use filesystem with it.
π§ Setting up vdirsyncer
For this tutorial we will use NextCloud.
Assuming a config like this:
[general]
status_path = "~/.vdirsyncer/status/"
[pair calendars]
conflict_resolution = "b wins"
a = "calendars_local"
b = "calendars_dav"
collections = ["from b"]
metadata = ["color", "displayname"]
[storage calendars_local]
type = "filesystem"
path = "~/.calendars/"
fileext = ".ics"
β¨ Setting up todoman β¨
Okay so for todoman, you drop this into ~/.config/todoman/config.py:
path = "~/.calendars/*"
That glob pattern (iykyk β it's the [wikipedia glob thing](https://en.wikipedia.org/wiki/Glob_(programming))) in path matches all the subfolders inside ~/.calendars/, which is literally exactly the tasklists we want, no cap. Now you can use todoman the way its docs say and just run vdirsyncer sync to push all your changes up to NextCloud. Slay.
π¦ Other clients π¦
These client applications also sync over CalDAV β bestie, they ate:
- The Tasks-app found on iOS
- OpenTasks for Android β https://github.com/dmfs/opentasks
- The Tasks-app for NextCloud's web UI β https://apps.nextcloud.com/apps/tasks
And further applications (these ones have missing pages, sadly):
- khal β http://lostpackets.de/khal/ β a CLI calendar app that supports vdir. You can use filesystem with it.
- Lots of graphical calendar apps like dayplanner (http://www.day-planner.org/), Orage (https://gitlab.xfce.org/apps/orage), or rainlendar (http://www.rainlendar.net/) save a whole calendar into a single
.icsfile. Use singlefile with those. - khard β https://github.com/scheibler/khard/ β a commandline addressbook that supports vdir. Use filesystem with it.
- contactquery.c β https://github.com/t-8ch/snippets/blob/master/contactquery.c β a tiny program explicitly written for querying vdirs from mutt.
- mates β https://github.com/pimutils/mates.rs β a commandline addressbook supporting vdir.
- vdirel β https://github.com/DamienCassou/vdirel β access vdir contacts from Emacs.
π Servers π
Baikal
Vdirsyncer is continuously tested against the latest version of Baikal β http://sabre.io/baikal/.
- Baikal up to
0.2.7also uses an old version of SabreDAV, with the same issue as ownCloud β see issue #160 (https://github.com/pimutils/vdirsyncer/issues/160). That issue is fixed in later versions.
DavMail (Exchange, Outlook)
DavMail (http://davmail.sourceforge.net/) is a proxy program that lets you use Card- and CalDAV clients with Outlook. Which means yes, you can use vdirsyncer with Outlook. Iconic.
Real talk though: in practice your success with DavMail may wildly vary. Depending on your Exchange server you might get hit with weird errors of all sorts (including data-loss π). So make absolutely sure you're on the latest DavMail:
[storage outlook]
type = "caldav"
url = "http://localhost:1080/users/user@example.com/calendar/"
username = "user@example.com"
password = "..."
- Older versions of DavMail handle URLs case-insensitively. See issue #144 (https://github.com/pimutils/vdirsyncer/issues/144).
- DavMail handles malformed data on the Exchange server very poorly. In those cases the Calendar Checking Tool for Outlook (https://www.microsoft.com/en-us/download/details.aspx?id=28786) might help.
- In some cases, you may see errors about duplicate events. It might look something like this:
error: my_calendar/calendar: Storage "my_calendar_remote/calendar" contains multiple items with the same UID or even content. Vdirsyncer will now abort the synchronization of this collection, because the fix for this is not clear; It could be the result of a badly behaving server. You can try running:
error:
error: vdirsyncer repair my_calendar_remote/calendar
error:
error: But make sure to have a backup of your data in some form. The offending hrefs are:
[...]
To fix it, you can try the Remove-DuplicateAppointments.ps1 PowerShell script (https://blogs.msdn.microsoft.com/emeamsgdev/2015/02/12/powershell-remove-duplicate-calendar-appointments/), which Microsoft came up with to remove duplicates.
FastMail
Vdirsyncer is continuously tested against FastMail (https://www.fastmail.com/), and shoutout to them for providing a free account for exactly this purpose. There are no known issues with it. FastMail's support pages (https://www.fastmail.com/help/technical/servernamesandports.html) give you the settings to use:
[storage cal]
type = "caldav"
url = "https://caldav.fastmail.com/"
username = "..."
password = "..."
[storage card]
type = "carddav"
url = "https://carddav.fastmail.com/"
username = "..."
password = "..."
Using vdirsyncer with Google Calendar is possible as of 0.10, but it is not tested frequently. You can use google_contacts and google_calendar.
For more info see issue #202 (https://github.com/pimutils/vdirsyncer/issues/202) and issue #8 (https://github.com/pimutils/vdirsyncer/issues/8).
iCloud
Vdirsyncer is regularly tested against iCloud (https://www.icloud.com/).
[storage cal]
type = "caldav"
url = "https://caldav.icloud.com/"
username = "..."
password = "..."
[storage card]
type = "carddav"
url = "https://contacts.icloud.com/"
username = "..."
password = "..."
Problems (ugh, I know):
- Vdirsyncer can't do two-factor auth with iCloud (there doesn't seem to be a way to do two-factor auth over the DAV APIs). You'll need app-specific passwords instead β https://support.apple.com/en-us/HT204397.
- iCloud has a few special requirements when creating collections. In principle vdirsyncer can do it, but it's recommended to create them from an Apple client (or the iCloud web interface).
- iCloud requires a minimum length of collection names.
- Calendars created by vdirsyncer cannot be used as tasklists.
nextCloud
Vdirsyncer is continuously tested against the latest version of nextCloud (https://nextcloud.com/):
[storage cal]
type = "caldav"
url = "https://nextcloud.example.com/"
username = "..."
password = "..."
[storage card]
type = "carddav"
url = "https://nextcloud.example.com/"
- WebCAL-subscriptions can't be discovered by vdirsyncer. See this relevant issue: https://github.com/nextcloud/calendar/issues/63.
ownCloud
Vdirsyncer is continuously tested against the latest version of ownCloud (https://owncloud.org/):
[storage cal]
type = "caldav"
url = "https://example.com/remote.php/dav/"
username = ...
password = ...
[storage card]
type = "carddav"
url = "https://example.com/remote.php/dav/"
username = ...
password = ...
- Versions older than
7.0.0: ownCloud uses SabreDAV, which had problems detecting collisions and race-conditions. The problems were reported and are fixed in SabreDAV's repo, and the corresponding fix is also in ownCloud since7.0.0. See issue #16 (https://github.com/pimutils/vdirsyncer/issues/16) for more.
Radicale
Radicale (http://radicale.org/) is a very lightweight server, but ngl it intentionally doesn't implement the CalDAV and CardDAV standards completely, which might lead to issues even with very well-written clients. And apart from its non-conformity with the standards, there are multiple other problems with its code quality and the way it's maintained. Consider using e.g. Xandikos instead, fr.
That said, vdirsyncer is continuously tested against the git version and the latest PyPI release of Radicale.
- Vdirsyncer can't create collections on Radicale.
- Radicale doesn't support time ranges in the calendar-query of CalDAV (https://github.com/Kozea/Radicale/issues/146), so setting
start_dateandend_datefor caldav will have no or unpredicted consequences. π - Versions of Radicale older than
0.9b1choke on RFC-conform queries for all items of a collection (https://github.com/Kozea/Radicale/issues/143).
You have to set item_types = ["VTODO", "VEVENT"] in caldav for vdirsyncer to work with those versions.
Xandikos
Xandikos (https://github.com/jelmer/xandikos) is a lightweight yet complete CalDAV and CardDAV server, backed by git. Obsessed. Vdirsyncer is continuously tested against its latest version.
After running ./bin/xandikos --defaults -d $HOME/dav, you should be able to point vdirsyncer against the root of Xandikos like this:
[storage cal]
type = "caldav"
url = "https://xandikos.example.com/"
username = "..."
password = "..."
[storage card]
type = "carddav"
url = "https://xandikos.example.com/"
username = "..."
password = "..."
π₯ KNOWN PROBLEMS π₯
For any unanswered questions or problems, see Support and Contact.
Requests-related ImportErrors
ImportError: No module named packages.urllib3.poolmanager
ImportError: cannot import name iter_field_objects
Debian β and nowadays even other distros β make modifications to the requests package that don't play well with packages assuming a normal requests. It's giving stubbornness on both sides, honestly.
See issue #82 (https://github.com/pimutils/vdirsyncer/issues/82) and issue #140 (https://github.com/pimutils/vdirsyncer/issues/140) for past discussions. You have exactly one option to work around this, and that's to install vdirsyncer in a virtual environment β see Manual installation. π«Ά
π CONTRIBUTING TO THIS PROJECT
Note: - bestie, if you have questions or support requests, pls readSupport and Contact <>first, ok? π - everyone participating has to follow the pimutils Code of Conduct β that'shttp://pimutils.org/coc, no exceptions, periodt. π«Ά
π The issue tracker
We organize bug reports and feature requests with GitHub issues over at https://github.com/pimutils/vdirsyncer/issues. That's the spot. β¨
And these labels https://github.com/pimutils/vdirsyncer/labels are the ones you actually care about:
- "Planning" β for issues that are still undecided, but where at least some discussion already exists. It's giving "we're thinking about it" energy. π€
- "Blocked" β issues that literally can't be worked on right now because some other unsolved problem exists. That other problem could be a bug in some software dependency, for instance. π
- "Ready" β contains issues that are ready to work on. Go go go. π₯
If you just want to get started with contributing, the "ready" issues are an option. Issues that are still in "Planning" are also an option, but they require more upfront thinking and may turn out to be impossible to solve, or at least harder than anticipated. On the flip side those tend to be the more interesting issues as well, depending on how one looks at it. π
All of those labels are also available as a kanban board on waffle.io at https://waffle.io/pimutils/vdirsyncer. It is really just an alternative overview over all issues, but it might be easier to comprehend. π¦
Feel free to contact me or comment on the relevant issues for further information. π
πͺ² Reporting bugs
- Make sure your problem isn't already listed in
Known Problems <>. Like, please check first, ily. π - Make sure you have the absolutely latest version of vdirsyncer. For users of some Linux distributions such as Debian or Fedora this may not be the version that your distro offers. In those cases please file a bug against the distro package, not against upstream vdirsyncer. Read the room bestie. π
- Use
--verbosity=DEBUGwhen including output from vdirsyncer. Yes, that exact flag. π
π‘ Suggesting features
If you're suggesting a feature, keep in mind that vdirsyncer tries not to be a full calendar or contacts client, but rather just the piece of software that synchronizes all the data. It knows its lane and it slays in it. π
Take a look at the documentation for software working with vdirsyncer <> too! π
π Submitting patches, pull requests
- Discuss everything in the issue tracker first (or contact me somehow else) before implementing it. Fr fr, talk to us first. π¬
- Make sure the tests pass. See below for running them. β
- But not because you wrote too few tests. π
- Add yourself to
AUTHORS.rst, and add a note toCHANGELOG.rsttoo. Get that credit, bestie, you earned it. π
π§ͺ Running tests, how to set up your development environment
For many patches, it might suffice to just let CI run the tests. However, CI is slow, so you might want to run them locally too. For this, set up a virtualenv (http://virtualenv.readthedocs.io/) and run this inside of it:
# Install development dependencies, including:
# - vdirsyncer from the repo into the virtualenv
# - style checks and formatting (ruff)
make install-dev
# Install git commit hook for some extra linting and checking
pre-commit install
Then you can run:
pytest # The normal testsuite
pre-commit run --all # Run all linters (which also run via pre-commit)
make -C docs html # Build the HTML docs, output is at docs/_build/html/
make -C docs linkcheck # Check docs for any broken links
The Makefile has a lot of options that allow you to control which tests are run, and which servers are tested. Take a look at its code where they are all initialized and documented. It's giving very much "read the source, bestie". π§
To tests against a specific DAV server, use DAV_SERVER:
make DAV_SERVER=xandikos test
The server will be initialised in a docker container and terminated at the end of the test suite. Containerized and clean, we love to see it. π³β¨
If you have any questions, feel free to open issues about it. π«Ά
ποΈ Structure of the testsuite
Within tests/, there are three main folders:
systemcontains system- and also integration tests. A rough rule is: If the test is using temporary files, put it here. πunit, where each testcase tests a single class or function. π―storageruns a generic storage testsuite against all storages. πΎ
The reason for this separation is: We are planning to generate separate coverage reports for each of those testsuites. Ideally unit would generate palatable coverage of the entire codebase on its own, and the combination of system and storage as well. π
ποΈ THE VDIR STORAGE FORMAT
This document describes a standard for storing calendars and contacts on a filesystem, with the main goal of being easy to implement. Simple > complicated, always. β¨
Vdirsyncer synchronizes to vdirs via filesystem #storage-filesystem. Each vdir (basically just a directory with some files in it) represents a calendar or addressbook. That's it, that's the whole vibe. π
π± Basic Structure
The main folder (root) contains an arbitrary number of subfolders (collections), which contain only files (items). Synonyms for "collection" may be "addressbook" or "calendar". Same thing, different name, iykyk. π¦
An item is:
- A vCard (
https://tools.ietf.org/html/rfc6350) file, in which case the file extension must be.vcf, or - An iCalendar (
https://tools.ietf.org/html/rfc5545) file, in which case the file extension must be.ics.
An item should contain a UID property as described by the vCard and iCalendar standards. If it contains more than one UID property, the values of those must not differ. No cap, don't be out here with conflicting UIDs. π
The file must contain exactly one event, task or contact. In most cases this also implies only one VEVENT/VTODO/VCARD component per file, but e.g. recurrence exceptions would require multiple VEVENT components per event. So like, mostly one, sometimes more, it depends. ποΈ
The filename should have similar properties as the UID of the file content. However, there is no requirement for these two to be the same. Programs may choose to store additional metadata in that filename, however, at the same time they must not assume that the metadata they included will be preserved by other programs. Rude? Maybe. True? Absolutely. π
π·οΈ Metadata
Any of the below metadata files may be absent. None of the files listed below have any file extensions. Not a single one. π«
- A file called
colorinside the vdir indicates the vdir's color, a property that is only relevant in UI design.
Its content is an ASCII-encoded hex-RGB value of the form #RRGGBB. For example, a file content of #FF0000 indicates that the vdir has a red (user-visible) color. No short forms or informal values such as red (as known from CSS, for example) are allowed. The prefixing # must be present. π
- Files called
displaynameanddescriptioncontain a UTF-8 encoded label/description, that may be used to represent the vdir in UIs. π - A file called
orderinside the vdir includes the relative order of the calendar, a property that is only relevant in UI design. π’
βοΈ Writing to vdirs
Creating and modifying items or metadata files should happen atomically (https://en.wikipedia.org/wiki/Atomicity_%28programming%29). All or nothing, bestie. π
Writing to a temporary file on the same physical device, and then moving it to the appropriate location is usually a very effective solution. For this purpose, files with the extension .tmp may be created inside collections. π§
When changing an item, the original filename must be used. Don't go renaming things, that's not the move. π¨
π Reading from vdirs
- Any file ending with the
.tmpor no file extension must not be treated as an item. Skip it, it's not real. π - The
identpart of the filename should not be parsed to improve the speed of item lookup. Speed matters, ok? β‘
π€ Considerations
The primary reason this format was chosen is due to its compatibility with the CardDAV (http://tools.ietf.org/html/rfc6352) and CalDAV (http://tools.ietf.org/search/rfc4791) standards. Interop queen. π
β‘ Performance
Currently, vdirs suffer from a rather major performance problem, one which current implementations try to mitigate by building up indices of the collections for faster search and lookup. Yeah, it's a whole thing. π
The reason items' filenames don't contain any extra information is simple: The solutions presented induced duplication of data, where one duplicate might become out of date because of bad implementations. As it stands right now, an index format could be formalized separately though. π
vdirsyncer doesn't really have to bother about efficient item lookup, because its synchronization algorithm needs to fetch the whole list of items anyway. Detecting changes is easily implemented by checking the files' modification time. So like, it just works. β¨
π PACKAGING GUIDELINES π
Okay so first off: thank you so much for packaging vdirsyncer! Bestie, these guidelines are here to help you dodge some common pitfalls. π«Ά
If you find yourself needing to patch anything, or going in a different direction, please open an issue so we can also address it in a way that works for everyone. Otherwise we get bug reports for code or scenarios that don't exist in upstream vdirsycner. π
Obtaining the source code
The main distribution channel is PyPI (https://pypi.python.org/pypi/vdirsyncer), and source tarballs can be obtained there. We mirror the same package tarball and wheel as GitHub releases. Please do not confuse these with the auto-generated GitHub "Source Code" tarball β those are missing some important metadata and your build will fail. π
We give each release a tag in the git repo. If you want to get notified of new releases, GitHub's feed (https://github.com/pimutils/vdirsyncer/releases.atom) is a good way. β¨
Tags will be signed by the maintainer who is doing the release (starting with 0.16.8), and generation of the tarball and wheel is done by CI. Hence, only the tag itself is signed. π₯
Dependency versions
As with most Python packages, setup.py denotes the dependencies of vdirsyncer. It also contains lower-bound versions of each dependency. Older versions will be rejected by the testsuite. No cap.
Testing
Everything testing-related goes through the Makefile in the root of the repository or PyPI package. Trying to e.g. run pytest directly will require a lot of environment variables to be set (for configuration) and you probably don't want to deal with that. π
You can install all the development dependencies with:
make install-dev
You probably don't want this since it will use pip to download the dependencies. Alternatively test dependencies are listed as test optional dependencies in pyproject.toml, again with lower-bound version requirements. π
You also have to have vdirsyncer fully installed at this point. Merely cd-ing into the tarball will not be sufficient. Literally.
Running the tests happens with:
pytest
Hypothesis will randomly generate test input. If you care about deterministic tests, set the DETERMINISTIC_TESTS variable to "true":
make DETERMINISTIC_TESTS=true test
There are a lot of additional variables that allow you to test vdirsyncer against a particular server. Those variables are not "stable" and may change drastically between minor versions. Just don't use them β you are unlikely to find bugs that vdirsyncer's CI hasn't found. π
Documentation
Using Sphinx (www.sphinx-doc.org/) you can generate the documentation you're reading right now in a variety of formats, such as HTML, PDF, or even as a manpage. That said, I only take care of the HTML docs' formatting. πΈ
You can find a list of dependencies in pyproject.toml, in the project.optional-dependencies section as docs. Again, you can install those using pip with:
pip install '.[docs]'
Then change into the docs/ directory and build whatever format you want using the Makefile in there (run make for the formats you can build). π¦
Contrib files
Reference systemd.service and systemd.timer unit files are provided. It is recommended to install this if your distribution is systemd-based. π
π SUPPORT AND CONTACT π
- The
#pimutilsIRC channel on Libera.Chat (https://pimutils.org/contact) might be active, depending on your timezone. Use it for support and general (including off-topic) discussion. π¬ - Open a GitHub issue (
https://github.com/pimutils/vdirsyncer/issues/) for concrete bug reports and feature requests. π - For security issues, contact
contact@pimutils.org. π
π CHANGELOG π
This changelog only contains information that might be useful to end users and package maintainers. For further info, see the git commit log. π
Package maintainers and users who have to manually update their installation may want to subscribe to GitHub's tag feed (https://github.com/pimutils/vdirsyncer/tags.atom). β
Version 0.21.0
- Implement retrying for
googlestorage type when a rate limit is reached. π tenacityis now a required dependency.- Drop support for Python 3.8.
- Retry transient network errors for nullipotent requests.
- Add support for Python 3.14. π
Version 0.20.0
- Remove dependency on abandoned
atomicwriteslibrary. - Implement
filter_hookfor the HTTP storage. - Drop support for Python 3.7.
- Add support for Python 3.12 and Python 3.13.
- Properly close the status database after using. This especially affects tests, where we were leaking a large amount of file descriptors. π
- Extend supported versions of
aiostreamto include0.7.x.
Version 0.19.3
- Added a
no_deleteoption to the storage configuration. issue #1090 (https://github.com/pimutils/vdirsyncer/issues/1090) - Fix crash when running
vdirsyncer repairon a collection. issue #1019 (https://github.com/pimutils/vdirsyncer/issues/1019) - Add an option to request vCard v4.0. issue #1066 (
https://github.com/pimutils/vdirsyncer/issues/1066) - Require matching
BEGINandENDlines in vobjects. issue #1103 (https://github.com/pimutils/vdirsyncer/issues/1103) - A Docker environment for Vdirsyncer has been added β Vdirsyncer DOCKERIZED (
https://github.com/Bleala/Vdirsyncer-DOCKERIZED). π³ - Implement digest auth. issue #1137 (
https://github.com/pimutils/vdirsyncer/issues/1137) - Add
filter_hookparameter tohttp(#storage-http). issue #1136 (https://github.com/pimutils/vdirsyncer/issues/1136)
Version 0.19.2
- Improve the performance of
SingleFileStorage. issue #818 (https://github.com/pimutils/vdirsyncer/issues/818) - Properly document some caveats of the Google Contacts storage.
- Fix crash when using auth certs. issue #1033 (
https://github.com/pimutils/vdirsyncer/issues/1033) - The filesystem storage can be specified with
type = "filesystem/icalendar"ortype = "filesystem/vcard". This has no functional impact, and is merely for forward compatibility with the Rust implementation of vdirsyncer. - Python 3.10 and 3.11 are officially supported. π
- Instructions for integrating with Google CalDav/CardDav have changed. Applications now need to be registered as "Desktop applications". Using "Web application" no longer works due to changes on Google's side. issue #1078 (
https://github.com/pimutils/vdirsyncer/issues/1078)
Version 0.19.1
- Fixed crash when operating on Google Contacts. issue #994 (
https://github.com/pimutils/vdirsyncer/issues/994) - The
HTTP_PROXYandHTTPS_PROXYare now respected. issue #1031 (https://github.com/pimutils/vdirsyncer/issues/1031) - Instructions for integrating with Google CalDav/CardDav have changed. Applications now need to be registered as "Web Application". issue #975 (
https://github.com/pimutils/vdirsyncer/issues/975) - Various documentation updates. π
Version 0.19.0
- Add
"shell"password fetch strategy to pass command string to a shell. - Add
"description"and"order"as metadata. These fetch theCalDAV: calendar-description,CardDAV:addressbook-descriptionandapple-ns:calendar-orderproperties respectively. - Add a new
showconfigstatus. This prints some configuration values as JSON. This is intended to be used by external tools and helpers that interact with vdirsyncer, and considered experimental. - Add
implicitoption to thepairsection (#pair-config). When set to"create", it implicitly creates missing collections during sync without user prompts. This simplifies workflows where collections should be automatically created on both sides. - Update TLS-related tests that were failing due to weak MDs. issue #903 (
https://github.com/pimutils/vdirsyncer/issues/903) pytest-httpserverandtrustmeare now required for tests.pytest-localserveris no longer required for tests.- Multithreaded support has been dropped. The
--max-workershas been removed. - A new
asynciobackend is now used. So far, this shows substantial speed improvements in discovery and metasync, but little change in sync. This will likely continue improving over time. issue #906 (https://github.com/pimutils/vdirsyncer/issues/906) - The
googlestorage types no longer requirerequests-oauthlib, but requirepython-aiohttp-oauthlibinstead. - Vdirsyncer no longer includes experimental support for EteSync (
https://www.etesync.com/). The existing integration had not been supported for a long time and no longer worked. Support for external storages may be added if anyone is interested in maintaining an EteSync plugin. EteSync users should consider usingetesync-dav(https://github.com/etesync/etesync-dav). - The plist for macOS has been dropped. It was broken and homebrew generates their own based on package metadata. macOS users are encouraged to use that as a reference. π
Changes to SSL configuration
Support for md5 and sha1 certificate fingerprints has been dropped. If you're validating certificate fingerprints, use sha256 instead. π
When using a custom verify_fingerprint, CA validation is always disabled.
If verify_fingerprint is unset, CA verification is always active. Disabling both features is insecure and no longer supported. π¨
The verify parameter no longer takes boolean values, it is now optional and only takes a string to a custom CA for verification.
The verify and verify_fingerprint will likely be merged into a single parameter in future.
Version 0.18.0
Note: Version 0.17 has some alpha releases but ultimately was never finalised. 0.18 actually continues where 0.16 left off. π
- Support for Python 3.5 and 3.6 has been dropped. This release mostly focuses on keeping vdirsyncer compatible with newer environments.
click8 andclick-threading0.5.0 are now required.- For those using
pipsi, we now recommend usingpipx, it's successor. - Python 3.9 is now supported. π
- Our Debian/Ubuntu build scripts have been updated. New versions should be pushed to those repositories soon.
Version 0.16.8
released 09 June 2020
- Support Python 3.7 and 3.8.
This release is functionally identical to 0.16.7. It's been tested with recent Python versions, and has been marked as supporting them. It will also be the final release supporting Python 3.5 and 3.6. π
Version 0.16.7
released on 19 July 2018
- Fixes for Python 3.7.
Version 0.16.6
released on 13 June 2018
- Packagers: Documentation building no longer needs a working installation of vdirsyncer.
Version 0.16.5
released on 13 June 2018
- Packagers:
click-log0.3 is required. - All output will now happen on stderr (because of the upgrade of
click-log).
Version 0.16.4
released on 05 February 2018
π Version 0.16.3 β released on 03 October 2017
- Fixed the tests for the new Hypothesis version. And that is literally the entire change, no cap, nothing else snuck in.
- First version with custom Debian and Ubuntu packages!! See issue #663
https://github.com/pimutils/vdirsyncer/issues/663. - Yeeted invalid ASCII control characters out of server responses. See issue #626
https://github.com/pimutils/vdirsyncer/issues/626.
π¦ packagers: Python 3.3 is no longer supported, bestie. See pull request #674 https://github.com/pimutils/vdirsyncer/pull/674.
π¦ Version 0.16.2 β released on 24 August 2017
- Fixed the crash when using
daterangeoritem_typefilters ingoogle_calendar<#storage-google_calendar>, see issue #657https://github.com/pimutils/vdirsyncer/issues/657.
π¦ Packagers: fixes for the new version0.2.0ofclick-logβ the version requirements for theclick-logdependency changed.
π Version 0.16.1 β released on 8 August 2017
- remoteStorage support? Gone. Removed. See issue #647
https://github.com/pimutils/vdirsyncer/issues/647. - Fixed the test failures caused by the latest
requestsversion, see issue #660https://github.com/pimutils/vdirsyncer/issues/660.
π Version 0.16.0 β released on 2 June 2017
- Strips
METHOD:PUBLISHthat some calendar providers add, see issue #502https://github.com/pimutils/vdirsyncer/issues/502. - Fixed a crash of Google storages when saving the token file π.
- Made DAV discovery more RFC-conformant, see pull request #585
https://github.com/pimutils/vdirsyncer/pull/585. - Vdirsyncer is now tested against Xandikos, see pull request #601
https://github.com/pimutils/vdirsyncer/pull/601. - Subfolders with a leading dot are now ignored during
discoverfor filesystem storage. Which makes it way easier to combine it with version control β¨. - Statuses are now stored in a sqlite database β old data is automatically migrated. Users with really large datasets should encounter performance improvements. This means
sqlite3is now a dependency of vdirsyncer. - Vdirsyncer is now licensed under the 3-clause BSD license, see issue #610
https://github.com/pimutils/vdirsyncer/issues/610. - Vdirsyncer now includes experimental support for EteSync
https://www.etesync.com/, see pull request #614https://github.com/pimutils/vdirsyncer/pull/614. - Vdirsyncer now uses more filesystem metadata for determining whether an item changed. Heads up: you will notice a possibly heavy CPU/IO spike on the first sync after upgrading π.
π¦ Packagers: referencesystemd.serviceandsystemd.timerunit files are provided. It is recommended to install these as documentation if your distribution is systemd-based.
πΈ Version 0.15.0 β released on 28 February 2017
- The deprecated syntax for configuration values is now completely rejected. All values now have to be valid JSON, periodt.
- A few UX improvements for Google storages, see issue #549
https://github.com/pimutils/vdirsyncer/issues/549and issue #552https://github.com/pimutils/vdirsyncer/issues/552. - Fixed collection discovery for
google_contacts<#storage-google_contacts>, see issue #564https://github.com/pimutils/vdirsyncer/issues/564. - iCloud is now tested on Travis, see issue #567
https://github.com/pimutils/vdirsyncer/issues/567.
π Version 0.14.1 β released on 05 January 2017
vdirsyncer repairno longer changes "unsafe" UIDs by default β an extra option has to be specified. See issue #527https://github.com/pimutils/vdirsyncer/issues/527.- A lot of important documentation updates β¨.
β Version 0.14.0 β released on 26 October 2016
vdirsyncer syncnow continues other uploads if one upload failed. The exit code in such situations is still non-zero.- Added the
partial_syncoption to thepairsection. See the config docs<#partial-sync-def>. - Vdirsyncer will now warn if there's a string without quotes in your config. Please file issues if you find documentation that uses unquoted strings π«Ά.
- Fixed an issue that would break khal's config setup wizard.
π§ Version 0.13.1 β released on 30 September 2016
- Fixed a bug that would completely break collection discovery π.
π Version 0.13.0 β released on 29 September 2016
- Python 2 is no longer supported at all. See issue #219
https://github.com/pimutils/vdirsyncer/issues/219. - Config sections are now checked for duplicate names. This also means you cannot have a storage section
[storage foo]and a pair[pair foo]in your config β they have to have different names. This is done so that console output is always unambiguous. See issue #459https://github.com/pimutils/vdirsyncer/issues/459. - Custom commands can now be used for conflict resolution during sync. See issue #127
https://github.com/pimutils/vdirsyncer/issues/127. http<#storage-http>now completely ignores UIDs. This avoids a lot of unnecessary down- and uploads.
π Version 0.12.1 β released on 20 August 2016
- Fixed a crash for Google and DAV storages. See pull request #492
https://github.com/pimutils/vdirsyncer/pull/492. - Fixed an URL-encoding problem with DavMail. See issue #491
https://github.com/pimutils/vdirsyncer/issues/491.
π¦ Version 0.12 β released on 19 August 2016
singlefile<#storage-singlefile>now supports collections. See pull request #488https://github.com/pimutils/vdirsyncer/pull/488.
π Version 0.11.3 β released on 29 July 2016
- The default value of the
authparameter was changed fromguesstobasicto resolve issues with the Apple Calendar Server (issue #457https://github.com/pimutils/vdirsyncer/issues/457) and improve performance. See issue #461https://github.com/pimutils/vdirsyncer/issues/461.
π¦ Packagers: theclick-threadingrequirement is now>=0.2. It was incorrect before. See issue #478https://github.com/pimutils/vdirsyncer/issues/478.
- Fixed a bug in the DAV XML parsing code that would make vdirsyncer crash on certain input. See issue #480
https://github.com/pimutils/vdirsyncer/issues/480. - Redirect chains should now be properly handled when resolving well-known URLs. See pull request #481
https://github.com/pimutils/vdirsyncer/pull/481.
π Version 0.11.2 β released on 15 June 2016
- Fixed a typo that would break tests π.
π Version 0.11.1 β released on 15 June 2016
- Fixed a bug in collection validation.
- Fixed a cosmetic bug in debug output.
- Various documentation improvements.
β¨ Version 0.11.0 β released on 19 May 2016
- Discovery is no longer automatically done when running
vdirsyncer sync.vdirsyncer discovernow has to be explicitly called. - Added a
.plistexample for Mac OS X. - Usage under Python 2 now requires a special config parameter to be set.
- Various deprecated configuration parameters no longer have specialized error messages β the generic error message for unknown parameters is shown instead.
- Vdirsyncer no longer warns that the
passwordevalparameter has been renamed topassword_command. - The keyring fetching strategy was dropped some versions ago, but the specialized error message has now been dropped too.
- An old status format from version
0.4is no longer supported. If you're experiencing problems, just delete your status folder.
- Vdirsyncer no longer warns that the
π₯ Version 0.10.0 β released on 23 April 2016
- New storage types
google_calendar<#storage-google_calendar>andgoogle_contacts<#storage-google_contacts>have been added π. - New global command line option
--config, to specify an alternative config file. See issue #409https://github.com/pimutils/vdirsyncer/issues/409. - The
collectionsparameter can now be used to synchronize differently-named collections with each other.
π¦ Packagers: the lxml dependency has been dropped.
- XML parsing is now a lot stricter. Malfunctioning servers that used to work with vdirsyncer may stop working π.
π«Ά Version 0.9.3 β released on 22 March 2016
singlefile<#storage-singlefile>andhttp<#storage-http>now handle recurring events properly.- Fixed a typo in the packaging guidelines.
- Moved to the pimutils organization on GitHub. Old links should redirect, but be aware of client software that doesn't properly handle redirects π.
πΈ Version 0.9.2 β released on 13 March 2016
- Fixed the testsuite for environments that don't have any web browser installed. See pull request #384
https://github.com/pimutils/vdirsyncer/pull/384.
π§ Version 0.9.1 β released on 13 March 2016
- Removed a leftover debug print statement in
vdirsyncer discover, see commit3d856749f37639821b148238ef35f1acba82db36. metasyncwill now strip whitespace from the start and the end of the values. See issue #358https://github.com/pimutils/vdirsyncer/issues/358.- New Packaging Guidelines have been added to the documentation.
β Version 0.9.0 β released on 15 February 2016
- The
collectionsparameter is now required inpairconfigurations. Vdirsyncer will tell you what to do in its error message. See issue #328https://github.com/pimutils/vdirsyncer/issues/328.
π Version 0.8.1 β released on 30 January 2016
- Fixed the error messages when an invalid parameter fetching strategy is used. This matters because users would receive awkward errors for using the deprecated keyring fetching.
π Version 0.8.0 β released on 27 January 2016
- Keyring support has been removed, which means
password.fetch = ["keyring", "example.com", "myuser"]doesn't work anymore.- For existing setups: use
password.fetch = ["command", "keyring", "get", "example.com", "myuser"]instead, which is more generic. See the documentation for details.
- For existing setups: use
- Now emitting a warning when running under Python 2. See issue #219
https://github.com/pimutils/vdirsyncer/issues/219.
π Version 0.7.5 β released on 23 December 2015
- Fixed a bug in
remotestoragethat would try to open a CLI browser for OAuth π. - Fixed a packaging bug that would prevent vdirsyncer from working with newer
lxmlversions.
π¦ Version 0.7.4 β released on 22 December 2015
- Improved error messages instead of faulty server behavior, see issue #290
https://github.com/pimutils/vdirsyncer/issues/290and issue #300https://github.com/pimutils/vdirsyncer/issues/300. - Safer shutdown of the threadpool, avoiding exceptions, see issue #291
https://github.com/pimutils/vdirsyncer/issues/291. - Fixed a sync bug for read-only storages, see commit
ed22764921b2e5bf6a934cf14aa9c5fede804d8e. - Etag changes are no longer sufficient to trigger sync operations β an actual content change is also necessary. See issue #257
https://github.com/pimutils/vdirsyncer/issues/257.
π Version 0.7.3
released on 05 November 2015
- no cap,
remotestorage-dependenciesis actually optional now, bestie π
π Version 0.7.2
released on 05 November 2015
- we un-broke the testsuite. that's it. that's the whole changelog entry π
πΈ Version 0.7.1
released on 05 November 2015
- Packagers: the setuptools extras keys
keyringandremotestoragegot added. they're basically optional dependencies, iykyk. seesetup.pyfor more details π«Ά - highly experimental remoteStorage support has been added β and fr fr, it may be completely overhauled or even removed in any version. this is not a drill π
- removed mentions of the old
password_commandin documentation
π¦ Version 0.7.0
released on 27 October 2015
- Packagers: new dependencies are
click_threading,click_logandclick>=5.0π₯ password_commandis gone. keyring support got completely overhauled β see Storing passwords
β Version 0.6.0
released on 06 August 2015
password_commandinvocations with non-zero exit code are now fatal (and will abort synchronization) instead of just producing a warning. like, it's over-over, not just warning-over π- Vdirsyncer is now able to synchronize metadata of collections! set
metadata = ["displayname"]and runvdirsyncer metasyncβ slay π - Packagers: don't use the GitHub tarballs, use the PyPI ones
- Packagers:
build.shis gone, andMakefileis included in tarballs. see the content ofMakefilefor how to run tests post-packaging verify_fingerprintdoesn't automatically disable verify anymore
π Version 0.5.2
released on 15 June 2015
- Vdirsyncer now checks and corrects the permissions of status files π
- Vdirsyncer is now more robust towards changing UIDs inside items
- Vdirsyncer is now handling unicode hrefs and UIDs correctly. software that produces non-ASCII UIDs is broken, but apparently it exists π
π Version 0.5.1
released on 29 May 2015
- N.b.: the PyPI upload of
0.5.0is completely broken π - raise version of required
requests-toolbeltto0.4.0 - command line should be a lot faster when no work is done, e.g. for help output β‘
- fix compatibility with iCloud again (we keep doing this π)
- use only one worker if debug mode is activated
verify=falseis now disallowed in vdirsyncer β please useverify_fingerprintinstead- fixed a bug where vdirsyncer's DAV storage was not using the configured useragent for collection discovery
π§ Version 0.4.4
released on 12 March 2015
- support for client certificates via the new
auth_certparameter β see issue #182 athttps://github.com/pimutils/vdirsyncer/issues/182and pull request #183 athttps://github.com/pimutils/vdirsyncer/pull/183π - the
icalendarpackage is no longer required - several bugfixes related to collection creation
π Version 0.4.3
released on 20 February 2015
- more performance improvements to
singlefile-storage β‘ - add
post_hookparam tofilesystem-storage - collection creation now also works with SabreDAV-based servers, such as Baikal or ownCloud
- removed some workarounds for Radicale β upgrading to the latest Radicale will fix the issues
- fixed issues with iCloud discovery
- Vdirsyncer now includes a simple
repaircommand that seeks to fix some broken items π©Ή
πΈ Version 0.4.2
released on 30 January 2015
- Vdirsyncer now respects redirects when uploading and updating items. this might fix issues with Zimbra
- relative
status_pathvalues are now interpreted as relative to the configuration file's directory - fixed compatibility with custom SabreDAV servers β see issue #166 at
https://github.com/pimutils/vdirsyncer/issues/166 - catch harmless threading exceptions that occur when shutting down vdirsyncer β see issue #167 at
https://github.com/pimutils/vdirsyncer/issues/167 - Vdirsyncer now depends on
atomicwrites - massive performance improvements to
singlefile-storage π₯ - items with extremely long UIDs should now be saved properly in
filesystem-storage β see issue #173 athttps://github.com/pimutils/vdirsyncer/issues/173
π¦ Version 0.4.1
released on 05 January 2015
- all
createarguments from all storages are gone. Vdirsyncer now just asks if it should try to create collections π - the old config values
True,False,on,offandNoneare now invalid - UID conflicts are now properly handled instead of ignoring one item. Card- and CalDAV servers are already supposed to take care of those though
- official Baikal support added π
β¨ Version 0.4.0
released on 31 December 2014
- the
passwordevalparameter has been renamed topassword_command - the old way of writing certain config values such as lists is now gone
- collection discovery has been rewritten. old configuration files should be compatible with it, but vdirsyncer now caches the results of the collection discovery. you have to run
vdirsyncer discoverif collections were added or removed on one side π - pair and storage names are now restricted to certain characters. Vdirsyncer will issue a clear error message if your configuration file is invalid in that regard
- Vdirsyncer now supports the XDG-Basedir specification. if the
VDIRSYNCER_CONFIGenvironment variable isn't set and the~/.vdirsyncer/configfile doesn't exist, it will look for the configuration file at$XDG_CONFIG_HOME/vdirsyncer/configπ - some improvements to CardDAV and CalDAV discovery, based on problems found with FastMail. support for
.well-known-URIs has been added
π Version 0.3.4
released on 8 December 2014
- some more bugfixes to config handling π©Ή
π Version 0.3.3
released on 8 December 2014
- Vdirsyncer now also works with iCloud! particularly collection discovery and etag handling were fixed βοΈ
- Vdirsyncer now encodes Cal- and CardDAV requests differently. this hasn't been well-tested with servers like Zimbra or SoGo, but isn't expected to cause any problems
- Vdirsyncer is now more robust regarding invalid responses from CalDAV servers. this should help with future compatibility with Davmail/Outlook
- fix a bug when specifying
item_typesof thecaldavstorage in the deprecated config format - fix a bug where vdirsyncer would ignore all but one character specified in
unsafe_href_charsof thecaldavandcarddavstorages π
π«Ά Version 0.3.2
released on 3 December 2014
- the current config format has been deprecated, and support for it will be removed in version
0.4.0. Vdirsyncer warns about this now β οΈ
π₯ Version 0.3.1
released on 24 November 2014
- fixed a bug where vdirsyncer would delete items if they're deleted on side A but modified on side B. instead vdirsyncer will now upload the new items to side A β see issue #128 at
https://github.com/pimutils/vdirsyncer/issues/128 - synchronization continues with the remaining pairs if one pair crashes β see issue #121 at
https://github.com/pimutils/vdirsyncer/issues/121 - the
processesconfig key is gone. there's now a--max-workersoption on the CLI which has a similar purpose β see pull request #126 athttps://github.com/pimutils/vdirsyncer/pull/126 - the Read The Docs-theme is no longer required for building the docs. if it is not installed, the default theme will be used β see issue #134 at
https://github.com/pimutils/vdirsyncer/issues/134
π Version 0.3.0
released on 20 September 2014
- add
verify_fingerprintparameter tohttp,caldavandcarddavβ see issue #99 athttps://github.com/pimutils/vdirsyncer/issues/99and pull request #106 athttps://github.com/pimutils/vdirsyncer/pull/106 - add
passwordevalparameter to the General Section β see issue #108 athttps://github.com/pimutils/vdirsyncer/issues/108and pull request #117 athttps://github.com/pimutils/vdirsyncer/pull/117 - emit warnings (instead of exceptions) about certain invalid responses from the server β see issue #113 at
https://github.com/pimutils/vdirsyncer/issues/113. this is apparently required for compatibility with Davmail
π Version 0.2.5
released on 27 August 2014
- don't ask for the password of one server more than once, and fix multiple concurrency issues β see issue #101 at
https://github.com/pimutils/vdirsyncer/issues/101 - better validation of DAV endpoints
π Version 0.2.4
released on 18 August 2014
- include workaround for collection discovery with latest version of Radicale
- include metadata files such as the changelog or license in source distribution β see issue #97 at
https://github.com/pimutils/vdirsyncer/issues/97and issue #98 athttps://github.com/pimutils/vdirsyncer/issues/98
β Version 0.2.3
released on 11 August 2014
- Vdirsyncer now has a
--versionflag β see issue #92 athttps://github.com/pimutils/vdirsyncer/issues/92 - fix a lot of bugs related to special characters in URLs β see issue #49 at
https://github.com/pimutils/vdirsyncer/issues/49
π§ Version 0.2.2
released on 04 August 2014
- remove a security check that caused problems with special characters in DAV URLs and certain servers. on top of that, the security check was nonsensical π β see issue #87 at
https://github.com/pimutils/vdirsyncer/issues/87and issue #91 athttps://github.com/pimutils/vdirsyncer/issues/91 - change some errors to warnings β see issue #88 at
https://github.com/pimutils/vdirsyncer/issues/88 - improve collection autodiscovery for servers without full support
π¦ Version 0.2.1
released on 05 July 2014
- fix bug where vdirsyncer shows empty addressbooks when using CardDAV with Zimbra
- fix infinite loop when password doesn't exist in system keyring π
- colorized errors, warnings and debug messages π¨
- vdirsyncer now depends on the
clickpackage instead ofargvard
π Version 0.2.0
released on 12 June 2014
- vdirsyncer now depends on the
icalendarpackage from PyPI, to get rid of its own broken parser - vdirsyncer now also depends on
requests_toolbelt. this makes it possible to guess the authentication type instead of blankly assuming basic - fix a semi-bug in
caldavandcarddavstorages where a tuple(href, etag)instead of the proper etag would have been returned from the upload method. vdirsyncer might do unnecessary copying when upgrading to this version - add the
singlefilestorage β see issue #48 athttps://github.com/pimutils/vdirsyncer/issues/48β - The
collectionsparameter for pair sections now accepts the special valuesfrom aandfrom bfor automatically discovering collections. See Pair Section. - The
read_onlyparameter was added to storage sections. See Storage Section.
πΈ Version 0.1.5
released on 14 May 2014 β a vintage era, honestly π
- Introduced changelogs β yes bestie, this very genre of list you're reading right now was born here π
- Many bugfixes
- Many doc fixes
vdirsyncernow doesn't necessarily need UIDs anymore for synchronization.vdirsyncernow aborts if one collection got completely emptied between synchronizations. See issue #42.
π¨ That last one is a big mood: if one of your collections shows up completely empty between syncs, vdirsyncer will straight-up abort instead of cheerfully deleting everything you love. She's protecting you. Let her.
π CREDITS AND LICENSE π
π«Ά Contributors
In alphabetical order β no faves, we don't play that:
- Ben Boeckel
- Bleala
- Christian Geier
- ClΓ©ment Mondon
- Corey Hinshaw
- Kai Herlemann
- Hugo Osvaldo Barrera
- Jason Cox
- Julian Mehne
- Malte Kiefer
- Marek Marczykowski-GΓ³recki
- Markus Unterwaditzer
- Michael Adler
- rEnr3n
- Thomas WeiΓschuh
- Witcher01
- samm81
Special thanks goes to β the real MVPs, periodt:
- FastMail sponsors a paid account for testing their servers. (iykyk β actual server testing, not vibes)
- Packagecloud provide repositories for
vdirsyncer's Debian packages.
βοΈ License
Copyright (c) 2014-2020 by Markus Unterwaditzer & contributors. See AUTHORS.rst for more details.
Some rights reserved.
Redistribution and use in source and binary forms of the software as well as documentation, with or without modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
- The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
β οΈ Okay so this next bit is ALL CAPS for a reason, it's giving legal-drama main character energy. Not me paraphrasing it β this is verbatim, bestie, protect it with your life:
THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
π DONATIONS π
vdirsyncer is and will always be free and open source software. We appreciate sponsors willing to fund our continued work on it. π
If you found my work useful, please consider donating. Thank you! π«Ά
- Bitcoin:
13p42uWDL62bNRH3KWA6cSpSgvnHy1fs2E. - Sponsor via one-time tips or recurring donations via Ko-fi.
- Sponsor via recurring donations via liberapay.
β¨ Author
Markus Unterwaditzer
π¦ Copyright
2014-2026, Markus Unterwaditzer & contributors
and that's the whole page, bestie β you made it to the end ππ
This one's from vdirsyncer 0.21, dated Sep 05, 2026, and yeah β that footer's the little signature at the bottom of every VDIRSYNCER(1) page. Go forth, sync your calendars, don't empty your collections. Mwah. π
π¦ where this page comes from
- arch rolling: vdirsyncer 0.21.0-1 Β· BSD-3-Clause
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms