RFC Standards Explained: vCard, iCalendar, and Syslog Examples

Last edited: 2026-08-06 09:44:12

Thumbnail

Almost every file your software writes to disk and every packet it puts on the wire is described somewhere in a Request for Comments document. RFCs are the specifications that let a calendar written by one vendor open correctly in another, and let a log line emitted by a router be parsed by a collector nobody coordinated with. This article walks through what an RFC is, how the documents are structured, and then reads three of them properly: RFC 6350 (vCard), RFC 5545 (iCalendar), and RFC 5424 (syslog).

What an RFC Actually Is

The series began in April 1969, when Steve Crocker published RFC 1, "Host Software", as a deliberately informal note among the handful of people building ARPANET. The name was chosen to sound unofficial. Nobody wanted to appear to be issuing decrees, so they asked for comments instead. Nearly six decades later the name has stuck, even though the series now carries the core specifications of the internet: IP, TCP, DNS, HTTP, TLS, and the file formats built on top of them.

Today RFCs are published by the RFC Editor, and most of the ones engineers care about come out of the IETF (Internet Engineering Task Force) after a working group has hammered out a draft and rough consensus has been reached. Two properties make the series unusually pleasant to work with:

  • RFCs are free and permanent. There is no paywall, no membership, and no login. Compare this with ISO or IEEE, where a single specification can cost several hundred dollars.
  • RFCs are immutable. A published RFC is never edited. If the specification changes, a new RFC is published that updates or obsoletes the old one. RFC 5545 obsoletes RFC 2445; RFC 9110 obsoletes RFC 7230. The old document stays online forever, which means a citation never rots.

That immutability has a practical consequence: the first thing to check when opening any RFC is the banner at the top of the page saying whether it has been obsoleted by something newer. Plenty of production bugs come from implementing a specification that was superseded a decade earlier.

Not Every RFC Is a Standard

This trips people up constantly. "It's in an RFC" does not mean "it is a standard". Every RFC carries a status:

  • Standards Track — Proposed Standard, then Internet Standard. Only a small fraction ever reaches full Internet Standard; most widely deployed protocols sit at Proposed Standard forever and that is completely normal.
  • Informational — describes something without endorsing it. RFC 3164, the old BSD syslog document, is Informational: it documents what implementations were already doing rather than prescribing what they should do.
  • Experimental — published to let people try an idea.
  • Best Current Practice (BCP) — operational guidance rather than protocol definition.
  • Historic — formally retired.

And then there is the 1st of April series, which contains RFC 1149 (IP over avian carriers) and RFC 2324 (the Hyper Text Coffee Pot Control Protocol, source of HTTP status code 418). These are jokes, but they are numbered, permanent, and formatted exactly like the real ones, which is very much part of the joke.

MUST, SHOULD, and MAY

Before reading any specification it is worth internalising RFC 2119, which defines the requirement keywords used throughout the series. Clarified later by RFC 8174, the rule is that these words carry their special meaning only when written in capitals:

  • MUST / REQUIRED / SHALL — an absolute requirement. Violating it makes the implementation non-conformant.
  • SHOULD / RECOMMENDED — there may be valid reasons to ignore this, but the full implications have to be understood first.
  • MAY / OPTIONAL — genuinely optional. Critically, an implementation that does not include an optional feature MUST still interoperate with one that does.

Most interoperability failures in the wild come from reading a SHOULD as a MUST, or a MUST as a suggestion. When a parser rejects a file that a competing parser accepts, the argument is nearly always about one of these words.

Example 1 — RFC 6350: The vCard Format

vCard is the format behind the .vcf files that phones and address books exchange. Its history is a good illustration of how specifications migrate into the RFC series: version 2.1 was published in 1996 by the versit consortium and was never an RFC at all. Version 3.0 arrived as RFC 2425 and RFC 2426 in 1998, and version 4.0 was published as RFC 6350 in 2011.

The format is a flat sequence of content lines, each of the form NAME;PARAM=value:VALUE:

BEGIN:VCARD
VERSION:4.0
FN:Ada Lovelace
N:Lovelace;Ada;;;
EMAIL;TYPE=work:ada@example.org
TEL;VALUE=uri;TYPE="voice,cell":tel:+46-70-123-4567
END:VCARD

A few design decisions in RFC 6350 are worth pointing out, because they recur in every text-based format the IETF has produced:

  • VERSION is mandatory and must come first, immediately after BEGIN:VCARD. A parser needs to know which grammar it is dealing with before it reads anything else.
  • Structured values are semicolon-delimited within a single property. The N property above carries five components (family, given, additional, prefixes, suffixes), which is why it ends with a run of empty fields.
  • Lines are folded at 75 octets. A long line is broken and continued on the next line, which begins with a single space or tab. Note that the limit is octets, not characters, so a folding implementation must not split a multi-byte UTF-8 sequence.
  • Version 4.0 relaxed the requirements. N is no longer mandatory, leaving FN (the formatted display name) as the only required name property, which suits organisations and single-name entities much better.

The version differences matter in practice, because an address book that only understands 3.0 will choke on 4.0 constructs like the geo: and tel: URI values. The vCard specification breakdowns at vcfconverter.com lay the three versions out property by property, which is a faster way to check a specific field than diffing the RFCs by hand.

Example 2 — RFC 5545: The iCalendar Format

iCalendar (.ics) is the format behind every meeting invitation and calendar subscription feed. RFC 5545 obsoleted RFC 2445 in 2009, and it shares an obvious family resemblance with vCard: the same BEGIN/END block structure, the same content-line grammar, the same 75-octet folding rule. That is not a coincidence, as both descend from the same MIME directory-profile work.

BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp//Scheduler 1.0//EN
BEGIN:VEVENT
UID:19970901T130000Z-123401@example.com
DTSTAMP:20260806T090000Z
DTSTART;TZID=Europe/Stockholm:20260810T130000
DTEND;TZID=Europe/Stockholm:20260810T140000
SUMMARY:Design review
RRULE:FREQ=WEEKLY;BYDAY=MO;COUNT=8
END:VEVENT
END:VCALENDAR

Where iCalendar gets genuinely hard is time. The specification permits three distinct forms of date-time value, and confusing them is the single most common source of calendar bugs:

  1. Floating time20260810T130000, no timezone at all. Means 13:00 wherever the reader happens to be. Correct for a birthday, wrong for a meeting.
  2. UTC20260810T130000Z, with the trailing Z. Unambiguous.
  3. Local time with a timezone referenceDTSTART;TZID=Europe/Stockholm:20260810T130000. This is the form required for recurring meetings, because a weekly 13:00 event must stay at 13:00 across a daylight-saving transition rather than drifting by an hour. It also means the file MUST contain a matching VTIMEZONE component defining that identifier.

The other requirements that generators routinely get wrong are UID and DTSTAMP on every event (both mandatory), CRLF line endings rather than bare LF, and RRULE recurrences that illegally combine UNTIL with COUNT. Anyone writing an ICS generator will recognise this list, and the RFC 5545 conformance checks documented by icsfile.com are a useful catalogue of exactly which of them break real calendar clients.

Example 3 — RFC 5424: The Syslog Protocol

The first two examples are file formats. Syslog is a wire protocol, and it demonstrates a different RFC pattern: what happens when a specification is written after a de-facto standard has already spread everywhere.

Syslog started life in the 1980s as part of Eric Allman's sendmail and was never designed as such. By 2001 it was so ubiquitous that RFC 3164 was published simply to write down what implementations were observed to do. The document is explicitly Informational and, in its own words, describes observed behaviour rather than prescribing a format. It produces messages like:

<34>Oct 11 22:14:15 mymachine su: 'su root' failed for lonvick

That timestamp has no year, no timezone, and no sub-second precision, and the su: tag is a loose convention rather than a defined field. Parsing it reliably across vendors is miserable.

RFC 5424 replaced it in 2009 with a strictly ordered header:

<34>1 2003-10-11T22:14:15.003Z mymachine.example.com su - ID47 - 'su root' failed

The fields are, in order: priority, version, timestamp, hostname, app-name, process ID, message ID, structured data, and the message itself. Three details make it far more machine-friendly than its predecessor:

  • The timestamp is RFC 3339, so it carries a year, an explicit offset, and optional fractional seconds. (This is a nice illustration of how RFCs compose: rather than redefining a date format, RFC 5424 simply cites the one that already exists.)
  • Absent values are explicitly nil. A missing field is written as a single hyphen, as with the process ID and structured data above. There is no ambiguity between "empty" and "not present".
  • Structured data is machine-readable. [origin ip="10.0.0.4"] carries key-value pairs directly, and vendors namespace custom identifiers with their IANA private enterprise number (exampleSDID@32473) so two vendors cannot collide.

The priority value in angle brackets is not arbitrary either. It packs two numbers into one integer:

PRI=facility×8+severity, \text{PRI} = \text{facility} \times 8 + \text{severity},

where facility runs from 0 (kernel) to 23 (local7) and severity from 0 (emergency) to 7 (debug). So <34> decomposes as facility 4 (security/authorization) and severity 2 (critical), while the very common <14> is facility 1 (user) at severity 6 (informational). A field-by-field walkthrough of the modern format, including the structured-data grammar, is maintained at syslog.tools, and it is a quicker reference than section 6 of the RFC when debugging a parser at three in the morning.

The Patterns Underneath All Three

Read enough RFCs and the same structural decisions keep reappearing:

A formal grammar, usually ABNF. RFC 5234 defines Augmented Backus-Naur Form, and most specifications include a complete ABNF section. When prose and grammar seem to disagree, the grammar is normative. If you are writing a parser, the ABNF section is the part to read first and the prose is commentary.

An explicit extension mechanism. vCard and iCalendar both allow X- prefixed properties for private use; syslog allocates namespaced structured-data identifiers. Formats without a defined extension point get extended anyway, just incompatibly.

IANA registries instead of hardcoded lists. Rather than freezing the set of valid values in the document, RFCs delegate to a registry that IANA maintains. This is why new media types or new syslog structured-data identifiers can appear without republishing anything.

Text over binary, and octets over characters. All three formats are line-oriented UTF-8 text, and all three specify limits in octets. That distinction is where multilingual data tends to break.

Security Considerations, always. Every RFC is required to have this section. It is regularly the most interesting part, and in the case of calendar and contact formats it is where the specification is candid about what a malicious file can do to a parser.

How to Read an RFC Without Reading All of It

RFCs are long, but they are consistently organised, so you rarely need to read one end to end:

  1. Check the header block for the status and, most importantly, for "Obsoleted by" or "Updated by".
  2. Read the abstract, which is a genuine summary and typically one paragraph.
  3. Jump to the ABNF or grammar section if you are implementing. This is usually where the actual answer to your question lives.
  4. Skim the IANA Considerations to find out where the extensible parts are registered.
  5. Read the Security Considerations before shipping anything that parses untrusted input.
  6. Check the errata. The RFC Editor maintains a public errata database per document, and since the RFC text itself can never be corrected, known mistakes only ever live there. Widely implemented specifications often have verified errata that materially change the meaning of a paragraph.

Given how much software is written against a vague memory of how a format works rather than the document that defines it, an hour with the actual specification is usually the cheapest debugging any team can do.

Sources and Further Reading

Was the post useful? Feel free to donate!

DONATE