msgraph-sdk-dotnet icon indicating copy to clipboard operation
msgraph-sdk-dotnet copied to clipboard

Sending mail with attachments ends in error "A task was canceled."

Open vko-insiders opened this issue 2 months ago • 6 comments

Describe the bug

I am trying to send a mail with attachment on customer site but it fails with an exception of type System.Threading.Tasks.TaskCanceledException with message A task was canceled. (no inner message). We are using Microsoft.Graph in version 4.54.0 with .NET 4.8 on Windows Server. Upgrading to a v5 is planned but not possible at the moment.

There are some curious things about it: Sending mails with and without attachment works in our environment. Sending mails without attachment is possible on customer site. Sending mails with attachment fails with said exception.

Trying to send mails with attachment via PowerShell is possible on customer site. Customer uses Proxy and Firewalls. We are utilizing the proxy and can rule out Firewall issues because when calling endpoints via browser like Chrome or Edge we get http error message 401 not authorized instead of 404 Not found, when we change the URI a bit. We are logging requests and responses, but are not able to log session upload requests/responses (neither on customer site nor local site). We can rule out the proxy as we also configured the proxy on Windows via Windows network settings and all other operations like fetching mails and sending mails without attachments work fine with that setting as well.

Expected behavior

I would expect to send mails with attachments on customer site.

How to reproduce

Create instance of GraphServiceClient where authProvider is a Delegated User Authentication, webProxy is our proxy and loggingHandler is logging the requests and responses (see below).

var httpClient = GraphClientFactory.Create(authProvider, proxy: webProxy, finalHandler: loggingHandler);
Client = new GraphServiceClient(httpClient);

Our logging handler is pretty simple

public class GraphLoggingMessageHandler : DelegatingHandler
{
    public GraphLoggingMessageHandler()
    {
        InnerHandler = new HttpClientHandler();
    }

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        request.Version = HttpVersion.Version11;
        HttpResponseMessage response = await GraphExceptionHandler.Call(async () =>
        {
            return await base.SendAsync(request, cancellationToken);
        });
        Log.Message("GraphLogging", await createLogMessage(request, response));
        return response;
    }

    private static async Task<string> createLogMessage(HttpRequestMessage request, HttpResponseMessage response)
    {
        string message = "=== Request ===\n" + request.ToString() + "\n";
        if (request.Content != null)
        {
            message += "Content: " + await request.Content.ReadAsStringAsync() + "\n";
        }

        message += "\n\n=== Response ===\n" + response.ToString() + "\n";
        if (response.Content != null)
        {
            message += "Content: " + await response.Content.ReadAsStringAsync() + "\n";
        }
        return message;
    }
}

Now the setup for sending mail with attachment is pretty much standard as well. We can see that a mail is created in Draft-folder and we can add attachments on our site and send it as expected, but adding attachments on customer site is not possible.

private async Task AddFileAttachments(Message draftMail, string[] attachmentPaths)
{
	foreach (var attachmentPath in attachmentPaths)
	{
		var attachmentContentSize = new FileInfo(attachmentPath).Length;
		var attachmentItem = new AttachmentItem
		{
			AttachmentType = AttachmentType.File,
			Name = Path.GetFileName(attachmentPath),
			Size = attachmentContentSize,
		};

		var uploadSession = await await Connection.Client.Users[Connection.User].Messages[draftMail.Id].Attachments
																.CreateUploadSession(attachmentItem)
																.Request()
																.PostAsync();
		var maxChunkSize = 1024 * 320;

		using (var filestream = System.IO.File.Open(attachmentPath, FileMode.Open, FileAccess.Read))
		{
			var streamLength = filestream.Length;
			filestream.Seek(0, SeekOrigin.Begin);

			LargeFileUploadTask<FileAttachment> largeFileUploadTask = new LargeFileUploadTask<FileAttachment>(uploadSession, filestream, maxChunkSize);

			IProgress<long> progress = new Progress<long>(prog =>
			{
				Log.Message($"ploaded {prog} bytes of {streamLength} bytes");
			});

			try
			{
				var result = await largeFileUploadTask.UploadAsync(progress);
			}
			catch (ServiceException ex)
			{
			}
			catch (Exception ex)
			{
			}
		}
	}
}

We also see no logging requests/responses done by largeFileUploadTask. So we cannot share request-ID on that particular calls with Microsoft Support.

SDK Version

4.54.0

Latest version known to work for scenario above?

No response

Known Workarounds

No response

Debug output

No response

Configuration

Windows Server 2019, 64-bit, Version 1809, OS Build 17763.5696.

Other information

I suspect the issue to be somewhere around this:

LargeFileUploadTask<FileAttachment> largeFileUploadTask = new LargeFileUploadTask<FileAttachment>(uploadSession, filestream, maxChunkSize);
var result = await largeFileUploadTask.UploadAsync(); // here

vko-insiders avatar Apr 29 '24 13:04 vko-insiders