iMIP subject and body omit DTSTART for recurring events — only the recurrence rule is rendered

Issue Description

For a recurring event, the human-readable iMIP message Stalwart generates
(subject line and both the HTML and plain-text body) shows only the
recurrence rule where the start of the meeting should be — e.g.
“When: Every week on Tuesday” — and never the DTSTART date or its time of
day. Non-recurring events render DTSTART correctly.

The attached event.ics is unaffected and carries the correct DTSTART/DTEND;
this is purely the rendered message a human reads.

The shared renderer means this affects invitations, updates, cancellations
and RSVP notifications alike.

Root cause looks straightforward: build_itip_template in
crates/services/src/task_manager/imip.rs iterates the properties and hits
RRULE before DTSTART. The RRULE arm sets has_rrule = true and claims the
calendar_when label; the DTSTART arm below it is guarded by
ICalendarProperty::Dtstart if !has_rrule, so for a recurring event it
falls through to _ => continue. The same loop feeds the subject, which is
why the subject loses the time too. At v0.16.21 that is imip.rs:437, with
has_rrule set at line 434. The long-date template already includes the time
of day — the renderer simply never reaches the field that would use it.

Not a configuration issue: no setting selects between the two fields.

Expected Behavior

The iMIP subject and body state when the meeting actually starts. For a
recurring event I would expect the start date and time rendered alongside
the recurrence rule, e.g.

When: Tuesday, 15 September 2026 at 10:00 (CEST), every week on Tuesday

rather than the two being mutually exclusive. RFC 5545 treats DTSTART as
part of the recurrence definition — the rule alone does not identify the
time of day — so dropping it leaves the message ambiguous.

Actual Behavior

DTSTART is omitted entirely for any event carrying an RRULE. The “When”
row and the subject line contain only the formatted recurrence rule:

When: Every week on Tuesday

No date, no time of day, no timezone. The recipient cannot tell from the
message when the meeting starts — only the .ics attachment carries it, so
a recipient reading the mail in a client that does not surface the
attachment’s details has no way to know.

Deviation: the start date and time are missing, not merely formatted
differently.

Reproduction Steps

  1. Two accounts: an organizer on the local domain, and an attendee
    (local or external — both reproduce).
  2. As the organizer, create a calendar event with a recurrence rule —
    e.g. weekly on Tuesday at 10:00 local time — add the attendee as an
    ATTENDEE, and let Stalwart send the scheduling message
    (CalDAV or JMAP CalendarEvent/set, either path).
  3. Open the resulting iMIP message as delivered to the attendee.
  4. Observe the subject line and the “When” row of the body: both show only
    “Every week on Tuesday”. No start date, no time.
  5. For contrast, repeat with the same event minus the recurrence rule —
    the single-occurrence invitation renders the full start date and time
    correctly.

Relevant Log Output

Not applicable — no error is logged. The message is generated and delivered
successfully; the defect is in what the template renders.

Stalwart Version

v0.16.x

Installation Method

NixOS

Database Backend

RocksDB

Blob Storage

RocksDB

Search Engine

Internal

Directory Backend

Internal

Additional Context

Observed across clients — the defect is server-side, in the generated
message, so the receiving client is irrelevant. Confirmed by reading the
rendered subject and body directly.

Proposed fix: stop treating DTSTART and RRULE as alternatives for the
calendar_when label. Render DTSTART as it is rendered today for
single-occurrence events, and append the formatted recurrence rule to the
same value. Same for the subject. No new locale string is needed — both
pieces already have formatters.

Searched this forum before filing; the nearest topics are t/1367 (iMIP
invitations omit meeting links) and t/1306 (add conference link and
location to iMIP invitation email), both about different missing fields.

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

This matches the current code. In crates/services/src/task_manager/imip.rs, the property loop sets has_rrule = true on the Rrule arm and assigns it the calendar_when label, while the Dtstart arm is guarded by if !has_rrule, so for any recurring event DTSTART is skipped and only the formatted recurrence rule is rendered in both the subject and the “When” line of the body. Non-recurring events go through the unguarded Dtstart branch and render correctly, which matches your reproduction.

This is a genuine defect rather than a configuration option, since there is no setting that chooses between showing DTSTART or the recurrence rule. Your proposed fix (render DTSTART as today and append the formatted RRULE to the same calendar_when value, for both subject and body) looks correct and doesn’t require new locale strings. This has been logged for a developer to review and 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.22 (yet to be released).