Utilo

ICS MIME Type – Free, Online, Private

text/calendar is the type for an iCalendar file. The body starts with BEGIN:VCALENDAR and is not JSON.

What .ics is

iCalendar is a text format for events, to-dos, and journal entries. A file starts with BEGIN:VCALENDAR and ends with END:VCALENDAR. Lines are name-value pairs. A line that is too long is folded by a CRLF followed by a space. RFC 5545 requires CRLF as the line break, which surprises generators that write LF only. The registered type is text/calendar. The method parameter, such as text/calendar; method=REQUEST, tells a client the scheduling operation. A published calendar file often omits method or uses PUBLISH. .ics is the extension. .ifb for free/busy is a different file and still this type when you serve it.

IANA registers text/calendar in RFC 5545. The media type is text/calendar. Extensions that use it on this page: .ics. A client compares the type, not the filename, once the response has arrived. The filename still matters on disk and in Content-Disposition, which is why a wrong extension and a wrong header are two different bugs.

What sends text/calendar

What sends text/calendar: Send text/calendar; charset=utf-8 for a download and for a feed a calendar client polls. Add a filename in Content-Disposition. Some clients ignore the URL path. If the calendar is a meeting request, set method=REQUEST and build a real iTIP message. A file of events to import is usually method=PUBLISH or no method. Do not send application/json to a calendar button and expect an import. Do not send text/calendar for a JSON API that happens to represent events. Cache a public calendar with a short max-age if the events change. A long cache is how a cancelled meeting stays on someone's phone. The file on disk is still .ics. Once the response exists, a client trusts text/calendar, not the filename. If you offer a webcal: link, the scheme is a hint to open a client. The response after the client fetches it is still HTTPS with text/calendar. The scheme does not change the media type and does not bypass authentication.

Content-Type for .ics

Send text/calendar; charset=utf-8. The charset parameter names the encoding of the body. Leaving it off forces the client to guess, and for several text types the registered default is not UTF-8. Do not send a charset on a redirect. The header belongs on the response that contains the bytes.

Content-TypeContent-Type: text/calendar; charset=utf-8

nginx, Apache, and Express

These snippets map .ics to text/calendar. nginx reads the types block when it picks a type from the URL's extension. A location that sets default_type, or an application that sets the header itself, overrides that map. Apache AddType applies in the directory context where you put it. The Express static example writes the header for files ending in .ics so a stale mime database in the framework cannot disagree with the type on this page.

nginx# /etc/nginx/mime.types, inside the types { } block
text/calendar               ics;
charset utf-8;
charset_types text/calendar;
ApacheAddType text/calendar .ics
AddCharset UTF-8 .ics
Expressimport express from "express";

const app = express();
app.use(express.static("public", {
  setHeaders(res, filePath) {
    if (filePath.endsWith(".ics")) {
      res.setHeader("Content-Type", "text/calendar; charset=utf-8");
    }
  },
}));

Pitfalls for text/calendar

Pitfalls that show up for text/calendar, and not for a neighboring type with a similar extension: LF-only line endings are the bug that makes a file open in one client and vanish in another. Write CRLF. Folded lines that forget the leading space on the continuation are the next bug. Another is a timezone floating in the file with no VTIMEZONE component, so the event shifts when the client guesses. Another is treating the file as HTML-safe because it is text. DESCRIPTION can contain characters you must escape with iCalendar escaping, which is not HTML escaping. A fifth is a subscription URL that redirects to an HTML login page with status 200. The client imports nothing and may cache the HTML under the calendar URL if you also got the type wrong.

  • text/calendar is the type. application/ics is not registered.
  • method=REQUEST and a PUBLISH file are different operations. Do not copy the parameter from a snippet that was a meeting invitation.
  • UTF-8 is what you want. The old default in the calendar world has a long history. Send the charset.
  • A BOM before BEGIN breaks strict parsers. Start at B.

Frequently asked questions

What is the first line?

BEGIN:VCALENDAR. The file ends with END:VCALENDAR. Line breaks are CRLF.

Which charset?

UTF-8. Send text/calendar; charset=utf-8.

What does the method parameter do?

It names the scheduling operation, such as REQUEST or PUBLISH. A plain export can omit it. A meeting invitation should not.

Is application/ics valid?

No. The registered type is text/calendar.