mailrs-ical
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] withMETHOD/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 coversREQUEST/REPLY/CANCEL/UPDATE/COUNTER/REFRESH/ADD/PUBLISH/DECLINECOUNTERper RFC 5546. - Serializer — [
serialize] turns a [ParsedInvite] back into RFC 5545 text, suitable for iTIPREPLYbodies. - Battle-tested — extracted from a production Rust mail server; verified against a corpus of real
.emlfixtures from Outlook / Nextcloud / Google / Apple Calendar / Thunderbird.
Quick start
use ;
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.unwrap;
assert_eq!;
assert_eq!;
assert_eq!;
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/calendarpart upstream (e.g. withmail-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
rrulecrate 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:
- Apache License, Version 2.0 (LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or https://opensource.org/licenses/MIT)
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.