Ben van Erp
Ben van Erp

Reputation: 33

Is it possible to create calendar events with attachments?

I want to create a calendar event using Microsoft Graph and this is working but unfortunately, I'm not able to add attachments to the event. The event is created but without the attachments. No error is reported.

This is my code:

DateTimeTimeZone start = new DateTimeTimeZone
{
    TimeZone = TimeZoneInfo.Local.Id,
    DateTime = dateTimePicker1.Value.ToString("o"),
};

DateTimeTimeZone end = new DateTimeTimeZone
{
    TimeZone = TimeZoneInfo.Local.Id,
    DateTime = dateTimePicker2.Value.ToString("o"),
};

Location location = new Location
{
    DisplayName = "Thuis",
};

byte[] contentBytes = System.IO.File
    .ReadAllBytes(@"C:\test\sample.pdf");

var ev = new Event();

FileAttachment fa = new FileAttachment
{
    ODataType = "#microsoft.graph.fileAttachment",
    ContentBytes = contentBytes,
    ContentType = "application/pdf",
    Name = "sample.pdf",
    IsInline = false,
    Size = contentBytes.Length
};

ev.Attachments = new EventAttachmentsCollectionPage();
ev.Attachments.Add(fa);

ev.Start = start;
ev.End = end;
ev.IsAllDay = false;
ev.Location = location;
ev.Subject = textBox2.Text;

var response = await graphServiceClient
    .Users["[email protected]"]
    .Calendar
    .Events
    .Request()
    .AddAsync(ev);

Upvotes: 3

Views: 2593

Answers (3)

nzrysldg
nzrysldg

Reputation: 1

You can share a file from OneDrive within the event by creating a sharing link.

If the file is not in OneDrive, you have to upload the file to OneDrive first. Afterwards, you can create a sharing link and present the attachement to the attendees(with access granted) in the event body.

public async Task<DriveItem> uploadFileToOneDrive(string eventOwnerEmail, string filePath, string fileName)
{
    // get a stream of the local file
    FileStream fileStream = new FileStream(filePath, FileMode.Open);

    string token = GetGraphToken();

    var graphServiceClient = new GraphServiceClient(new DelegateAuthenticationProvider((requestMessage) =>
    {
        requestMessage
            .Headers
            .Authorization = new AuthenticationHeaderValue("bearer", token);

        return Task.FromResult(0);
    }));


    // upload the file to OneDrive
    var uploadedFile = graphServiceClient.Users[eventOwnerEmail].Drive.Root
                                  .ItemWithPath(fileName)
                                  .Content
                                  .Request()
                                  .PutAsync<DriveItem>(fileStream)
                                  .Result;

    return uploadedFile;
}


public async Task<Permission> getShareLinkOfDriveItem(string eventOwnerEmail, DriveItem _item)
{
    string token = GetGraphToken();

    var graphServiceClient = new GraphServiceClient(new DelegateAuthenticationProvider((requestMessage) =>
    {
        requestMessage
            .Headers
            .Authorization = new AuthenticationHeaderValue("bearer", token);

        return Task.FromResult(0);
    }));    
    
    var type = "view";
    var scope = "anonymous"; 

    var ret = await graphServiceClient.Users[eventOwnerEmail].Drive.Items[_item.Id]
                                .CreateLink(type, scope, null, null, null)
                                .Request()
                                .PostAsync();


    return ret;
}

you can call methods from your program as below:

var driveItem = uploadFileToOneDrive(eventOwnerEmail, filePath, fileName);
Task<Permission> shareLinkInfo = getShareLinkOfDriveItem(eventOwnerEmail, driveItem);

string shareLink = shareLinkInfo.Result.Link.WebUrl;

you can attach shared file to event body as below:

 body = "<p>You can access the file from the link: <a href = '" + shareLink  + "' >" + driveItem.Name + " </a></p> "; 

Upvotes: 0

Guilherme Flores
Guilherme Flores

Reputation: 399

I discovered that if you create the event without attendees, than create the attachment and update the event with the attendees they'll receive the event e-mail with all the attachments.

I'm using HTTP put shouldn't be a problem to change it to GRAPH SDK.

That's my code:

var eventContainer = new EventContainer();
eventContainer.Init(); //populate the event with everything except the attendees and attachments        

//Send POST request and get the updated event obj back
eventContainer = GraphUtil.CreateEvent(eventContainer);

//Create a basic attachment
var attachment = new Attachment
{
      ODataType = "#microsoft.graph.fileAttachment",
      contentBytes = Convert.ToBase64String(File.ReadAllBytes(path)),
      name = $"attachment.pdf"
};

//Post request to create the attachment and get updated obj back
attachment = GraphUtil.CreateAttachment(attachment);

//Prepare new content to update the event
var newContent = new
{
       attachments = new List<Attachment> { attachment },
       attendees = New List<Attendee> { attends } //populate attendees here
};

//Patch request containing only the new content get the updated event obj back.
eventContainer = GraphUtil.UpdateEvent(newContent);

If you send the attachment after send the event, the attendees can only see the attachment on their calendar event, and not on the event e-mail that asks their confirmation.

e-mail with attachment

Upvotes: 1

Vadim Gremyachev
Vadim Gremyachev

Reputation: 59348

It appears it still not supported to create an event along with attachments within a single request (a similar issue)

As a workaround, an event without attachments could be created first and then attachments added into it (requires two requests to the server), for example:

var ev = new Event
{
    Start = start,
    End = end,
    IsAllDay = false,
    Location = location,
    Subject = subject
};

//1.create an event first 
var evResp = await graphServiceClient.Users[userId].Calendar.Events.Request().AddAsync(ev);

byte[] contentBytes = System.IO.File.ReadAllBytes(localPath);
var attachmentName = System.IO.Path.GetFileName(localPath);
var fa = new FileAttachment
{
    ODataType = "#microsoft.graph.fileAttachment",
    ContentBytes = contentBytes,
    ContentType = MimeMapping.GetMimeMapping(attachmentName),
    Name = attachmentName,
    IsInline = false
};

//2. add attachments to event
var faResp = await graphServiceClient.Users[userId].Calendar.Events[evResp.Id].Attachments.Request().AddAsync(fa);

Upvotes: 1

Related Questions