【问题标题】:How to save MailMessage object to disk as *.eml or *.msg file如何将 MailMessage 对象作为 *.eml 或 *.msg 文件保存到磁盘
【发布时间】:2010-11-18 21:03:55
【问题描述】:

如何将 MailMessage 对象保存到磁盘? MailMessage 对象不公开任何 Save() 方法。

如果它以任何格式保存,*.eml 或 *.msg,我都没有问题。知道怎么做吗?

【问题讨论】:

    标签: c# .net email mailmessage eml


    【解决方案1】:

    为简单起见,我只引用Connect item的解释:

    您实际上可以配置 SmtpClient 向文件发送电子邮件 系统而不是网络。你可以 以编程方式使用 以下代码:

    SmtpClient client = new SmtpClient("mysmtphost");
    client.DeliveryMethod = SmtpDeliveryMethod.SpecifiedPickupDirectory;
    client.PickupDirectoryLocation = @"C:\somedirectory";
    client.Send(message);
    

    您也可以在您的 应用程序配置文件,如 这个:

     <configuration>
         <system.net>
             <mailSettings>
                 <smtp deliveryMethod="SpecifiedPickupDirectory">
                     <specifiedPickupDirectory pickupDirectoryLocation="C:\somedirectory" />
                 </smtp>
             </mailSettings>
         </system.net>
     </configuration>
    

    发送电子邮件后,您应该 查看电子邮件文件被添加到 您指定的目录。然后你可以 有一个单独的进程发送 以批处理模式发送电子邮件。

    您应该能够使用空构造函数而不是列出的构造函数,因为它无论如何都不会发送它。

    【讨论】:

    • 我发现除了Ryan提供的之外,我还需要添加
    • 有什么办法可以改变输出.eml文件的文件名吗?我不希望它看起来像下面这样:f80f4695-551c-47d7-8879-40ad89707b23.eml 谢谢!
    • 虽然是老帖子,但我想在@buzzzzjay 的最后一个问题上添加一个答案:看看这里:link
    • 感谢您的链接,这真的很有帮助!
    • 好,它对我有用。进一步如何打开 Outlook 以在客户端打开刚刚保存的文件。
    【解决方案2】:

    这是一个将 MailMessage 转换为包含 EML 数据的流的扩展方法。 显然,它使用文件系统有点破解,但它可以工作。

    public static void SaveMailMessage(this MailMessage msg, string filePath)
    {
        using (var fs = new FileStream(filePath, FileMode.Create))
        {
            msg.ToEMLStream(fs);
        }
    }
    
    /// <summary>
    /// Converts a MailMessage to an EML file stream.
    /// </summary>
    /// <param name="msg"></param>
    /// <returns></returns>
    public static void ToEMLStream(this MailMessage msg, Stream str)
    {
        using (var client = new SmtpClient())
        {
            var id = Guid.NewGuid();
    
            var tempFolder = Path.Combine(Path.GetTempPath(), Assembly.GetExecutingAssembly().GetName().Name);
    
            tempFolder = Path.Combine(tempFolder, "MailMessageToEMLTemp");
    
            // create a temp folder to hold just this .eml file so that we can find it easily.
            tempFolder = Path.Combine(tempFolder, id.ToString());
    
            if (!Directory.Exists(tempFolder))
            {
                Directory.CreateDirectory(tempFolder);
            }
    
            client.UseDefaultCredentials = true;
            client.DeliveryMethod = SmtpDeliveryMethod.SpecifiedPickupDirectory;
            client.PickupDirectoryLocation = tempFolder;
            client.Send(msg);
    
            // tempFolder should contain 1 eml file
    
            var filePath = Directory.GetFiles(tempFolder).Single();
    
            // stream out the contents
            using (var fs = new FileStream(filePath, FileMode.Open))
            {
                fs.CopyTo(str);
            }
    
            if (Directory.Exists(tempFolder))
            {
                Directory.Delete(tempFolder, true);
            }
        }
    }
    

    然后,您可以获取返回的流并按照您的意愿进行操作,包括保存到磁盘上的另一个位置或存储在数据库字段中,甚至作为附件发送电子邮件。

    【讨论】:

    • 嗨 Saille... 您的代码运行良好,是的,它正在创建 eml 或 Msg 文件,但我无法在 MS Outlook 中打开它:(需要您的帮助。
    • .EML 文件应该在 Outlook 中打开,但如果无法打开,请尝试将文件扩展名重命名为 .MHT,然后在 Internet Explorer 中打开。
    • Saille - 是否可以在没有“发件人”地址的情况下保存,以便可以从打开它的用户发送?干杯。
    • 你必须尝试一下。我想您的邮件客户端会希望根据其设置设置回复地址。
    【解决方案3】:

    如果您使用的是 Mailkit。只需写下面的代码

    string fileName = "your filename full path";
    MimeKit.MimeMessage message = CreateMyMessage ();
    message.WriteTo(fileName);
    

    【讨论】:

      【解决方案4】:

      在社区的帮助下,我想出了一个针对 .NET 5 的解决方案。我将 this 旧解决方案与 this 帖子中的建议结合起来,并受到 Mailkit 的启发,这导致了很好的扩展方法,没有不必要的依赖

      public static class MailMessageHelper
      {
          public static void WriteTo(this MailMessage mail, Stream stream)
          {
              Assembly assembly = typeof(SmtpClient).Assembly;
              Type _mailWriterType = assembly.GetType("System.Net.Mail.MailWriter");
      
              // Get reflection info for MailWriter contructor
              ConstructorInfo _mailWriterConstructor =
                  _mailWriterType.GetConstructor(
                      BindingFlags.Instance | BindingFlags.NonPublic,
                      null,
                      new Type[] { typeof(Stream), typeof(bool) },
                      null);
      
              // Construct MailWriter object with our FileStream
              object _mailWriter =
                _mailWriterConstructor.Invoke(new object[] { stream, true });
      
              // Get reflection info for Send() method on MailMessage
              MethodInfo _sendMethod =
                  typeof(MailMessage).GetMethod(
                      "Send",
                      BindingFlags.Instance | BindingFlags.NonPublic);
      
              // Call method passing in MailWriter
              _sendMethod.Invoke(
                  mail,
                  BindingFlags.Instance | BindingFlags.NonPublic,
                  null,
                  new object[] { _mailWriter, true, true },
                  null);
      
              // Finally get reflection info for Close() method on our MailWriter
              MethodInfo _closeMethod =
                  _mailWriter.GetType().GetMethod(
                      "Close",
                      BindingFlags.Instance | BindingFlags.NonPublic);
      
              // Call close method
              _closeMethod.Invoke(
                  _mailWriter,
                  BindingFlags.Instance | BindingFlags.NonPublic,
                  null,
                  Array.Empty<object>(),
                  null);
          }
      }
      

      用法

      MailMessage mail = new(mailFrom, mailTo, mailSubject, mailContent);
      mail.WriteTo(new FileStream(@"path_to_file\new_mail.eml", FileMode.Create));
      

      另外,如果您使用MemoryStream 并希望在string 中获得结果,只需更改扩展方法的返回类型并在最后写入

      return Encoding.ASCII.GetString(stream.ToArray());
      

      享受

      【讨论】:

      • 我可以确认这在 .net 5 中效果很好,谢谢!
      【解决方案5】:

      由于某种原因,client.send 失败(在使用该方法实际发送之后),所以我插入了良好的 'ole CDO 和 ADODB 流。在设置 .Message 值之前,我还必须使用 template.eml 加载 CDO.message。但它有效。

      因为上面的一个是C,这里是VB的一个

          MyMessage.From = New Net.Mail.MailAddress(mEmailAddress)
          MyMessage.To.Add(mToAddress)
          MyMessage.Subject = mSubject
          MyMessage.Body = mBody
      
          Smtp.Host = "------"
          Smtp.Port = "2525"
          Smtp.Credentials = New NetworkCredential(------)
      
          Smtp.Send(MyMessage)        ' Actual Send
      
          Dim oldCDO As CDO.Message
          oldCDO = MyLoadEmlFromFile("template.eml")  ' just put from, to, subject blank. leave first line blank
          oldCDO.To = mToAddress
          oldCDO.From = mEmailAddress
          oldCDO.Subject = mSubject
          oldCDO.TextBody = mBody
          oldCDO.HTMLBody = mBody
          oldCDO.GetStream.Flush()
          oldCDO.GetStream.SaveToFile(yourPath)
      

      【讨论】:

      • 欢迎来到 StackOverflow!由于问题与标签c#有关,其他语言的答案没有帮助,对不起。
      【解决方案6】:

      试试这个

      请使用这两个参考 (使用MailBee;) (使用 MailBee.Mime;)

          public static string load(string to,string from,string cc,string bcc,string subject,string body, List<string> reportList,string path, bool HtmlbodyType)
          {
              try
              {
                  MailBee.Mime.MailMessage msg = new MailBee.Mime.MailMessage();
                  msg.From.AsString = from;
                  msg.Subject = subject;
                  if (HtmlbodyType == true)
                  {
                      msg.BodyHtmlText = body;
                  }
                  else
                  {
                      msg.BodyPlainText = body;
                  }
                  
                  string[] receptionEmail = to.Split(new string[] { ",", ";" }, StringSplitOptions.RemoveEmptyEntries);
                  string[] ccEmail = cc.Split(new string[] { ",", ";" }, StringSplitOptions.RemoveEmptyEntries);
                  string[] bccEmail = bcc.Split(new string[] { ",", ";" }, StringSplitOptions.RemoveEmptyEntries);
                  string message = "";
                  foreach (string To in receptionEmail)
                  {
                      msg.To.Add(To);
                  }
                  foreach (string CC in ccEmail)
                  {
                          msg.Cc.Add(CC);
                  }
                  foreach (string Bcc in bccEmail)
                  {
                          msg.Bcc.Add(Bcc);
      
                  }
                      for (int x = 0; x < reportList.Count; x++)
                      {
                          string fileName = reportList[x];
                          msg.Attachments.Add(fileName);
                      }
      
                      msg.SaveMessage(path);
                      return "Success";
                  
              }
              catch (Exception ex)
              {
                  return ex.Message;
              }
      
          }
      

      【讨论】:

        猜你喜欢
        • 2016-09-23
        • 2021-11-03
        • 1970-01-01
        • 1970-01-01
        • 2011-04-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-08-20
        相关资源
        最近更新 更多