5

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

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

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

4

5 回答 5

3

您可以使用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 TypeHeader 等于signed-data. 您可以使用该类重复上述过程SignedCMS,以公开其内容。该Decrypt调用应省略。

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

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

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

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


您可以使用此项目中的代码获得灵感,查看此问题中的第三方选项,或在 NuGet 上尝试这些包。

于 2014-02-07T14:09:47.770 回答
3

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

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

于 2014-02-08T01:04:58.077 回答
2

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

  1. 安装Mimekit Nuget 包
  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))

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

于 2019-05-14T10:06:48.043 回答
1

使用可通过 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 保存到我选择的目录中。

于 2014-02-14T08:30:27.353 回答
0

哑剧套件。

我收到一个错误:

mltipartAttachments(i).Content.DecodeTo(fileStrm)

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

我用这个解决了它:

Dim mp As MimePart = mltipartAttachments(i)
mp.Content.DecodeTo(fileStrm)
于 2019-07-11T12:15:55.310 回答