英文:
Send Mails unattended with Microsoft Graph API
问题
我想在.NET控制台应用程序中使用Microsoft Graph API无人值守地发送邮件。
该API支持直接发送邮件或创建草稿,然后修改并发送它。前者对附件大小有限制,每个附件的大小必须小于3 MB。查看文档
后者需要Mail.ReadWrite API权限。将其添加为应用程序权限将使应用程序能够访问组织中的每个邮箱,如果可能的话,我不想授予此权限。
另一个选项是使用用户名和密码身份验证流程。但是,我们公司的AD要求多因素身份验证,这是该流程的限制。
我尝试使用客户端凭据流程对应用程序进行身份验证。发送超过3 MB的附件需要Mail.ReadWrite权限。
使用我的用户帐户对应用程序进行用户名/密码身份验证也失败,因为需要MFA。
我正在使用NuGet包Azure.Identity进行身份验证流程和Microsoft.Graph来发送请求。
从.NET控制台应用程序无人值守地发送超过3 MB的附件邮件的正确方法是什么?我在哪里出错了?
提前感谢您,并请告诉我如果需要更多详细信息。
英文:
I want to send mails unattended in a .NET console application with the Microsoft Graph API.
The API supports sending a mail directly or create a draft, modify it and send it. The first has a limitation on attachment size. Each attachment has to be under 3 MB in size. See Documentation
The latter one requires the Mail.ReadWrite API permission. Adding it as an application permission would enable the application to access every mailbox in the organisation, which I do not want to grant if possible.
Another option would be to use the username and password authentication flow. But our corporation AD requires multi-factor authentication, a constraint of that flow.
I tried to authentiate the application with the client credential flow. Sending an attachment over 3 MB requires the Mail.ReadWrite privilege.
Authenticating the application with my user account using the username/password did also fail, because of the MFA requirement.
I am using the NuGet packages Azure.Identity for the authentication flow and Microsoft.Graph to send the requests.
What is the proper way to send mails unattended with attachments over 3 MB from a .NET console application? Where did I take the wrong turn?
Thanks in advance and let me know if you need more details.
答案1
得分: 1
客户端凭证流通常是最佳选项,因为它避免了使用用户名和密码,这有许多相关问题(多因素身份验证仅是其中之一)。关于完全访问租户的问题,您可以缩小访问范围,以便您的应用程序仅能够发送/访问特定的邮箱。有关发送超过3MB的电子邮件,请参阅链接https://learn.microsoft.com/en-us/graph/outlook-large-attachments?tabs=csharp。如果您使用Graph SDK,它会使这个过程相对容易,例如:
var fileStream = System.IO.File.OpenRead(bigAttachment.FullName);
var uploadRequestBody = new Microsoft.Graph.Users.Item.Messages.Item.Attachments.CreateUploadSession.CreateUploadSessionPostRequestBody
{
    AttachmentItem = new AttachmentItem
    {
        AttachmentType = AttachmentType.File,
        Name = bigAttachment.Name,
        Size = fileStream.Length,
        ContentType = "application/octet-stream"
    }
};
var uploadSession = graphClient.Users[objectID]
    .Messages[savedDraft.Id]
    .Attachments
    .CreateUploadSession
    .PostAsync(uploadRequestBody).GetAwaiter().GetResult();
// 最大切片大小必须是320 KiB的倍数
int maxSliceSize = 320 * 1024;
var fileUploadTask = new LargeFileUploadTask<FileAttachment>(uploadSession, fileStream, maxSliceSize);
var totalLength = fileStream.Length;
// 创建在每个切片上传后调用的回调
IProgress<long> progress = new Progress<long>(prog =>
{
    Console.WriteLine($"已上传 {prog} 字节,共 {totalLength} 字节");
});
try
{
    // 上传文件
    var uploadResult = fileUploadTask.UploadAsync(progress).GetAwaiter().GetResult();
    Console.WriteLine(uploadResult.UploadSucceeded ? "上传完成" : "上传失败");
}
catch (ServiceException ex)
{
    Console.WriteLine($"上传时出错: {ex.ToString()}");
}
英文:
The client credentials flow is generally the best option as this avoids having a username and password which has a lot of associated problems (MFA is just one). With the issue of having full access to the tenant you can scope down the access https://learn.microsoft.com/en-us/graph/auth-limit-mailbox-access so your app can then only Send/Access particular mailboxes.
For sending emails over 3mb see https://learn.microsoft.com/en-us/graph/outlook-large-attachments?tabs=csharp if you use the Graph SDK it makes this relatively easy eg
        var fileStream = System.IO.File.OpenRead(bigAttachment.FullName);
        var uploadRequestBody = new Microsoft.Graph.Users.Item.Messages.Item.Attachments.CreateUploadSession.CreateUploadSessionPostRequestBody
        {
            AttachmentItem = new AttachmentItem
            {
                AttachmentType = AttachmentType.File,
                Name = bigAttachment.Name,
                Size = fileStream.Length,
                ContentType = "application/octet-stream"
            }
        };
        var uploadSession = graphClient.Users[objectID]
            .Messages[savedDraft.Id]
            .Attachments
            .CreateUploadSession
            .PostAsync(uploadRequestBody).GetAwaiter().GetResult();
        // Max slice size must be a multiple of 320 KiB
        int maxSliceSize = 320 * 1024;
        var fileUploadTask = new LargeFileUploadTask<FileAttachment>(uploadSession, fileStream, maxSliceSize);
        var totalLength = fileStream.Length;
        // Create a callback that is invoked after each slice is uploaded
        IProgress<long> progress = new Progress<long>(prog =>
        {
            Console.WriteLine($"Uploaded {prog} bytes of {totalLength} bytes");
        });
        try
        {
            // Upload the file
            var uploadResult = fileUploadTask.UploadAsync(progress).GetAwaiter().GetResult();
            Console.WriteLine(uploadResult.UploadSucceeded ? "Upload complete" : "Upload failed");
        }
        catch (ServiceException ex)
        {
            Console.WriteLine($"Error uploading: {ex.ToString()}");
        }
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论