170 lines
7.0 KiB
Markdown
170 lines
7.0 KiB
Markdown
# Mail Calendar Sync for Nextcloud
|
|
|
|
Automatically apply calendar invitation responses (iMIP) received via email to your Nextcloud calendar events.
|
|
|
|
## What it does
|
|
|
|
When someone responds to a calendar invitation you sent (Accept, Decline, Tentative), this app automatically updates the attendee's participation status in your calendar — no manual action needed.
|
|
|
|
### Supported iMIP methods
|
|
|
|
| Method | Behavior |
|
|
|--------|----------|
|
|
| **REPLY** | Updates attendee status (ACCEPTED/DECLINED/TENTATIVE) on an **existing** event in your calendar. The event must already exist (matched by UID). |
|
|
| **REQUEST** | Updates an existing event with new details (time changes, etc). Optionally auto-adds new invitations to your calendar. |
|
|
| **CANCEL** | Marks an existing event as CANCELLED when the organizer cancels it. |
|
|
|
|
### Key safety feature
|
|
|
|
**The app always checks that the event UID from the email response already exists in your calendar before applying any changes.** This prevents stale or spoofed responses from creating phantom events.
|
|
|
|
## Requirements
|
|
|
|
- Nextcloud 28 or later
|
|
- [Nextcloud Mail app](https://apps.nextcloud.com/apps/mail) installed and configured with at least one account
|
|
- At least one writable calendar
|
|
- Background jobs (cron) configured and running
|
|
|
|
## Installation
|
|
|
|
1. Copy the `mail_calendar_sync` folder to your Nextcloud `apps/` directory:
|
|
|
|
```bash
|
|
cp -r mail_calendar_sync /var/www/nextcloud/apps/
|
|
```
|
|
|
|
2. Set proper permissions:
|
|
|
|
```bash
|
|
chown -R www-data:www-data /var/www/nextcloud/apps/mail_calendar_sync
|
|
```
|
|
|
|
3. Enable the app:
|
|
|
|
```bash
|
|
sudo -u www-data php occ app:enable mail_calendar_sync
|
|
```
|
|
|
|
4. Run the database migration:
|
|
|
|
```bash
|
|
sudo -u www-data php occ migrations:migrate mail_calendar_sync
|
|
```
|
|
|
|
## Configuration
|
|
|
|
Each user configures the app individually:
|
|
|
|
1. Go to **Settings → Groupware → Mail Calendar Sync**
|
|
2. Enable the sync
|
|
3. Select which **Mail account** to scan for responses
|
|
4. Select which **Calendar** to apply updates to
|
|
5. Optionally enable **auto-accept** to automatically add new invitations
|
|
6. Click **Save**
|
|
|
|
### Manual sync
|
|
|
|
Click the **"Sync now"** button in settings to trigger an immediate scan instead of waiting for the background job.
|
|
|
|
## How it works
|
|
|
|
```
|
|
┌─────────────────┐ ┌────────────────┐ ┌────────────────────┐
|
|
│ Background Job │ │ Mail Service │ │ Calendar Service │
|
|
│ (every 10 min) │────>│ (IMAP fetch) │────>│ (CalDAV lookup) │
|
|
└─────────────────┘ └────────────────┘ └────────────────────┘
|
|
│ │ │
|
|
│ 1. Load user config │ 2. Find iMip messages │ 3. Search by UID
|
|
│ │ in INBOX │ in user calendars
|
|
│ │ │
|
|
│ │ 4. Extract ICS from │ 5. Verify event exists
|
|
│ │ MIME parts │ before updating
|
|
│ │ │
|
|
│ │ │ 6. Update attendee
|
|
│ │ │ PARTSTAT
|
|
└───────────────────────┴────────────────────────┘
|
|
```
|
|
|
|
1. A **background job** runs every 10 minutes
|
|
2. For each user with sync enabled, it queries the **Mail app's database** for recent messages flagged as iMip
|
|
3. For unprocessed messages, it connects via **IMAP** to fetch the actual email and extract `text/calendar` MIME parts
|
|
4. It parses the ICS data using the **sabre/vobject** library
|
|
5. Based on the METHOD (REPLY/REQUEST/CANCEL), it:
|
|
- Searches the user's calendars for the event by **UID**
|
|
- Only proceeds if the event **already exists** (for REPLY and CANCEL)
|
|
- Updates the attendee participation status or event data
|
|
- Writes the updated event back via `ICreateFromString`
|
|
6. Each processed message is tracked to avoid re-processing
|
|
|
|
## Architecture
|
|
|
|
```
|
|
mail_calendar_sync/
|
|
├── appinfo/
|
|
│ ├── info.xml # App metadata & dependencies
|
|
│ └── routes.php # API routes
|
|
├── lib/
|
|
│ ├── AppInfo/
|
|
│ │ └── Application.php # App bootstrap
|
|
│ ├── BackgroundJob/
|
|
│ │ └── ProcessImipResponsesJob.php # Cron job (every 10 min)
|
|
│ ├── Controller/
|
|
│ │ └── SettingsController.php # REST API for settings UI
|
|
│ ├── Db/
|
|
│ │ ├── Config.php # User config entity
|
|
│ │ ├── ConfigMapper.php # Config DB mapper
|
|
│ │ ├── LogEntry.php # Activity log entity
|
|
│ │ ├── LogMapper.php # Log DB mapper
|
|
│ │ ├── ProcessedMessage.php # Processed msg entity
|
|
│ │ └── ProcessedMessageMapper.php # Processed msg DB mapper
|
|
│ ├── Migration/
|
|
│ │ └── Version1000Date20250209000000.php # DB schema
|
|
│ ├── Service/
|
|
│ │ ├── CalendarService.php # Calendar lookup & update
|
|
│ │ ├── MailService.php # IMAP fetch & ICS extraction
|
|
│ │ └── SyncService.php # Orchestrates the full flow
|
|
│ └── Settings/
|
|
│ └── PersonalSettings.php # Settings page registration
|
|
├── templates/
|
|
│ └── personal-settings.php # Settings page HTML
|
|
├── js/
|
|
│ └── personal-settings.js # Settings page JavaScript
|
|
├── css/
|
|
│ └── personal-settings.css # Settings page styles
|
|
├── composer.json
|
|
└── README.md
|
|
```
|
|
|
|
## Database tables
|
|
|
|
| Table | Purpose |
|
|
|-------|---------|
|
|
| `oc_mcs_config` | Per-user configuration (enabled, mail account, calendar, auto-accept) |
|
|
| `oc_mcs_log` | Activity log of all processed responses (kept 30 days) |
|
|
| `oc_mcs_processed` | Tracks which email messages have been processed (kept 90 days) |
|
|
|
|
## Troubleshooting
|
|
|
|
### No messages being processed
|
|
|
|
- Ensure the Mail app has synced recent messages (check Mail app directly)
|
|
- Verify that incoming invitation responses have `text/calendar` MIME parts
|
|
- Check that the Mail app flags messages with `$imip` (this happens during Mail sync)
|
|
- Try clicking "Sync now" in the settings to trigger an immediate scan
|
|
|
|
### Events not being updated
|
|
|
|
- The event **must already exist** in the selected calendar (matched by UID)
|
|
- The attendee email in the response must match an attendee in the existing event
|
|
- Check the activity log in settings for "SKIPPED" entries with explanations
|
|
|
|
### Check server logs
|
|
|
|
```bash
|
|
sudo -u www-data php occ log:tail --level=debug | grep -i "mail_calendar_sync\|MailCalendarSync"
|
|
```
|
|
|
|
## License
|
|
|
|
AGPL-3.0-or-later
|