5

I have been using Microsoft Graph .NET Client Library to send mail messages for quite a while and it's been working great but today I noticed a very strange problem.

As of today here are the basic rules for attachments...

  • If the file size is under 3 MB, do a single POST on the attachments navigation property of the Outlook item; see how to do this for a message or for an event. The successful POST response includes the ID of the file attachment.
  • If the file size is between 3MB and 150MB, create an upload session, and iteratively use PUT to upload ranges of bytes of the file until you have uploaded the entire file. A header in the final successful PUT response includes a URL with the attachment ID.

https://learn.microsoft.com/en-us/graph/outlook-large-attachments?tabs=http

So pretty simple. If the attachment is less than 3 MB I simply include it with the message. If it's more then I create an upload session.

Now for the problem. If there are multiple attachments that add up to a total size that is over that limit I receive the following message...

The maximum request length supported is 4MB.

To try and work around this I started upload sessions for the rest of the files after the cumulative limit was hit. However, I then received the following error message...

Message: Attachment size must be greater than the minimum size.

This is because there is a minimum size for upload sessions.

Quick recap: I cannot upload multiple small attachments when the total exceeds the maximum limit. I can't upload them with a session because it is less than the minimum limit. Has anyone noticed this problem?

Using Microsoft Graph Client Library v3.6

  • (1) Can you please get the response id, timestamp of the error response? (2) Also please see if you can repro the issue with POSTMAN as well – Dev Sep 29 '20 at 15:33
  • Code: BadRequest Message: The maximum request length supported is 4MB. Inner error: AdditionalData: date: 2020-09-29T19:20:04 request-id: 564706e7-9ea1-4b94-bc0c-b8f556ffd9ca – PeerlessProgrammer Sep 30 '20 at 14:16
  • I have not tried it in POSTMAN since I'm able to test every combination using .NET code. Thanks – PeerlessProgrammer Sep 30 '20 at 14:17
  • Also, this exact same code had been working for a few months and just started having the problem 3 days ago. So I'm wondering if it's something on Microsoft's end that they changed. I would love for someone from the Microsoft Graph team to weigh in on this? – PeerlessProgrammer Sep 30 '20 at 16:04
  • Are you still able to reproduce the issue. If so, please get us the latest accurate requestid and time stamp. – Shiva Keshav Varma Oct 15 '20 at 11:43
  • Because of my backlog of work and deadlines I ended up just creating a work around. Basically I categorize the files into small (< 3MB) and large (=> 3MB). If the accumulated total of small files adds up to less than 3 MB I attach them to the message. If they add up to 3 MB or more I compress them into one zip file and send them using an upload session. For large files I continue to send them in a separate upload session. – PeerlessProgrammer Oct 19 '20 at 11:47

2 Answers2

3

The below code works for the total > 4 Mb:

Message draft = await _GraphClient
                        .Users[UserPrincipalNameOrId]
                        .MailFolders
                        .Drafts
                        .Messages
                        .Request()
                        //.WithMaxRetry(5)
                        .AddAsync(emailToSend);

foreach (var attachment in Attachments)
{
    if (attachment.FullPath != null)
    {
        FileInfo f = new FileInfo(attachment.FullPath);
        if (f.Length < MINIMUM_SIZE_FOR_UPLOAD_SESSION) // 3 Mo
        {
            string mimeType = MimeTypes.MimeTypeMap.GetMimeType(f.Extension); 
            FileAttachment fileAttachment = new FileAttachment
            {
                ODataType = "#microsoft.graph.fileAttachment",
                ContentBytes = System.IO.File.ReadAllBytes(attachment.FullPath),
                ContentType = mimeType,
                ContentId = f.Name, 
                Name = f.Name
            };
            await _GraphClient
                    .Users[UserPrincipalNameOrId]
                    .Messages[draft.Id]
                    .Attachments
                    .Request()
                    .AddAsync(fileAttachment);
        }
        else
        {
            // Attachments >= 3 Mb
            using (var filestream = System.IO.File.Open(attachment.FullPath, System.IO.FileMode.Open, FileAccess.Read, FileShare.None))
            {
                var attachmentItem = new AttachmentItem
                {
                    AttachmentType = AttachmentType.File,
                    Name = Path.GetFileName(filestream.Name),
                    Size = filestream.Length
                };

                var uploadSession = await _GraphClient
                        .Users[UserPrincipalNameOrId]
                        .Messages[draft.Id]
                        .Attachments
                        .CreateUploadSession(attachmentItem)
                        .Request()
                        .PostAsync();

                var maxSliceSize = 320 * 1024; // 320 KB - Change this to your slice size. 5MB is the default.
                var largeFileUploadTask = new LargeFileUploadTask<FileAttachment>(uploadSession, filestream, maxSliceSize);

                // upload away with relevant callback
                IProgress<long> progressCallback = new Progress<long>(prog => { });
                try
                {
                    var uploadResult = await largeFileUploadTask.UploadAsync(progressCallback);
                    if (!uploadResult.UploadSucceeded)
                    {
                        // error
                    }
                }
                catch (ServiceException e)
                {
                    // exception
                }
            } // using()
        }
    }
}

await _GraphClient
        .Users[UserPrincipalNameOrId]
        .Messages[draft.Id]
        .Send()
        .Request()
        .WithMaxRetry(5)
        .PostAsync();
SyLaDe
  • 77
  • 11
  • This checks the size of each individual file. Each file could be less than 3 mb, but the total can exceed 4 mb. The OP is talking about the total size of attachments. – user79284 Sep 22 '22 at 18:36
  • Hello @SyLaDe, what are the permission need for the above approach , I believe `Mail.ReadWrite` & `Mail.Send` – JackFrost Sep 28 '22 at 14:28
  • Hello @JackForst. Yes Mail.ReadWrite & Mail.Send – SyLaDe Dec 15 '22 at 13:09
0

Not sure if this will work. But you could try to save the email as a template and use the API to add the attachments to the template. Then send the template.

It looks like the limit is a limit on the size for a call, not the size of the email.