【问题标题】:EWS: Retrieving attachments from signed emailsEWS:从签名的电子邮件中检索附件
【发布时间】:2014-03-04 22:49:18
【问题描述】:

我有一个 C# 程序,它通过检索附件并将电子邮件分类到子文件夹来管理资源邮箱。最近出现了一个问题,客户希望向我们发送签名的电子邮件,因此当程序检索他们的附件时,会保存一个名为“smime.p7m”的文件而不是文件附件。在 Outlook 中查看电子邮件时,该文件不存在,只有我们想要的附件。但是,在单步执行代码时,Email 对象中列出的附件仅包含此.p7m 文件。

我已从电子邮件中检索到 mime 内容,但它只是字节。当我在文本编辑器中查看 .p7m 文件时,我在底部文件中看到了我想要的文件的内容(终极挑逗)!如何在无需解析 .p7m 文件的感兴趣内容的情况下获取原始附件?

交换服务器是 2010 SP2,这一切都是通过使用 EWS 托管 API 的 C# 程序进行的。

【问题讨论】:

  • 嗨,有没有可能使用 EWS 托管 Java API 来做同样的事情。我有一个 Java 程序,它连接到邮箱并获取附件。但是对于签名的电子邮件,“Smime.p7m”文件只会被下载,而不是原始的 .txt 文件。任何建议都会很有帮助。

标签: c# email attachment ews-managed-api smime


【解决方案1】:

您可以使用EnvelopedCMS 类从加密附件中获取 MIME。假设您的安全上下文可以访问密钥。

byte[] content = ...The byte[] from the smime.p7m attachment ...
var encrypted = new EnvelopedCms();
encrypted.Decode(content);
encrypted.Decrypt();
byte[] unencryptedButRawMimeEntity = encrypted.ContentInfo.Content;

这将允许您获取未加密的 MIME 实体(没有传输标头的原始电子邮件)。

注意如果邮件已签名,则解密的 MIME 实体将是另一个单个附件,其 SMIME Type 标头等于 signed-data。您可以使用SignedCMS 类重复上述过程,以公开其内容。应该省略 Decrypt 调用。

然后您必须解析/解码 MIME 以提取其正文和附件。

执行此操作的代码显然驻留在System.Net.Mime 命名空间中,但无论出于何种原因,Microsoft 都没有为其提供公共入口点。我在其他地方读过,你可以使用反射来访问它。这样做的缺点是,它不受支持,并且非公共接口在框架的后续版本中可能会发生变化。 this question 中的代码向您展示了如何处理 quoted-printable 传输编码。

另外,您可以编写或借用您自己的 MIME 解析器,就像我一样。不幸的是,由于IP,我不能给你代码。

当时我无法找到一个简单的替代方案。现在我很想尝试下面链接的 NuGet 包并为自己省点痛苦。以OpenPOP.Net开头。


您可以使用code in this project 获得灵感,查看this question 中的第三方选项,或在NuGet 上尝试these packages

【讨论】:

  • 谢谢乔德雷尔。我会看一下 OpenPOP.Net,看看它会把我带到哪里。然后我会发布我发现的任何积极结果:)
  • @Jodrell 我意识到这篇文章已经很老了,但我希望有人可能仍然知道。如何判断给定的安全上下文是否可以访问密钥?
【解决方案2】:

您应该查看MimeKit(MIME 解析器 + S/MIME 和 PGP 支持)和MailKit(如果您需要 SMTP、POP3 和/或 IMAP)。

我在 GitHub 项目主页的文档中写了一些关于如何使用 MimeKit 的解密和签名验证 API 的示例。

【讨论】:

    【解决方案3】:

    我花了 3 天时间尝试签名但未加密的电子邮件中提取附件我们的项目在 vb.net 中,但应该很容易将其重写为 c#。 以下是对我有用的步骤:

    1. 安装Mimekit Nuget Package
    2. 通过查看其内容类型和附件名称来正确识别 S/Mime 签名的电子邮件(S/Mime 签名的电子邮件始终附有 smime.p7m 文件)
    If String.Equals(origMessage.Attachments.First.ContentType, "multipart/signed", 
    StringComparison.OrdinalIgnoreCase) AndAlso
    String.Equals(origMessage.Attachments.First.Name, "smime.p7m", StringComparison.OrdinalIgnoreCase) Then
    
    1. 将 smime 文件加载为 EWS FileAttachment 并从中创建新的 memoryStream。然后创建此流的 MimeKit.MimeEntity。现在你正在使用非常适合这些东西的 MimeKit 库
    Dim smimeFile As FileAttachment = origMessage.Attachments.First
    smimeFile.Load()
    Dim memoryStreamSigned As MemoryStream = New MemoryStream(smimeFile.Content)
    Dim entity = MimeEntity.Load(memoryStreamSigned)
    
    1. 迭代所有附件的 MimeEntity 实例
    If TypeOf entity Is Cryptography.MultipartSigned Then
        Dim mltipart As Multipart = entity
        Dim attachments As MimeEntity = mltipart(0)
        If TypeOf attachments Is Multipart Then
            Dim mltipartAttachments As Multipart = attachments
            For i As Integer = 0 To mltipartAttachments.Count - 1
                If mltipartAttachments(i).IsAttachment Then
                    **'BOOM, now you're looping your attachment files one by one**
                    **'Call your decode function to read your attachment as array of Bytes**
                End If
            Next
        End If
    End If
    
    1. 将附件读取为字节数组。在上一步的 for 中执行此操作。
    'Read and decode content stream
    Dim fileStrm = New MemoryStream()
    mltipartAttachments(i).Content.DecodeTo(fileStrm)
    
    Dim decodedBytes(0 To fileStrm.Length - 1) As Byte
    fileStrm.Position = 0  'This is important because .DecodeTo set the position to the end!!
    fileStrm.Read(decodedBytes, 0, Convert.ToInt32(fileStrm.Length))
    

    现在您已将附件文件解码为字节数组,您可以保存它或做任何您想做的事情:)希望这会有所帮助!

    【讨论】:

      【解决方案4】:

      使用可通过 NuGet 访问的 OpenPOP.NET 和 EWS 托管 API,我能够检索嵌入在特定电子邮件的 mime 内容中的附件。我用过

      System.Exchange.WebServices.Data.Item email = new System.Exchange.WebServices.Data.Item(myEmail);
      OpenPop.Mime.Message message = new OpenPop.Mime.Message(email.MimeContent.Content);
      List<OpenPop.Mime.MessagePart> validMessageParts = message.FindAllAttachments().Where(x => x.FileName.Contains(".csv") == true || x.FileName.Contains(".xlsx") == true || x.FileName.Contains(".xls") == true).ToList<MessagePart>();
      
      foreach (MessagePart messagePart in validMessageParts)
      {
        if (messagePart != null)
        {
          using (FileStream fileStream = new FileStream(savingPath + messagePart.ContentDisposition.FileName, FileMode.Create, FileAccess.ReadWrite))
          {
              messagePart.Save(fileStream);
          }
        }
      }
      

      将特定电子邮件中的所有 csv、xlsx 和 xls 保存到我选择的目录中。

      【讨论】:

      • 作者不是在询问“简单”的附件处理。用户询问如何处理在对象模型中显示为附件的签名/加密电子邮件。
      【解决方案5】:

      MimeKit。

      我收到一个错误:

      mltipartAttachments(i).Content.DecodeTo(fileStrm)
      

      “内容”不是“MimeEntity”的成员

      我用这个解决了:

      Dim mp As MimePart = mltipartAttachments(i)
      mp.Content.DecodeTo(fileStrm)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-04-09
        • 1970-01-01
        • 2017-07-11
        • 2013-06-14
        • 1970-01-01
        • 1970-01-01
        • 2017-02-18
        • 1970-01-01
        相关资源
        最近更新 更多