mailrs-ical 1.0.0

RFC 5545 (iCalendar) parser, serializer, and iTIP semantics — zero I/O, hand-rolled, with VTIMEZONE + RRULE support.
Documentation

mailrs-ical

Crates.io docs.rs License Downloads MSRV

English | 简体中文 | 日本語

RFC 5545 (iCalendar) + RFC 5546 (iTIP) parser, serializer, and typed semantics for Rust — hand-rolled, zero I/O, with VTIMEZONE + RRULE support.

Extracted from mailrs so any Rust project that needs to ingest text/calendar invites (or generate REPLY payloads) can lean on the same battle-tested core: byte-by-byte parsing with no parser-combinator dependency, typed Method / Attendee / Organizer / CalDateTime, and inline VTIMEZONE handling with chrono-tz IANA fallback.

Highlights

  • Zero I/O — pure parsing and formatting. No file system, no network, no async runtime. The caller wires everything.
  • Typed semantics — [parse_invite] returns a fully-typed [ParsedInvite] with METHOD / UID / SEQUENCE / DTSTAMP / DTSTART / DTEND / ATTENDEE / ORGANIZER / RRULE / EXDATE / RDATE / RECURRENCE-ID / STATUS / SUMMARY / LOCATION / DESCRIPTION / VTIMEZONE.
  • VTIMEZONE smart fallback — accepts inline VTIMEZONE blocks per RFC 5545; falls back to chrono-tz IANA names when the TZID is a known location.
  • iTIP awareness — [Method] enum covers REQUEST / REPLY / CANCEL / UPDATE / COUNTER / REFRESH / ADD / PUBLISH / DECLINECOUNTER per RFC 5546.
  • Serializer — [serialize] turns a [ParsedInvite] back into RFC 5545 text, suitable for iTIP REPLY bodies.
  • Battle-tested — extracted from a production Rust mail server; verified against a corpus of real .eml fixtures from Outlook / Nextcloud / Google / Apple Calendar / Thunderbird.

Quick start

use mailrs_ical::{parse_invite, Method};

let ics = b"BEGIN:VCALENDAR\r\nVERSION:2.0\r\nMETHOD:REQUEST\r\n\
            PRODID:-//Example//Cal//EN\r\nBEGIN:VEVENT\r\n\
            UID:abc\r\nDTSTAMP:20260101T000000Z\r\n\
            DTSTART:20260102T100000Z\r\nSUMMARY:Lunch\r\n\
            END:VEVENT\r\nEND:VCALENDAR\r\n";

let invite = parse_invite(ics).unwrap();
assert_eq!(invite.method, Method::Request);
assert_eq!(invite.uid, "abc");
assert_eq!(invite.summary, "Lunch");

See examples/parse_invite.rs for a walk-through that parses an invite, prints the typed view, and round-trips it through serialize.

What this crate does NOT do

  • No MIME parsing — extract the text/calendar part upstream (e.g. with mail-parser).
  • No SMTP — see mailrs-smtp-proto / mailrs-smtp-client.
  • No calendar storage, no CalDAV server. This is the wire-format layer only.
  • No RRULE expansion to concrete instances — the parser captures the raw RRULE string; consumers expand with the rrule crate as needed.

Module overview

Module What it does
parse RFC 5545 §3.1 text → raw AST (line folding, property tree, BEGIN/END nesting).
semantics AST → typed [ParsedInvite] (METHOD, ATTENDEE, ORGANIZER, SEQUENCE, RRULE, …).
vtimezone Inline VTIMEZONE handling with chrono-tz IANA fallback.
serialize [ParsedInvite] → RFC 5545 text (for iTIP REPLY).

License

Licensed under either of:

at your option.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.