After some investigations I found, that Google API does not work as expected with your personal account @gmail.com. You should have organization domain account in Google in format you@your_organisation_domain
Then, what is also pretty confusing, there is documentation at Google Drive API page, with "Delegate domain-wide authority to your service account" section not mentioned at Calendar API page.
There are 7 steps in the section, are required to be done.
BTW with personal account administration site admin.google.com is even unavailable. So it's impossible to perform these 7 steps with @gmail.com account.
Then, when client is authorised in Google Apps Admin Console > Security > Advanced settings > Manage OAuth Client access the code starts to work.
There is a code that works for me:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using Google.Apis.Calendar.v3;
using Google.Apis.Calendar.v3.Data;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;
namespace CrmToGoogleCalendar
{
class Program
{
static void Connect()
{
Console.WriteLine("Calendar via OAuth2 Service Account Sample");
var certificate = new X509Certificate2("My MC Project-3f38defdf4e4.p12", "notasecret", X509KeyStorageFlags.Exportable);
var serviceAccountEmail = "795039984093-c6ab1mknpediih2eo9cb70mc9jpu9h03@developer.gserviceaccount.com";
var userAccountEmail = "me@testdomain.com";
var credential = new ServiceAccountCredential(new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
User = userAccountEmail,
Scopes = new[] { CalendarService.Scope.Calendar }
}
.FromCertificate(certificate));
var service = new CalendarService(new BaseClientService.Initializer()
{
ApplicationName = "Test calendar sync app",
HttpClientInitializer = credential
});
/* Get list of calendars */
var calList = service.CalendarList.List().Execute().Items;
var myCalendar = calList.First(@c => @c.Id == userAccountEmail);
/* CREATE EVENT */
var event1 = new Event()
{
Kind = "calendar#event",
Summary = "Calendar event via API",
Description = "Programmatically created",
Status = "confirmed",
Organizer = new Event.OrganizerData() {
Email = userAccountEmail
},
Start = new EventDateTime()
{
DateTime = DateTime.Now.AddDays(1)
},
End = new EventDateTime()
{
DateTime = DateTime.Now.AddDays(1).AddHours(1)
},
ColorId = "6",
Reminders = new Event.RemindersData()
{
UseDefault = false,
Overrides = new List<EventReminder>(
new [] {
new EventReminder()
{
Method = "popup",
Minutes = 60
}
})
}
};
event1 = service.Events.Insert(event1, myCalendar.Id).Execute();
Console.WriteLine("Created event Id: {0}", event1.Id);
/* ENLIST EVENTS */
Console.WriteLine("calendar id={0}", myCalendar.Id);
var events = service.Events.List(myCalendar.Id).Execute();
foreach (var @event in events.Items)
{
Console.WriteLine("Event ID: {0}, ICalUID: {1}", @event.Id, @event.ICalUID);
Console.WriteLine(" Name: {0}", @event.Summary);
Console.WriteLine(" Description: {0}", @event.Description);
Console.WriteLine(" Status: {0}", @event.Status);
Console.WriteLine(" Color: {0}", @event.ColorId);
Console.WriteLine(" Attendees: {0}", @event.Attendees == null ? "" : @event.Attendees.Select(a => a.Email).ToString());
Console.WriteLine(" Kind: {0}", @event.Kind);
Console.WriteLine(" Location: {0}", @event.Location);
Console.WriteLine(" Organizer: {0}", @event.Organizer.Email);
Console.WriteLine(" Recurrence: {0}", @event.Recurrence == null ? "no recurrence" : String.Join(",", @event.Recurrence));
Console.WriteLine(" Start: {0}", @event.Start.DateTime == null ? @event.Start.Date : @event.Start.DateTime.ToString());
Console.WriteLine(" End: {0}", @event.End.DateTime == null ? @event.End.Date : @event.End.DateTime.ToString());
Console.WriteLine(" Reminders: {0}", @event.Reminders.UseDefault.Value ? "Default" : "Not defailt, " +
(@event.Reminders.Overrides == null ? "no overrides" : String.Join(",", @event.Reminders.Overrides.Select(reminder => reminder.Method + ":" + reminder.Minutes)))
);
Console.WriteLine("=====================");
}
Console.ReadKey();
}
static void Main(string[] args)
{
Connect();
}
}
}
The output produced looks so:
Calendar via OAuth2 Service Account Sample
Created event Id: jkits4dnpq6oflf99mfqf1kdo0
calendar id=me@testdomain.com
Event ID: 1logvocs77jierahutgv962sus, ICalUID: 1logvocs77jierahutgv962sus@google.com
Name: test event
Description: test description2
Status: confirmed
Color:
Attendees:
Kind: calendar#event
Location: location2
Organizer: me@testdomain.com
Recurrence: RRULE:FREQ=WEEKLY;BYDAY=TH
Start: 2014-07-31
End: 2014-08-01
Reminders: Not defailt, email:10,popup:10
=====================
Event ID: 1logvocs77jierahutgv962sus_20140814, ICalUID: 1logvocs77jierahutgv962sus@google.com
Name: test event updated
Description: test description2
Status: confirmed
Color:
Attendees:
Kind: calendar#event
Location: location2
Organizer: me@testdomain.com
Recurrence: no recurrence
Start: 2014-08-14
End: 2014-08-15
Reminders: Not defailt, email:10
=====================
Event ID: 974hqdhh8jhv5sdobkggmdvvd8, ICalUID: 974hqdhh8jhv5sdobkggmdvvd8@google.com
Name: One hour event
Description: test description
Status: confirmed
Color: 7
Attendees:
Kind: calendar#event
Location: Meeting Room Hire, Broadway, 255 The Bdwy, Broadway, NSW 2007, Australia
Organizer: me@testdomain.com
Recurrence: no recurrence
Start: 1/08/2014 10:00:00 AM
End: 1/08/2014 11:00:00 AM
Reminders: Default
=====================
Event ID: jkits4dnpq6oflf99mfqf1kdo0, ICalUID: jkits4dnpq6oflf99mfqf1kdo0@google.com
Name: Calendar event via API
Description: Programmatically created
Status: confirmed
Color: 6
Attendees:
Kind: calendar#event
Location:
Organizer: me@testdomain.com
Recurrence: no recurrence
Start: 2/08/2014 12:30:50 PM
End: 2/08/2014 1:30:50 PM
Reminders: Not defailt, popup:60
=====================
First event is recurrent weekly whole day event series.
Second is updated single event of the first (has the same UID).
Third is single event for one hour.
The last is created by code above.
Hope this will help others to economy their time.