iCal feed issues in Office 365 and outlook.com



Steps to Reproduce

There is an issue with the MIME type in the webcal generated link that prevents calendar from displaying events when imported into Office 365 calendar; there are similar reports for other calendars on Discourse Meta (Google calendar displays the events regardless).

Steps to reproduce:

  • Grab the webcal link from an Event plugin enabled category.
  • Import webcal link as new calendar into Office 365.
  • New calendar is added but no events are shown.



Here’s the report from the validator:

Invalid MIME type detected, should be ‘text/calendar’ (found MIME type ‘text/plain; charset=utf-8’) near line # 1
Reference: RFC 5545 8.1. iCalendar Media Type Registration


1 Like

Hello @angus what is the ETA on this one?

This bug really prevents me from deploying your plugin into production, so if you could spare a few minutes for this one I would really appreciate it.

Thanks and keep up the good work :heart_eyes:

1 Like

Sure thing. Taking a look…

1 Like

@md-misko This is now fixed :+1:

Example: https://icalendar.org/validator.html?url=https://thepavilion.io/c/public-work/l/calendar.ics?time_zone=Australia/Melbourne

1 Like

Thanks, it works like a charm :heart_eyes:

Hi @angus!

Unfortunately it seems that this was not the root cause after all. The error persists specifically for Office 365 and outlook.com.

I took a deeper look into the contents of the .ics file and I discovered what might be the real culprit: the timezone is declared multiple times, in fact as many times as there are events in the calendar:


This is indicated on the webcal validator, although it is not marked as an syntax error.

File Size: 1161 lines, 32513 bytes
Number of events found: 42
Number of timezones found: 42

Nevertheless this is definitely an issue with Microsoft services, since the manual import of this .ics file fails when imported to outlook.com or Office 365 with the error ‘Content conversion failed’

When imported manually with multiple timezones edited out the import is successful.

I hope this will be an easy fix :smile:

1 Like

It looks that the last line below (line 511 in plugin.rb) is adding new timezone to .ics for every event instead of adding a timezone only once per unique timezone:

      @topic_list.topics.each do |t|
        if t.event && t.event[:start]
          event = CalendarEvents::Helper.localize_event(t.event, tzid)
          timezone = tz.ical_timezone event[:start]
          cal.add_timezone timezone

Unfortunately my Ruby skills are nearly nonexistent so I’m unable to directly submit a PR, hope this helps anyway.

Ok, I’ll take a look at it on Friday.

@md-misko Could you remind me about this on Friday? (Melbourne time GMT +10)

1 Like

@angus Well, I thought I would go one better :smile: I was trying to understand the code and started tinkering with it a little and came up with this (see commented lines):

    def event_ics(opts = {})
      guardian.ensure_can_see!(@category) if @category

      name_prefix = @category ? "#{SiteSetting.title} - #{@category.name}" : SiteSetting.title
      base_url = @category ? @category.url : Discourse.base_url

      calendar_name = "#{name_prefix} #{I18n.t("webcal_description.events")}"
      calendar_url = "#{base_url}/calendar"
      list_opts = {}
      list_opts[:category] = @category.id if @category

      tzid = params[:time_zone]
      tz = TZInfo::Timezone.get tzid

      cal = Icalendar::Calendar.new
      cal.x_wr_calname = calendar_name
      cal.x_wr_timezone = tzid
#added following lines
      event_now = DateTime.now 
      timezone = tz.ical_timezone event_now
      cal.add_timezone timezone

      @topic_list = TopicQuery.new(current_user, list_opts).list_calendar

      @topic_list.topics.each do |t|
        if t.event && t.event[:start]
          event = CalendarEvents::Helper.localize_event(t.event, tzid)
          timezone = tz.ical_timezone event[:start]
#removed following line: only add timezone once
          # cal.add_timezone timezone 

          ## to do: check if working later
          if event[:format] == :date_only
            event[:start] = event[:start].to_date
            event[:end] = event[:end].to_date if event[:end]

          cal.event do |e|
            e.dtstart = Icalendar::Values::DateTime.new event[:start], 'tzid' => tzid
            if event[:end]
              e.dtend = Icalendar::Values::DateTime.new event[:end], 'tzid' => tzid
            e.summary = t.title
#added url to event body: most calendar clients don't display url field
            e.description = t.url << "\n\n" << t.excerpt
            e.url = t.url


      render body: cal.to_ical, formats: [:ics], content_type: Mime::Type.lookup("text/calendar") unless performed?

I tested it locally on my server and on Office 365 and it seems to work as desired.

I have also taken the liberty to add the url to event body, since I haven’t found a single web or app calendar client that displays the url field included in the webcal .ics file.

It works really well for me as a quick back link to the forum, but if you feel it doesn’t belong there, please remove it.

Thanks for all your work on these fantastic plugins, I hope this will lessen your burden a tiny bit :smile:

1 Like

Amazing! If you could make a PR for that I’ll merge it :slight_smile:

1 Like

The test in the example

is failing.


Problem! Found 1 warning


  1. Invalid MIME type detected, should be ‘text/calendar’ (found MIME type ‘text/html; charset=utf-8’) [near line # 1](javascript:void(0);)Reference: RFC 5545 8.1. iCalendar Media Type Registration

Problem! Found 2 errors


  1. This is not an iCalendar file or URL [near line # 1](javascript:void(0);)Reference: RFC 5545 3.4. iCalendar Object
  2. Missing VCALENDAR object [near line # 1](javascript:void(0);)Reference: RFC 5545 3.4 iCalendar Object

Permalink: https://icalendar.org/validator.html?url=https://thepavilion.io/c/public-work/l/calendar.ics?time_zone=Australia/Melbourne

I checked the contents and it’s the login page for the site.
How do we pass an api key with this plugin for an ics feed?

@csmu, Thanks for reporting the issue. We’ll give you an update on this tomorrow(monday). cc @angus

1 Like

I added &api_key={valid-api-key}&api_user={valid-user-name} and it worked!

Cheers and thanks.

1 Like

G’day Faizaan

Adding api credentials sorted it.


That’s great. Do get back if you have more queries :slight_smile: