Skip to content

Automated CardDAV to CalDAV birthday synchronization service. Fetches contacts from CardDAV servers and creates recurring birthday events in CalDAV calendars. Features Docker support, cron scheduling, customizable templates, and works with Nextcloud, Baikal, Radicale, SOGo.

License

Notifications You must be signed in to change notification settings

anatosun/bdaysync

Repository files navigation

Birthday Sync Service

Build Status Docker Image License: MIT

A containerized service that automatically syncs birthdays from CardDAV to CalDAV servers with built-in scheduling.

Features

  • Automated Birthday Sync: Fetches contacts from CardDAV and creates recurring birthday events in CalDAV
  • Multi-Server Support: Compatible with Nextcloud, Baikal, Radicale, SOGo, and other CardDAV/CalDAV servers
  • Flexible Scheduling: Cron-style scheduling or interval-based syncing
  • Customizable Events: Template-based event titles, descriptions, and reminders
  • Container-Native: Built for Docker with health checks and graceful shutdown
  • Multi-Architecture: Supports AMD64 and ARM64 platforms

Quick Start

Using Pre-built Image

# Create environment file
cp .env.template .env
# Edit .env with your server credentials

# Run with docker-compose
docker-compose up -d

# Check logs
docker-compose logs -f birthday-sync

Building Locally

git clone https://github.com/anatosun/bdaysync.git
cd bdaysync
docker-compose build
docker-compose up -d

Configuration

Environment Variables

Variable Required Default Description
CARDAV_SERVER_URL - CardDAV server URL
CARDAV_USERNAME - CardDAV username
CARDAV_PASSWORD - CardDAV password
CALDAV_SERVER_URL - CalDAV server URL
CALDAV_USERNAME - CalDAV username
CALDAV_PASSWORD - CalDAV password

Scheduling Configuration

Variable Default Description
RUN_MODE daemon Run mode: daemon, once
SYNC_SCHEDULE 0 6 * * * Cron schedule for sync
DIAGNOSTIC_SCHEDULE 0 7 * * 0 Cron schedule for diagnostics
SYNC_INTERVAL_HOURS 0 Alternative: sync every N hours
STARTUP_DELAY 30 Seconds to wait before first sync

Event Customization

Variable Default Description
BIRTHDAY_EVENT_TITLE 🎂 {name}'s Birthday Event title template
BIRTHDAY_EVENT_DESCRIPTION Birthday of {name} Event description template
BIRTHDAY_REMINDER_DAYS 1,7 Reminder days (comma-separated)
BIRTHDAY_REMINDER_MESSAGE Reminder: {name}'s birthday is in {days} days! Reminder message template
BIRTHDAY_EVENT_CATEGORY Birthday Event category
BIRTHDAY_UPDATE_EXISTING true Update existing events

Logging & Debug

Variable Default Description
DEBUG false Enable debug logging
LOG_LEVEL INFO Log level (DEBUG, INFO, WARNING, ERROR)
LOG_TO_FILE false Write logs to file
TZ UTC Container timezone

Server Examples

Nextcloud

CARDAV_SERVER_URL=https://nextcloud.example.com/remote.php/dav/addressbooks/username/
CALDAV_SERVER_URL=https://nextcloud.example.com/remote.php/dav/calendars/username/personal/

Baikal

CARDAV_SERVER_URL=https://baikal.example.com/dav.php/addressbooks/username/
CALDAV_SERVER_URL=https://baikal.example.com/dav.php/calendars/username/default/

Radicale

CARDAV_SERVER_URL=https://radicale.example.com/username/
CALDAV_SERVER_URL=https://radicale.example.com/username/

Usage

Docker Run

docker run -d \
  --name birthday-sync \
  --env-file .env \
  -v birthday-logs:/var/log/birthday-sync \
  --restart unless-stopped \
  ghcr.io/anatosun/bdaysync:latest

Management Commands

# Manual sync
docker exec birthday-sync python bdaysync/main.py --once

# Run diagnostics
docker exec birthday-sync python bdaysync/main.py --diagnose

# Health check
docker exec birthday-sync python bdaysync/main.py --health-check

# View logs
docker-compose logs -f birthday-sync

# Skip ASCII banner
docker exec birthday-sync python bdaysync/main.py --no-banner --once

Local Development

# Install dependencies
pip install -r requirements.txt

# Set environment variables
export CARDAV_SERVER_URL="https://your-server.com/dav/"
export CARDAV_USERNAME="username"
# ... other variables

# Run directly
cd bdaysync
python main.py --diagnose
python main.py --once

Scheduling Examples

Cron-Style Scheduling

# Daily at 6 AM
SYNC_SCHEDULE=0 6 * * *

# Every 12 hours
SYNC_SCHEDULE=0 */12 * * *

# Weekdays at 9 AM
SYNC_SCHEDULE=0 9 * * 1-5

# Monthly on 1st at 6 AM
SYNC_SCHEDULE=0 6 1 * *

Interval-Based Scheduling

# Every 24 hours
SYNC_INTERVAL_HOURS=24

# Every 6 hours
SYNC_INTERVAL_HOURS=6

Architecture

bdaysync/
├── main.py              # Entry point
├── config.py            # Environment validation & logging
├── cardav_client.py     # CardDAV operations
├── caldav_client.py     # CalDAV operations
├── scheduler.py         # Cron-like scheduling
└── __init__.py          # Package initialization

Key Components

  • CardDAV Client: Discovers addressbooks and fetches contacts with birthdays
  • CalDAV Client: Creates/updates birthday events with customizable templates
  • Scheduler Service: Handles cron-style or interval-based scheduling
  • Configuration Manager: Validates environment and sets up logging

Troubleshooting

Debug Mode

DEBUG=true
LOG_LEVEL=DEBUG

Common Issues

Authentication Failed:

  • Verify server URLs (check trailing slashes)
  • Ensure credentials are correct
  • Check if app passwords are required (Nextcloud, etc.)

No Contacts Found:

  • Verify addressbook URL structure
  • Check contacts have birthday fields populated
  • Enable debug logging for detailed discovery info

Events Not Created:

  • Verify calendar permissions
  • Check CalDAV server supports event creation
  • Review calendar URL format

Template Errors:

  • Ensure proper escaping of special characters
  • Use simple templates without complex formatting
  • Check logs for format string errors

Log Analysis

# View all logs
docker-compose logs birthday-sync

# Follow logs in real-time
docker-compose logs -f birthday-sync

# View last 50 lines
docker-compose logs --tail=50 birthday-sync

# Search for errors
docker-compose logs birthday-sync | grep -i error

Multi-Architecture Support

Images are built for multiple architectures:

  • linux/amd64 (Intel/AMD 64-bit)
  • linux/arm64 (ARM 64-bit, Apple Silicon, Raspberry Pi 4+)

Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes using Conventional commits (git commit -m 'feat: added amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Development Setup

# Clone repository
git clone https://github.com/anatosun/bdaysync.git
cd bdaysync

# Install development dependencies
pip install -r requirements.txt

# Run the program
python -m bdaysync/main.py

License

This project is licensed under the MIT License - see the LICENSE file for details.

Support

Acknowledgments

About

Automated CardDAV to CalDAV birthday synchronization service. Fetches contacts from CardDAV servers and creates recurring birthday events in CalDAV calendars. Features Docker support, cron scheduling, customizable templates, and works with Nextcloud, Baikal, Radicale, SOGo.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages