fix: dedupe scheduling emails, Stalwart-compatible calendar filters

This commit is contained in:
Linus Rath
2026-06-11 18:24:43 +02:00
parent a27a5be3dd
commit be58cee989
5 changed files with 438 additions and 267 deletions
+9 -33
View File
@@ -471,13 +471,9 @@ export const useCalendarStore = create<CalendarStore>()(
}
set((state) => ({ events: [...state.events, mappedCreated] }));
if (sendSchedulingMessages && created.participants) {
try {
await client.sendImipInvitation(created);
} catch (e) {
debug.error('Failed to send invitation emails:', e);
}
}
// Invitation emails are sent by the server: `sendSchedulingMessages`
// on CalendarEvent/set makes Stalwart queue the iTIP REQUEST itself.
// Sending a client-side iMIP copy here produced duplicate emails.
return mappedCreated;
} catch (error) {
debug.error('Failed to create event:', error);
@@ -541,22 +537,9 @@ export const useCalendarStore = create<CalendarStore>()(
return merged;
}),
}));
if (sendSchedulingMessages) {
const mergedParticipants = cleanUpdates.participants ?? storeEvent?.participants;
if (mergedParticipants) {
const eventForInvitation = {
...(storeEvent ?? {}),
...cleanUpdates,
id: realId,
participants: mergedParticipants,
} as import('@/lib/jmap/types').CalendarEvent;
try {
await client.sendImipInvitation(eventForInvitation);
} catch (e) {
debug.error('Failed to send invitation emails:', e);
}
}
}
// Update emails (iTIP REQUEST/REPLY) are sent by the server via the
// `sendSchedulingMessages` argument already passed above - a manual
// iMIP send here produced duplicate emails.
} catch (error) {
debug.error('Failed to update event:', error);
set({ error: 'Failed to update event' });
@@ -787,16 +770,9 @@ export const useCalendarStore = create<CalendarStore>()(
const realId = storeEvent?.originalId || stripLocalAccountPrefix(id, storeEvent?.localAccountId);
const targetAccountId = storeEvent?.accountId;
client = resolveAccountClient(client, storeEvent?.localAccountId);
if (sendSchedulingMessages) {
try {
const event = await client.getCalendarEvent(realId, targetAccountId);
if (event?.participants) {
await client.sendImipCancellation(event);
}
} catch (e) {
debug.error('Failed to send cancellation emails:', e);
}
}
// Cancellation emails (iTIP CANCEL) are sent by the server via the
// `sendSchedulingMessages` argument on the destroy below - a manual
// iMIP send here produced duplicate emails.
debug.log('calendar', 'Calendar deleteEvent', {
storeId: id,
realId,