在 C# 中将多个 eml 文件转换为单个 PST

发布于 2024-09-05 00:57:36 字数 136 浏览 6 评论 0原文

我需要编写一个函数,它将获取多个 eml 文件(可能来自单个文件系统文件夹)并将它们转换为单个 PST 文件。

是否可以?如果是,有人可以提供示例代码吗?

我认为这是可能的,因为有许多商业 eml 到 pst 转换器正在这样做

I need to write a single function which will take multiple eml files ( may be from a single filesystem folder ) and convert them to a single PST file.

Is it possible? if yes can someone provide a sample code?

I assume its possible because there are many commercial eml to pst converters out there doing this

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

美男兮 2024-09-12 00:57:36

虽然 Outlook 可以打开 EML 文件,但仅使用 VBA 无法以编程方式实现。因此,我创建了这个 VBA 宏,它循环遍历某个文件夹并使用 SHELL EXEC 打开每个 EML 文件。 Outlook 可能需要几毫秒才能打开 EML 文件,因此 VBA 会等待,直到在 ActiveInspector 中打开某些内容。最后,将此电子邮件复制到某个选定的文件夹中,并且(如果成功)原始 EML 文件将被删除。

该宏有时会崩溃,但您可以随时重新启动该宏,并且它将从之前崩溃的位置重新启动(请记住,所有成功导入的 EML 文件都将被删除)。如果重启后仍然崩溃,则可能是下一个要导入的 EML 文件出现问题。在这种情况下,您只需删除有问题的 EML 即可。

PS:有时您可以自己打开 EML,而不会导致 Outlook 崩溃,但根据我的测试,每次 EML 文件导致 Outlook 崩溃时,都是一些不重要的事情,例如已读回执。

这是我的VBA代码。如果您有任何疑问或问题,请告诉我。

'----------------------------------------------------
' Code by Ricardo Drizin (contact info at http://www.drizin.com.br)
'----------------------------------------------------
Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Option Explicit

'---------------------------------------------------------------------
' This method closes ActiveInspectors if any.
' All inporting is based on the assumption that the EML
' is opened by shell and we can refer to it through the ActiveInspector
'---------------------------------------------------------------------
Function CloseOpenInspectors() As Boolean
    Dim app As Outlook.Application: Set app = CreateObject("Outlook.Application")
    Dim insp As Outlook.Inspector
    Dim count As Integer
    count = 0
repeat:
    count = count + 1
    Set insp = app.ActiveInspector
    If TypeName(insp) = "Nothing" Then
        CloseOpenInspectors = True
        Exit Function
    End If
    If TypeName(insp.CurrentItem) = "Nothing" Then
        CloseOpenInspectors = True
        Exit Function
    End If
    If (count > 100) Then
        MsgBox "Error. Could not close ActiveInspector. "
        CloseOpenInspectors = False
    End If

    insp.Close (olDiscard)
    GoTo repeat
End Function


'---------------------------------------------------------------------
' This method allows user to choose a Root Folder in Outlook
' All EML files will be imported under this folder
'---------------------------------------------------------------------
Function GetRootFolder() As Outlook.folder
    Dim app As Outlook.Application: Set app = CreateObject("Outlook.Application")
    Dim NS As Outlook.NameSpace: Set NS = app.GetNamespace("MAPI")
    Dim fold As Outlook.folder
    Set fold = NS.PickFolder
    'MsgBox fold.Name
    Set GetRootFolder = fold
End Function

'---------------------------------------------------------------------
' Creates a child folder in Outlook, under root folder.
'---------------------------------------------------------------------
Function GetChildFolder(parentFolder As Outlook.folder, name As String)
    On Error Resume Next
    Dim fold2 As Outlook.folder
    Set fold2 = parentFolder.folders.Item(name)
    If Err.Number Then
        On Error GoTo 0
        Set fold2 = parentFolder.folders.Add(name)
    End If
    On Error GoTo 0
    'MsgBox fold2.Name
    Set GetChildFolder = fold2
End Function

'---------------------------------------------------------------------
' Imports the EML open in the current ActiveInspector
' into the given folder
'---------------------------------------------------------------------
Sub ImportOpenItem(targetFolder As Outlook.folder)
    Dim app As Outlook.Application: Set app = CreateObject("Outlook.Application")
    Dim insp As Outlook.Inspector: Set insp = app.ActiveInspector

    Dim retries As Integer
    retries = 0
    While TypeName(insp) = "Nothing" ' READING PANE should be visible, or else it will not work.
        'MsgWaitObj (1000)
        Sleep (50)
        DoEvents
        Sleep (50)
        Set insp = app.ActiveInspector
        retries = retries + 1
        'If retries > 100 Then
        '    Stop
        'End If
    Wend

    If TypeName(insp) = "Nothing" Then
        MsgBox "Error! Could not find open inspector for importing email."
        Exit Sub
    End If


    Dim m As MailItem, m2 As MailItem, m3 As MailItem
    Set m = insp.CurrentItem
    'MsgBox m.Subject
    Set m2 = m.Copy
    Set m3 = m2.Move(targetFolder)
    m3.Save
    Set m = Nothing
    Set m2 = Nothing
    Set m3 = Nothing
    insp.Close (olDiscard)
    Set insp = Nothing
End Sub


'---------------------------------------------------------------------
' Scans a given folder for *.EML files and import them
' into the given folder.
' Each EML file will be deleted after importing.
'---------------------------------------------------------------------
Sub ImportEMLFromFolder(targetFolder As Outlook.folder, emlFolder As String)
    If Right(emlFolder, 1) <> "\" Then emlFolder = emlFolder & "\"
    Dim firstImport As Boolean: firstImport = True

    Dim file As String
    Dim count As Integer: count = 0
    'MsgBox fold.Items.count
    'Exit Sub
    file = Dir(emlFolder & "*.eml")

repeat:
    If file = "" Then
        'MsgBox "Finished importing EML files. Total = " & count
        Debug.Print "Finished importing EML files. Total = " & count
        Exit Sub
    End If
    count = count + 1

    Debug.Print "Importing... " & file & " - " & emlFolder
    Shell ("explorer """ & emlFolder & file & """")
    'If firstImport Then Stop
    firstImport = False
    Sleep (50)
    On Error GoTo nextfile
    Call ImportOpenItem(targetFolder)
    Call Kill(emlFolder & file)
nextfile:
    On Error GoTo 0
    Sleep (50)

    file = Dir()
    GoTo repeat
End Sub

'---------------------------------------------------------------------
' Main method.
' User chooses an Outlook root Folder, and a Windows Explorer root folder.
' All EML files inside this folder and in immediate subfolders will be imported.
'---------------------------------------------------------------------
Sub ImportAllEMLSubfolders()
    Call CloseOpenInspectors

    MsgBox "Choose a root folder for importing "
    Dim rootOutlookFolder As Outlook.folder
    Set rootOutlookFolder = GetRootFolder()
    If rootOutlookFolder Is Nothing Then Exit Sub

    Dim rootWindowsFolder As String
    rootWindowsFolder = "D:\Outlook Express EMLs folder"
    rootWindowsFolder = InputBox("Choose a windows folder where you have your EML files", , rootWindowsFolder)
    If IsNull(rootWindowsFolder) Or IsEmpty(rootWindowsFolder) Or rootWindowsFolder = "" Then Exit Sub
    If Right(rootWindowsFolder, 1) <> "\" Then rootWindowsFolder = rootWindowsFolder & "\"

    Dim subFolders As New Collection

    Dim subFolder As String
    subFolder = Dir(rootWindowsFolder, vbDirectory)
repeat:
    If subFolder = "." Or subFolder = ".." Then GoTo nextdir
    If (GetAttr(rootWindowsFolder & subFolder) And vbDirectory) = 0 Then GoTo nextdir
    subFolders.Add (subFolder)
nextdir:
    subFolder = Dir()
    If subFolder <> "" Then GoTo repeat

Dim outlookFolder As Outlook.folder

' Importing main folder
Call ImportEMLFromFolder(rootOutlookFolder, rootWindowsFolder)

' Importing subfolders
While subFolders.count
    subFolder = subFolders.Item(1)
    subFolders.Remove (1)
    Set outlookFolder = GetChildFolder(rootOutlookFolder, subFolder)
    Debug.Print "Importing " & rootWindowsFolder & subFolder & " into Outlook folder " & outlookFolder.name & "..."
    Call ImportEMLFromFolder(outlookFolder, rootWindowsFolder & subFolder)
Wend
    Debug.Print "Finished"

End Sub

Although Outlook can open EML files, there is no way to do it programatically only with VBA. So I created this VBA macro which loops through some folder and opens each EML file using SHELL EXEC. It may take a few milliseconds until Outlook opens the EML file, so the VBA waits until something is open in ActiveInspector. Finally, this email is copied into some chosen folder, and (in case of success) the original EML file is deleted.

This macro crashes sometimes, but you can restart the macro at any time, and it will restart from where it previously crashed (remember, all successfully imported EML files are deleted). If it keeps crashing after restart, then probably there is a problem with the next EML file which is about to be imported. In this case you can just delete the problematic EML.

PS: Sometimes you can open the EML yourself, without crashing Outlook, but according to my tests, everytime that a EML file was crashing Outlook it was something unimportant, like read receipts.

Here follows my VBA code. If you have any doubts or problems, let me know.

'----------------------------------------------------
' Code by Ricardo Drizin (contact info at http://www.drizin.com.br)
'----------------------------------------------------
Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Option Explicit

'---------------------------------------------------------------------
' This method closes ActiveInspectors if any.
' All inporting is based on the assumption that the EML
' is opened by shell and we can refer to it through the ActiveInspector
'---------------------------------------------------------------------
Function CloseOpenInspectors() As Boolean
    Dim app As Outlook.Application: Set app = CreateObject("Outlook.Application")
    Dim insp As Outlook.Inspector
    Dim count As Integer
    count = 0
repeat:
    count = count + 1
    Set insp = app.ActiveInspector
    If TypeName(insp) = "Nothing" Then
        CloseOpenInspectors = True
        Exit Function
    End If
    If TypeName(insp.CurrentItem) = "Nothing" Then
        CloseOpenInspectors = True
        Exit Function
    End If
    If (count > 100) Then
        MsgBox "Error. Could not close ActiveInspector. "
        CloseOpenInspectors = False
    End If

    insp.Close (olDiscard)
    GoTo repeat
End Function


'---------------------------------------------------------------------
' This method allows user to choose a Root Folder in Outlook
' All EML files will be imported under this folder
'---------------------------------------------------------------------
Function GetRootFolder() As Outlook.folder
    Dim app As Outlook.Application: Set app = CreateObject("Outlook.Application")
    Dim NS As Outlook.NameSpace: Set NS = app.GetNamespace("MAPI")
    Dim fold As Outlook.folder
    Set fold = NS.PickFolder
    'MsgBox fold.Name
    Set GetRootFolder = fold
End Function

'---------------------------------------------------------------------
' Creates a child folder in Outlook, under root folder.
'---------------------------------------------------------------------
Function GetChildFolder(parentFolder As Outlook.folder, name As String)
    On Error Resume Next
    Dim fold2 As Outlook.folder
    Set fold2 = parentFolder.folders.Item(name)
    If Err.Number Then
        On Error GoTo 0
        Set fold2 = parentFolder.folders.Add(name)
    End If
    On Error GoTo 0
    'MsgBox fold2.Name
    Set GetChildFolder = fold2
End Function

'---------------------------------------------------------------------
' Imports the EML open in the current ActiveInspector
' into the given folder
'---------------------------------------------------------------------
Sub ImportOpenItem(targetFolder As Outlook.folder)
    Dim app As Outlook.Application: Set app = CreateObject("Outlook.Application")
    Dim insp As Outlook.Inspector: Set insp = app.ActiveInspector

    Dim retries As Integer
    retries = 0
    While TypeName(insp) = "Nothing" ' READING PANE should be visible, or else it will not work.
        'MsgWaitObj (1000)
        Sleep (50)
        DoEvents
        Sleep (50)
        Set insp = app.ActiveInspector
        retries = retries + 1
        'If retries > 100 Then
        '    Stop
        'End If
    Wend

    If TypeName(insp) = "Nothing" Then
        MsgBox "Error! Could not find open inspector for importing email."
        Exit Sub
    End If


    Dim m As MailItem, m2 As MailItem, m3 As MailItem
    Set m = insp.CurrentItem
    'MsgBox m.Subject
    Set m2 = m.Copy
    Set m3 = m2.Move(targetFolder)
    m3.Save
    Set m = Nothing
    Set m2 = Nothing
    Set m3 = Nothing
    insp.Close (olDiscard)
    Set insp = Nothing
End Sub


'---------------------------------------------------------------------
' Scans a given folder for *.EML files and import them
' into the given folder.
' Each EML file will be deleted after importing.
'---------------------------------------------------------------------
Sub ImportEMLFromFolder(targetFolder As Outlook.folder, emlFolder As String)
    If Right(emlFolder, 1) <> "\" Then emlFolder = emlFolder & "\"
    Dim firstImport As Boolean: firstImport = True

    Dim file As String
    Dim count As Integer: count = 0
    'MsgBox fold.Items.count
    'Exit Sub
    file = Dir(emlFolder & "*.eml")

repeat:
    If file = "" Then
        'MsgBox "Finished importing EML files. Total = " & count
        Debug.Print "Finished importing EML files. Total = " & count
        Exit Sub
    End If
    count = count + 1

    Debug.Print "Importing... " & file & " - " & emlFolder
    Shell ("explorer """ & emlFolder & file & """")
    'If firstImport Then Stop
    firstImport = False
    Sleep (50)
    On Error GoTo nextfile
    Call ImportOpenItem(targetFolder)
    Call Kill(emlFolder & file)
nextfile:
    On Error GoTo 0
    Sleep (50)

    file = Dir()
    GoTo repeat
End Sub

'---------------------------------------------------------------------
' Main method.
' User chooses an Outlook root Folder, and a Windows Explorer root folder.
' All EML files inside this folder and in immediate subfolders will be imported.
'---------------------------------------------------------------------
Sub ImportAllEMLSubfolders()
    Call CloseOpenInspectors

    MsgBox "Choose a root folder for importing "
    Dim rootOutlookFolder As Outlook.folder
    Set rootOutlookFolder = GetRootFolder()
    If rootOutlookFolder Is Nothing Then Exit Sub

    Dim rootWindowsFolder As String
    rootWindowsFolder = "D:\Outlook Express EMLs folder"
    rootWindowsFolder = InputBox("Choose a windows folder where you have your EML files", , rootWindowsFolder)
    If IsNull(rootWindowsFolder) Or IsEmpty(rootWindowsFolder) Or rootWindowsFolder = "" Then Exit Sub
    If Right(rootWindowsFolder, 1) <> "\" Then rootWindowsFolder = rootWindowsFolder & "\"

    Dim subFolders As New Collection

    Dim subFolder As String
    subFolder = Dir(rootWindowsFolder, vbDirectory)
repeat:
    If subFolder = "." Or subFolder = ".." Then GoTo nextdir
    If (GetAttr(rootWindowsFolder & subFolder) And vbDirectory) = 0 Then GoTo nextdir
    subFolders.Add (subFolder)
nextdir:
    subFolder = Dir()
    If subFolder <> "" Then GoTo repeat

Dim outlookFolder As Outlook.folder

' Importing main folder
Call ImportEMLFromFolder(rootOutlookFolder, rootWindowsFolder)

' Importing subfolders
While subFolders.count
    subFolder = subFolders.Item(1)
    subFolders.Remove (1)
    Set outlookFolder = GetChildFolder(rootOutlookFolder, subFolder)
    Debug.Print "Importing " & rootWindowsFolder & subFolder & " into Outlook folder " & outlookFolder.name & "..."
    Call ImportEMLFromFolder(outlookFolder, rootWindowsFolder & subFolder)
Wend
    Debug.Print "Finished"

End Sub
花想c 2024-09-12 00:57:36

很可能是更简单或更好的方法,但一种方法可能是使用 Interop 来自动化 Outlook。可能有一些使用 Outlook 内置导入功能的能力,这将是我尝试寻找的第一件事。假设这是不可能的,您仍然应该能够通过读取应用程序中的 eml 文件,然后通过 Interop 创建邮件项目来完成此操作。

通常,eml 文件只是 MIME 格式的文本文件,因此只需将它们作为文本文件读取并解析即可。 这里是一篇关于从 C# 解析 MIME 的文章,否则只需搜索“ POP3 C#”,您会找到相关的其他文章。

然后,您可以按照 此处

据猜测,我假设您可能必须首先创建一个 Application 对象,然后使用它来获取 Store 对象(我认为每个 PST 文件将是一个< code>Store),然后是其中的 Folder,然后找到某种方法使用从 eml 文件解析的数据来创建 MailItem

本文介绍如何使用 Outlook 自动化创建联系人和约会,以及可能会有用。

Might very well be easier or better ways but one way would probably be to use Interop to automate Outlook. There might be some ability to use the built in Import features of Outlook and that would be the first thing I'd try looking for. Assuming that that's not possible, you should still be able to do it by reading the eml files in your app and then creating the mail items via Interop.

Normally eml files are just text files in MIME format so that's just a matter of reading them in as text files and parsing them. Here's one article about parsing MIME from C# and otherwise just search for "POP3 C#" and you'll find other articles about that.

Then you use Outlook Interop from the namespace Microsoft.Office.Interop.Outlook as is described here.

At a guess I'd assume that you might have to first create an Application object, then use that to get the Store object (I think each PST file will be one Store) and then the Folder in there and then find some way to create the MailItem using the data you parsed from the eml file.

This article describes using Outlook automation to create contacts and appointments and could probably be useful.

初与友歌 2024-09-12 00:57:36

您可以使用 Redemption (我是它的作者)。大致思路(VBA):

  set Session = CreateObject("Redemption.RDOSession")
  Session.LogonPstStore("c:\temp\test.pst")
  set Folder = Session.GetDefaultFolder(olFolderInbox)
  set Msg = Folder.Items.Add("IPM.Note")
  Msg.Sent = true
  Msg.Import("c:\temp\test.eml", 1024)
  Msg.Save

You can use Redemption (I am its author) for that. Something along the lines (VBA):

  set Session = CreateObject("Redemption.RDOSession")
  Session.LogonPstStore("c:\temp\test.pst")
  set Folder = Session.GetDefaultFolder(olFolderInbox)
  set Msg = Folder.Items.Add("IPM.Note")
  Msg.Sent = true
  Msg.Import("c:\temp\test.eml", 1024)
  Msg.Save
横笛休吹塞上声 2024-09-12 00:57:36

您可以在此处找到 pst 文件格式的规范。但我想您会花一些时间将它们放在一起来自己创建一个 eml->pst 解析器。但这应该是可能的。

You can find the specifications to the pst file format here. But I guess you would spend some time putting it all together to create a eml->pst parser yourself. But it should be possible.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文