Add an alert to an event in Ical.net - c#

I am using ical.net to provide outlook internet calendar integration for my solution.
I have several events from 00:00 a.m. to 00:00 a.m. (next day).
When I add an alarm to the events, in Outlook these events show with no alert.
This is the code how I added the alarms and events.
foreach (var taskItem in taskItems.Where(t => t.DueDate != null && t.DueDate.HasValue == true))
{
var hyperlink = Request.GetBaseUrl();
hyperlink = string.Format("{0}/TaskBoard/Tasks?listId={1}", hyperlink, taskItem.ListId);
var dueDate = new DateTime(taskItem.DueDate.Value.Ticks, DateTimeKind.Utc);
var alarm = new Alarm()
{
Summary = taskItem.Title,
Trigger = new Trigger(TimeSpan.FromMinutes(-15)),
Action = AlarmAction.Display
};
var calendarEvent = new Event
{
Class = "PUBLIC",
Summary = taskItem.Title,
Created = new CalDateTime(taskItem.Created.Value),
Description = string.Format("Open board: {0}", hyperlink),
Start = new CalDateTime(dueDate),
End = new CalDateTime(dueDate.AddDays(1)),
Uid = taskItem.Id.ToString(),
Location = taskItem.ListTitle
};
calendarEvent.Alarms.Add(alarm);
calendar.Events.Add(calendarEvent);
}
this is the resulting iCal file content
BEGIN:VCALENDAR
PRODID:-//github.com/rianjs/ical.net//NONSGML ical.net 2.2//EN
VERSION:2.0
X-WR-CALNAME:Agile Kanban - Meine Aufgaben
BEGIN:VEVENT
CLASS:PUBLIC
CREATED:20170814T114839
DESCRIPTION:Open board: https://localhost:44300/TaskBoard/Tasks?listId=637
90e98-cacc-4f03-992f-f3276db06dda
DTEND:20170827T220000Z
DTSTAMP:20170829T170757Z
DTSTART:20170826T220000Z
LOCATION:Room1
SEQUENCE:0
SUMMARY:Task changed
UID:1d4b10bf-7434-41d9-8dd2-311e3679b0a7
BEGIN:VALARM
ACTION:Display
SUMMARY:Task changed
TRIGGER:-PT15M
END:VALARM
END:VEVENT
END:VCALENDAR

How are the event added to Outlook ?
If they are made available as an http subscription, Outlook is probably ignoring it on purpose. How one wants to be notified in advance is a really a personal choice so calendar clients tend to ignore alarms from outside sources, whether added via an invitations (see Sent email with iCal to outlook with valarm reminder ) or via public calendar subscriptions.
If you are doing an import of the task and the alarms still do not show up, there might be a problem with your iCalendar stream so seing the actual iCalendar stream instead of your code would be more useful.
Finally, I vaguely remember Outlook handling only absolute alarms (see https://www.rfc-editor.org/rfc/rfc5545#section-3.8.6.3) for VTODO but I do not know whether it is still the case.

Related

ICAL .NET Remove or Delete Event

I am using https://github.com/rianjs/ical.net with .Net 6 API. I am able to create an event like below.
var calendar = new Calendar();
calendar.AddTimeZone(new VTimeZone("America/Chicago"));
var icalEvent = new CalendarEvent
{
Summary = "David's vacation days",
Description = "Description for event",
Start = new CalDateTime(2022, 12, 12, 15, 0, 0),
End = new CalDateTime(2022, 12, 12, 16, 0, 0)
};
calendar.Events.Add(icalEvent);
var iCalSerializer = new CalendarSerializer();
result = iCalSerializer.SerializeToString(calendar);
This creates a .ics file, opening which creates an event in the calendar.
BEGIN:VCALENDAR PRODID:-//github.com/rianjs/ical.net//NONSGML ical.net 4.0//EN VERSION:2.0 BEGIN:VTIMEZONE TZID:America/Chicago X-LIC-LOCATION:America/Chicago END:VTIMEZONE BEGIN:VEVENT DESCRIPTION:Description for event DTEND:20221212T160000 DTSTAMP:20221213T184639Z DTSTART:20221212T150000 SEQUENCE:0 SUMMARY:David's vacation days UID:4aca19e6-a7a8-426c-a488-c2abf789c395 END:VEVENT END:VCALENDAR
I see that if I edit the file and add METHOD:CANCEL, SEQUENCE:1, it opens in outlook with 'Remove from calendar'.
Now, how to do this remove event programmatically? I am hoping iCAL has something instead of me serializing the event to string and add the method etc. to that string manually.

Is it possible to directly open the Outlook meeting window?

I am trying to have my application to open the Outlook meeting window with some pre-populated fields.
I have found that this question was already asked here.
However, the code provided in the answer(which works fine) doesn't open the meeting window but the appointement window. Those are two different things that are handled differently in Outlook and what I need is indeed the meeting window.
Is there any way to achieve this or do I absolutely have to open the appointement window first and then invite people to turn it into a meeting?
Create an appointment just as in the other question, but then set the MeetingStatus property of the appointment.
Microsoft.Office.Interop.Outlook.Application outlookApplication = new Microsoft.Office.Interop.Outlook.Application(); ;
Microsoft.Office.Interop.Outlook.AppointmentItem appointmentItem = (Microsoft.Office.Interop.Outlook.AppointmentItem)outlookApplication.CreateItem(Microsoft.Office.Interop.Outlook.OlItemType.olAppointmentItem);
// This line was added
appointmentItem.MeetingStatus = Microsoft.Office.Interop.Outlook.OlMeetingStatus.olMeeting;
appointmentItem.Subject = "Meeting Subject";
appointmentItem.Body = "The body of the meeting";
appointmentItem.Location = "Room #1";
appointmentItem.Start = DateTime.Now;
appointmentItem.Recipients.Add("test#test.com");
appointmentItem.End = DateTime.Now.AddHours(1);
appointmentItem.ReminderSet = true;
appointmentItem.ReminderMinutesBeforeStart = 15;
appointmentItem.Importance = Microsoft.Office.Interop.Outlook.OlImportance.olImportanceHigh;
appointmentItem.BusyStatus = Microsoft.Office.Interop.Outlook.OlBusyStatus.olBusy;
appointmentItem.Recipients.ResolveAll();
appointmentItem.Display(true);
One more note to NineBerries good solution, because I had an issue here:
The line
appointmentItem.Recipients.ResolveAll();
is necessary if you have optional attendees in the meeting.
Otherwise they will be reset to "required" even if you set
recipient.Type = Microsoft.Office.Interop.Outlook.OlMeetingRecipientType.olOptional;
before, which is due to "late auto-resolving" of names in Outlook (or so it seems).

iCal Time Zone issue

I'm trying to allow a user to download an iCal for their calendar in ASP.Net, but am having a timezone issue.
If I download the file on my computer, the time appears correct and within the correct timeframe. However, when I try to download it on a phone, the timezone switches and it becomes 5 hours behind (aka 7:00 AM becomes 3:00 AM).
Does anyone know how to fix this issue/set the timezone?
Here is the code:
iCalendar iCal = new iCalendar();
Event evt = iCal.Create<Event>();
DateTime dt = (DateTime)Convert.ToDateTime(lblTicketDue.Text);
Console.Write(dt);
evt.Start = new iCalDateTime(dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second);
evt.End = new iCalDateTime((DateTime)Convert.ToDateTime(lblTicketDue.Text).AddMinutes(15.0));
Alarm alarm = new Alarm();
alarm.Action = AlarmAction.Display;
alarm.Summary = "Ticket due!";
Trigger t = new Trigger();
iCalDateTime icdt = new iCalDateTime(dt.Subtract(TimeSpan.FromMinutes(120.0)));
t.DateTime = icdt;
alarm.Trigger = t;
evt.Alarms.Add(alarm);
iCal.Events.Add(evt);
iCalendarSerializer serializer = new iCalendarSerializer();
string output = serializer.SerializeToString(iCal);
Response.ContentType = "text/calendar";
Response.Write(output);
Response.End();
Hard to tell without looking at the actual iCalendar stream that gets generated but it is quite likely that you are generating your DTSTART/DTEND using floating time (e.g. "20160517T070000" ).
If the event is not recurring (no RRULE), what you want to do is convert your datetime to UTC and use the "date with UTC time" format described in https://www.rfc-editor.org/rfc/rfc5545#section-3.3.5
i.e. something like "20160517Txx0000Z"
If the event is recurring you would then need to use the last form (date with local time and timezone reference).

What is the proper way to serve iCal Events?

I am attempting to allow users to add events from an online calendar to the calendars on their device using DDay.iCal. This seems to work fine on iOS and on desktop platforms, but I am running into a snag with Android devices. I run into this message:
Is there a better way to serve this event that would keep that from happening?
public ActionResult ICS(int id)
{
// Get event from Database
var heEvent = HEEvent.GetEventDetails(id);
// Create iCal object
var iCal = new iCalendar();
iCal.Method = "PUBLISH";
// Create iCal Event
var icalEvent = iCal.Create<DDay.iCal.Event>();
icalEvent.Summary = heEvent.Name;
icalEvent.Start = new iCalDateTime(heEvent.TimeBegin.Year, heEvent.TimeBegin.Month, heEvent.TimeBegin.Day, heEvent.TimeBegin.Hour, heEvent.TimeBegin.Minute, 00);
TimeSpan calculatedEventDuration = heEvent.DateEnd.Subtract(heEvent.TimeBegin);
if (calculatedEventDuration.Hours > 1) { icalEvent.Duration = calculatedEventDuration; }
else { icalEvent.Duration = TimeSpan.FromHours(1); } // default to 1 hour if event time is less
icalEvent.Location = heEvent.Location;
// Create a serialization context and serializer factory.
// These will be used to build the serializer for our object.
ISerializationContext ctx = new SerializationContext();
ISerializerFactory factory = new DDay.iCal.Serialization.iCalendar.SerializerFactory();
// Get a serializer for our object
IStringSerializer serializer = factory.Build(iCal.GetType(), ctx) as IStringSerializer;
string output = serializer.SerializeToString(iCal);
var contentType = "text/calendar";
var bytes = Encoding.UTF8.GetBytes(output);
return File(bytes, contentType, String.Format(#"{0}.ics", heEvent.Name.Replace(" ", "_")));
}
Your error, you don't need me to tell you, has nothing to do with Ical. It's entirely between you, your phone, and your technology budget. (Buy an SD card !)
As regards serving Icalendars, you often hear them called feeds, but clients subscribed to an Icalendar poll the calendar url regularly, requesting the whole calendar each time. To avoid lots of needless processing, you will want to persist the calendar(s) somehow so that changes propagate without regenerating the same calendar thousands of times. For this, I suggest the file system and good use of HTTP caching headers. When your calendar is modified, write it as a static file in a web facing directory. Perhaps you're already doing this. Then set sensible caching headers on your webserver and away you go.

iCal client support for multiple event requests

When a user signs up on our website, I'd like to send them an email that allows them to automatically update their calendar with the classes they have enrolled in. In most cases this will be multiple days/events.
As a test I'm using DDay.ical to create a multi-event request. However, it doesn't seem like either Outlook or the iPhone mail app notices the second event in the ical attachment.
I know that multiple events are supported in the iCal standard. How that doesn't mean that all clients support that scenarios. Do other clients support multi-event ical requests?
I don't think I'm doing anything wrong in code, but I'll post my code fragment to be sure:
// Create event part.
iCalendar iCal1 = new iCalendar();
iCal1.AddLocalTimeZone();
iCal1.Method = "REQUEST";
Event evt1 = iCal1.Create<Event>();
evt1.Start = new iCalDateTime(new DateTime(2014, 8, 4, 12, 30, 00, DateTimeKind.Local));
evt1.End = evt1.Start.AddMinutes(30);
evt1.IsAllDay = false;
evt1.Summary = string.Format("Lesson - {0}", evt1.Start.ToString("MM/dd"));
evt1.Location = "Anytown";
// Add recipients for appointment.
Attendee att1 = new Attendee("mailto:" + "me#MyDomain.com");
att1.RSVP = false;
att1.CommonName = "Me Jones";
evt1.Attendees.Add(att1);
Event evt2 = iCal1.Create<Event>();
evt2.Start = new iCalDateTime(new DateTime(2014, 8, 11, 12, 30, 00, DateTimeKind.Local));
evt2.End = evt1.Start.AddMinutes(30);
evt2.IsAllDay = false;
evt2.Summary = string.Format("Lesson - {0}", evt2.Start.ToString("MM/dd"));
evt2.Location = "AnyTown";
// Add recipients for appointment.
Attendee att2 = new Attendee("mailto:" + "me#MyDomain.com");
att2.RSVP = false;
att2.CommonName = "Me Jones";
evt2.Attendees.Add(att2);
iCalendarSerializer serializer1 = new iCalendarSerializer();
string t = serializer1.SerializeToString(iCal1);
Byte[] bytes = System.Text.Encoding.ASCII.GetBytes(t);
using (var ms = new System.IO.MemoryStream(bytes))
{
using (var a = new System.Net.Mail.Attachment(ms, "meeting.ics", "text/calendar")) //Either load from disk or use a MemoryStream bound to the bytes of a String
{
a.ContentDisposition.Inline = true; //Mark as inline
msg.Attachments.Add(a); //Add it to the message
Mailer.Send(msg);
}
}
Unfortunately, you're completely dependent on the implementation of Icalendar in the various email clients, and these are generally very protective of their users' calendars. They generally all support multi-event Icalendars, but invitations that "go straight in" to a users calendar have to be sent one event at a time. I'm not aware of any exceptions to this.
To process an Icalendar attachment containing more than one event, in Outlook for example, you need to save the attachment to disk, navigate to it and open it. It then opens as a separate calendar, and you need to drag the events one by one into your calendar. Nightmare. This will rarely be worth the trouble to develop.
Another option of course is to host the Icalendar on your website and get your users to subscribe by entering the calendar URL in their client. This has the advantage that changes propagate automatically, but email clients will still treat the events as external (no automatic reminders, in outlook the default is to display them in a separate pane, Gmail at least displays events from different calendars on the same grid.)

Categories