HTTP RSVP for a local attendee updates only the organizer's CalendarEvent

Issue Description

When both the organizer and attendee are local Stalwart users, responding to an invitation using the Yes / No / Maybe links in the invitation email does not update the attendee’s own CalendarEvent.

The HTTP RSVP endpoint reports success and updates the attendee’s participation status on the organizer’s copy of the event, but the corresponding event in the attendee’s account remains needs-action.

This leaves JMAP clients on the attendee account believing that the invitation still requires a response.

Expected Behavior

When a local attendee responds through the HTTP RSVP link, the response should be reflected in the attendee’s own CalendarEvent as well as the organizer’s scheduling state.

For example, after clicking Yes, a subsequent CalendarEvent/get in the attendee’s account should report:

"participationStatus": "accepted"

The response should otherwise have the same effective scheduling result as accepting the invitation through CalendarEvent/set with sendSchedulingMessages: true.

Actual Behavior

The HTTP endpoint returns:

RSVP has been recorded.

and the organizer’s CalendarEvent is updated to show the attendee as accepted.

However, the attendee’s corresponding CalendarEvent remains:

"participationStatus": "needs-action"

No CalendarEvent state change occurs in the attendee account.

The normal scheduling response is also not generated. In testing, the organizer received no acceptance notification/email after the HTTP RSVP. Performing the same acceptance through CalendarEvent/set on the attendee’s event immediately produced both the expected event update and scheduling response.

Reproduction Steps

  1. Create two local Stalwart accounts, for example:

  2. From the organizer account, create a calendar event inviting [email protected], with scheduling messages enabled.

  3. Confirm that Stalwart creates corresponding JMAP events for both accounts.

  4. Before responding, query both events with CalendarEvent/get. The attendee should be needs-action in both.

  5. Open the invitation email received by [email protected] and click the Yes link generated by Stalwart, which points to /calendar/rsvp?...&m=ACCEPTED.

  6. Confirm that the web page reports that the RSVP was recorded.

  7. Query both events again using CalendarEvent/get.

  8. Observe that:

    • the organizer’s copy now shows [email protected] as accepted;
    • the attendee’s own copy still shows needs-action.
  9. For comparison, update the attendee’s event through JMAP:

{
  "participants/attendee/participationStatus": "accepted"
}

with sendSchedulingMessages: true.

  1. The attendee’s event then changes to accepted, and the organizer receives the normal scheduling notification/email.

Stalwart Version

v0.16.x

Installation Method

Built from source

Database Backend

RocksDB

Blob Storage

RocksDB

Search Engine

Internal

Directory Backend

Internal

I have reviewed the documentation and FAQ and confirm that my issue is NOT addressed there.

on

I have searched this support forum (open and closed topics) and confirm this is not a duplicate.

on

I understand that topics in this category are triaged by a bot first but a human reply will follow up. If I’d prefer a human-only reply, I’ll add the no-ai tag to my topic.

on

Looking at the RSVP handler source confirms this is exactly what happens. The http_rsvp_handle function (in crates/groupware/src/calendar/itip.rs) only performs a direct CalendarEvent update on the account/document referenced by the signed RSVP token (i.e. the copy the invite link points to), writing the new PARTSTAT into that single event and committing the batch. It does not invoke any scheduling/iTIP outbound processing to notify the organizer, nor does it touch the attendee’s own copy of the event if the token references a different account’s copy.

By contrast, CalendarEvent/set with sendSchedulingMessages: true goes through the full JMAP scheduling pipeline, which both updates the attendee’s own event and generates the iTIP reply message to the organizer.

So the behavior you’re seeing (organizer’s copy updated, no scheduling email sent, attendee’s own event left at needs-action) is consistent with what the current RSVP handler code does: it’s a narrow direct-write path that bypasses the scheduling machinery entirely rather than reusing it. This looks like a genuine gap in the HTTP RSVP flow rather than a documented limitation, so it will need engineering follow-up rather than a configuration fix.

This is an automated reply from the Stalwart Help Bot. Other community members may follow up if this answer is incomplete or wrong.

Fixed in v0.16.19 (yet to be released).