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

如何用Graph SDK发送带附件的MIME邮件并避免winmail.dat

问题:通过Microsoft Graph SDK发送HTML邮件带PDF附件避免winmail.dat

我使用C#的Graph SDK从Web应用发送邮件,邮件正文为HTML格式并附带PDF附件。但收件人收到邮件时会附带winmail.dat文件,有时还会出现noname文件,邮件也会以纯文本形式展示。Gmail可以解析winmail.dat,但并非所有客户端都支持。

调研得知需使用MIME格式,但难以找到简洁示例。请问如何通过Graph API/SDK发送带附件的HTML格式MIME邮件,且不会生成winmail.dat?


现有代码

创建MimeMessage的代码

private MimeMessage GetMimeMessage(string fromEmail, string subject, string htmlBody, IEnumerable<string> toRecipients, IEnumerable<string> ccRecipients, IEnumerable<string> attachments)
{
    var message = new MimeMessage();

    foreach (var recipient in toRecipients)
        message.To.Add(MailboxAddress.Parse(recipient));
    
    foreach (var recipient in ccRecipients)
        message.Cc.Add(MailboxAddress.Parse(recipient));

    message.From.Add(MailboxAddress.Parse(fromEmail));
    message.Subject = subject;
    var builder = new BodyBuilder();
    builder.TextBody = htmlBody;
    builder.HtmlBody = htmlBody;
    
    foreach (var attachment in attachments)
        builder.Attachments.Add(attachment);
    
    message.Body = builder.ToMessageBody();
    return message;
}

发送邮件的代码

private async Task SendMimeMessageWithGraph(string sendFromEmail, MimeMessage mimeMessage)
{
    var stream = new MemoryStream();
    mimeMessage.WriteTo(stream);
    
    stream.Position = 0;
    StringContent MessagePost = new StringContent(Convert.ToBase64String(stream.ToArray()), Encoding.UTF8, "text/plain");

    var message = new Message();
    var mypost = await MessagePost.ReadAsStringAsync();
    var sendMailRequest = _GraphClient.Users[sendFromEmail].SendMail(message, true).Request().GetHttpRequestMessage();
    sendMailRequest.Content = MessagePost;
    sendMailRequest.Method = HttpMethod.Post;
    var sendResult = await _GraphClient.HttpProvider.SendAsync(sendMailRequest);
    Debug.WriteLine(sendResult.StatusCode);
}

生成的MIME内容

From: fromemail@fromemail.com
Date: Tue, 06 Sep 2022 21:39:47 -0400
Subject: Invoice #0000003
Message-Id: <2FWZXJIFTHU4.JPGM32IG50SI2@person1234>
To: Newperson@new.com
Cc: cc@cc.cc
MIME-Version: 1.0
Content-Type: multipart/alternative; boundary="=-9G8gCZS3S+XQhQ+1kLqUog=="

--=-9G8gCZS3S+XQhQ+1kLqUog==
Content-Type: text/plain; charset=utf-8

Please see attached invoice.<br><br>Thank you for your business,<br>Test<br>Person<br>222-999-1111<br>email@email.com<br><img height="50px" width="auto" src="data:image/svg+xml;base64,PD94b...>">
--=-9G8gCZS3S+XQhQ+1kLqUog==
Content-Type: text/html; charset=utf-8

Please see attached invoice.<br><br>Thank you for your business,<br>Test<br>Person<br>222-999-1111<br>email@email.com<br><img height="50px" width="auto" src="data:image/svg+xml;base64,PD94...">
--=-9G8gCZS3S+XQhQ+1kLqUog==--

问题分析

  1. 纯文本内容错误:直接将HTML内容赋值给TextBody,导致纯文本部分包含HTML标签,客户端解析时会优先展示混乱的纯文本内容。
  2. MIME结构错误:带附件的邮件需要使用multipart/mixed作为外层结构(包含正文部分和附件),现有代码生成的是multipart/alternative结构,附件被错误处理,进而生成winmail.dat。
  3. 请求Content-Type错误:发送完整MIME邮件时,Graph API要求的Content-Type是message/rfc822,而非text/plain。

修正后的代码

正确创建MimeMessage

private MimeMessage GetMimeMessage(string fromEmail, string subject, string htmlBody, IEnumerable<string> toRecipients, IEnumerable<string> ccRecipients, IEnumerable<string> attachments)
{
    var message = new MimeMessage();

    foreach (var recipient in toRecipients)
        message.To.Add(MailboxAddress.Parse(recipient));
    
    foreach (var recipient in ccRecipients)
        message.Cc.Add(MailboxAddress.Parse(recipient));

    message.From.Add(MailboxAddress.Parse(fromEmail));
    message.Subject = subject;
    
    var builder = new BodyBuilder();
    // 将HTML转换为可读的纯文本,避免客户端展示混乱内容
    builder.TextBody = HtmlToPlainText(htmlBody);
    builder.HtmlBody = htmlBody;
    
    foreach (var attachment in attachments)
        builder.Attachments.Add(attachment);
    
    message.Body = builder.ToMessageBody();
    return message;
}

// 简易HTML转纯文本方法,可根据实际需求扩展完善
private string HtmlToPlainText(string html)
{
    // 替换换行标签为换行符
    var plainText = html.Replace("<br>", "\n").Replace("<br/>", "\n").Replace("<BR>", "\n");
    // 移除所有HTML标签
    plainText = System.Text.RegularExpressions.Regex.Replace(plainText, "<.*?>", string.Empty);
    // 合并多余空白字符
    plainText = System.Text.RegularExpressions.Regex.Replace(plainText, @"\s+", " ").Trim();
    return plainText;
}

正确发送MIME邮件

private async Task SendMimeMessageWithGraph(string sendFromEmail, MimeMessage mimeMessage)
{
    using var stream = new MemoryStream();
    mimeMessage.WriteTo(stream);
    stream.Position = 0;

    // 设置正确的Content-Type为message/rfc822
    var messageContent = new StringContent(Convert.ToBase64String(stream.ToArray()), Encoding.UTF8, "message/rfc822");

    // 直接构造SendMail请求,无需创建空Message对象
    var request = new HttpRequestMessage(HttpMethod.Post, $"https://graph.microsoft.com/v1.0/users/{sendFromEmail}/sendMail");
    request.Content = messageContent;

    var sendResult = await _GraphClient.HttpProvider.SendAsync(request);
    sendResult.EnsureSuccessStatusCode(); // 确保请求成功,可根据业务需求添加异常处理
    Debug.WriteLine(sendResult.StatusCode);
}

说明

  • MIME结构自动处理:当邮件同时包含正文(文本+HTML)和附件时,MimeKit的BodyBuilder会自动生成multipart/mixed外层结构,内部包含multipart/alternative(正文部分)和附件,彻底避免winmail.dat的生成。
  • 纯文本优化:新增HTML转纯文本的方法,确保纯文本部分为可读的普通文本,客户端会根据自身支持情况选择展示HTML或纯文本内容。
  • 请求格式修正:将Content-Type改为message/rfc822,符合Graph API接受完整MIME邮件的要求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 11:54:27