You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Microsoft Graph生成Excel后发送邮件无报错停滞求助

问题

我通过Microsoft Graph实现微软邮箱发送邮件,同时生成Excel文件作为附件发送。单独发邮件功能正常,但生成Excel后第二次调用发信代码时,程序无报错却卡在以下代码处:

var msgResult = await graphClient.Users["myemail@mycompany.com"].MailFolders.Drafts.Messages.Request().WithMaxRetry(9).AddAsync(message);

完整代码如下:

class Solds
{
    public string Empres { get; set; }
    public string NClient { get; set; }
    public string Name { get; set; }
    public string PurchaseNumber { get; set; }
    public DateTime Date { get; set; }
    public string Codart { get; set; }
    public string Description { get; set; }
    public string Fampro { get; set; }
    public string Serpro { get; set; }
    public string Group { get; set; }
    public decimal Price { get; set; }
    public decimal Cost { get; set; }
    public string Seller { get; set; }
    public string Quarter { get; set; }
}

static void Main(string[] args)
{
    List<String> Destinations = new List<string>() { "myemail@mycompany.com" };
    List<string> Cc = new List<string>();
    List<System.IO.FileInfo> Filess = new List<System.IO.FileInfo>();

    List<Solds> lstSolds = GetData();

    SenMailUsingMicrosoftGraph(Destinations, Cc, "", "Text of the Body", "title of the mail", Filess);
    // GenerateExcel creates a Excel File (i use ClosedXML) and retuns a FileInfo
    Filess.Add(GenerateExcel(lstSolds));

    SenMailUsingMicrosoftGraph(Destinations, Cc, "", "Text of the Body", "title of the mail", Filess);
}


private static async void SenMailUsingMicrosoftGraph(List<String>Destinations, List<String>Cc, string HidenCopy, string Body, string Title, List<FileInfo>Filess)
{
    ClientSecretCredential credential = new ClientSecretCredential("MyTenantID", "MyClientId", "MyClientSecret");

    List<Recipient> recipientsDestinatarios = new List<Recipient>();
    List<Recipient> recipientsCopias = new List<Recipient>();

    foreach (var c in Destinations)
    {
        recipientsDestinatarios.Add(
            new Recipient
            {
                EmailAddress = new EmailAddress
                {
                    Address = c
                }
            });
    }

    foreach (var mail in Cc)
    {
        recipientsCopias.Add(
            new Recipient
            {
                EmailAddress = new EmailAddress
                {
                    Address = mail
                }
            });
    }

    var message = new Microsoft.Graph.Message
    {
        Subject = Title,
        Body = new ItemBody
        {
            ContentType = BodyType.Html,
            Content = Body
        },
        ToRecipients = recipientsDestinatarios,
        CcRecipients = recipientsCopias,
        BccRecipients = new List<Recipient>()
        {
            new Recipient
            {
                EmailAddress=new EmailAddress{Address=Hiden}
            }
        }
    };

    GraphServiceClient graphClient = new GraphServiceClient(credential);

    var msgResult = await graphClient.Users["myemail@mycompany.com"].MailFolders.Drafts.Messages
                                .Request()
                                .WithMaxRetry(9)
                                .AddAsync(message);
    foreach (var Archivo in Filess)
    {
        var attachmentContentSize = Archivo.Length;
        var attachmentItem = new AttachmentItem
        {
            AttachmentType = AttachmentType.File,
            Name = Archivo.Name,
            Size = attachmentContentSize,
        };

        //initiate the upload session for large files 
        var uploadSession = await graphClient.Users["myemail@mycompany.com"].Messages[msgResult.Id].Attachments
                                                        .CreateUploadSession(attachmentItem)
                                                        .Request()
                                                        .PostAsync();

        var maxChunkSize = 1024 * 320;
        var allBytes = System.IO.File.ReadAllBytes(Archivo.FullName);

        using (var stream = new MemoryStream(allBytes))
        {
            stream.Position = 0;
            LargeFileUploadTask<FileAttachment> largeFileUploadTask = new LargeFileUploadTask<FileAttachment>(uploadSession, stream, maxChunkSize);

            await largeFileUploadTask.UploadAsync();
        }
    }
    await graphClient.Users["myemail@mycompany.com"].Messages[msgResult.Id].Send().Request().PostAsync();

}

private static FileInfo GenerateExcel(List<Solds> lstSolds)
{
    System.IO.FileInfo file= new System.IO.FileInfo(@"E:\MyFolder\MyFile.xlsx");

    if (file.Exists) file.Delete();

    using (var wb = new XLWorkbook())
    {
        var ws = wb.Worksheets.Add("Example");
        ws.Cell(2, 1).InsertTable(lstSolds);

        wb.SaveAs(file.FullName);

    }
    return file;
}
private static List<Solds> GetData()
{
    List<Solds> lstSolds = new List<Solds>();

    string connString = @"Data Source=MyServer\SQLExpress; Initial Catalog=MyDataBAse;User Id=User;Password=password;";
    string sentenciaSQL = "QuarterSolds";

    using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(connString))
    {
        using (SqlCommand comm = new SqlCommand(sentenciaSQL, conn))
        {
            DateTime t = DateTime.Now;
            conn.Open();
            comm.CommandType = System.Data.CommandType.StoredProcedure;
            comm.CommandTimeout = 240;
            using (SqlDataReader reader = comm.ExecuteReader())
            {
                if (reader.HasRows)
                {
                    while (reader.Read())
                    {
                        Solds v = new Solds();
                        decimal d = 0;

                        v.Empres = reader.GetValue(0).ToString();
                        v.NClient = reader.GetValue(1).ToString();
                        v.Name = reader.GetValue(2).ToString();
                        v.PurchaseNumber = reader.GetValue(3).ToString();
                        v.Date = DateTime.TryParse(reader.GetValue(4).ToString(), out t) ? t : t;
                        v.Codart = reader.GetValue(5).ToString();
                        v.Description = reader.GetValue(6).ToString();
                        v.Fampro = reader.GetValue(7).ToString();
                        v.Serpro = reader.GetValue(8).ToString();
                        v.Group = reader.GetValue(9).ToString();
                        v.Price = decimal.TryParse(reader.GetValue(10).ToString(), out d) ? d : 0;
                        v.Cost = decimal.TryParse(reader.GetValue(11).ToString(), out d) ? d : 0;
                        v.Seller = reader.GetValue(12).ToString();
                        v.Quarter = reader.GetValue(13).ToString();

                        lstSolds.Add(v);
                    }
                }
                else Console.WriteLine("No lines");
            }
        }
    }
    return lstSolds;
}

解决建议

1. 修复async void的异步调用问题

SenMailUsingMicrosoftGraph方法使用async void会导致控制台程序主线程不等待异步操作完成,甚至引发线程阻塞。改为async Task,同时将Main方法改为异步:

static async Task Main(string[] args)
{
    List<String> Destinations = new List<string>() { "myemail@mycompany.com" };
    List<string> Cc = new List<string>();
    List<System.IO.FileInfo> Filess = new List<System.IO.FileInfo>();

    List<Solds> lstSolds = GetData();

    await SenMailUsingMicrosoftGraph(Destinations, Cc, "", "Text of the Body", "title of the mail", Filess);
    Filess.Add(GenerateExcel(lstSolds));

    await SenMailUsingMicrosoftGraph(Destinations, Cc, "", "Text of the Body", "title of the mail", Filess);
}

private static async Task SenMailUsingMicrosoftGraph(List<String> Destinations, List<String> Cc, string HidenCopy, string Body, string Title, List<FileInfo> Filess)
{
    // 原有代码逻辑不变
}

这是导致程序停滞的核心原因,async void的异步异常无法被正常捕获,会导致程序静默挂起。

2. 修正Bcc收件人变量错误

代码中BccRecipients使用了未定义的Hiden变量,应替换为方法参数HidenCopy,否则会引发编译错误或空地址问题,间接导致草稿创建请求阻塞:

BccRecipients = new List<Recipient>()
{
    new Recipient
    {
        EmailAddress=new EmailAddress{Address=HidenCopy}
    }
}

3. 验证Excel文件是否被占用

GenerateExcel生成文件后,可能存在未释放的句柄导致文件被锁定。添加文件可访问性验证:

var excelFile = GenerateExcel(lstSolds);
// 验证文件未被占用
using (var stream = excelFile.Open(FileMode.Open, FileAccess.Read, FileShare.None))
{
    // 无异常则说明文件可正常读取
}
Filess.Add(excelFile);

4. 添加异常捕获与日志

在停滞的代码块周围添加异常捕获,输出详细错误信息,排查异步操作中的静默异常:

try
{
    var msgResult = await graphClient.Users["myemail@mycompany.com"].MailFolders.Drafts.Messages
                                .Request()
                                .WithMaxRetry(9)
                                .AddAsync(message);
}
catch (Exception ex)
{
    Console.WriteLine($"创建草稿失败: {ex.Message}");
    if (ex.InnerException != null)
    {
        Console.WriteLine($"内部异常: {ex.InnerException.Message}");
    }
    throw;
}

5. 复用Graph客户端实例

每次调用发信方法都新建GraphServiceClient和ClientSecretCredential会增加认证开销,改为单例复用:

private static readonly ClientSecretCredential _credential = new ClientSecretCredential("MyTenantID", "MyClientId", "MyClientSecret");
private static readonly GraphServiceClient _graphClient = new GraphServiceClient(_credential);

// 在SenMailUsingMicrosoftGraph方法中直接使用_graphClient

内容的提问来源于stack exchange,提问作者Ion

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 12:20:41