简体   繁体   English

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

[英]Convert multiple eml files to single PST in C#

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. 我需要编写一个函数,该函数将接收多个eml文件(可能来自单个文件系统文件夹)并将它们转换为单个PST文件。

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 我认为这是有可能的,因为有很多商业的EML到PST转换器正在这样做

Although Outlook can open EML files , there is no way to do it programatically only with VBA. 尽管Outlook可以打开EML文件 ,但是无法仅通过VBA 以编程方式进行操作 So I created this VBA macro which loops through some folder and opens each EML file using SHELL EXEC . 因此,我创建了一个VBA宏,该宏循环通过某些文件夹并使用SHELL EXEC打开每个EML文件。 It may take a few milliseconds until Outlook opens the EML file, so the VBA waits until something is open in ActiveInspector. 直到Outlook打开EML文件为止,可能要花费几毫秒的时间,因此VBA会等到在ActiveInspector中打开某些内容。 Finally, this email is copied into some chosen folder, and (in case of success) the original EML file is deleted. 最后,将这封电子邮件复制到某个选定的文件夹中,并在成功的情况下删除原始的EML文件。

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 ). 该宏有时会崩溃,但是您可以随时重新启动该宏,它将从先前崩溃的位置重新启动(请记住,所有成功导入的EML文件都将被删除 )。 If it keeps crashing after restart, then probably there is a problem with the next EML file which is about to be imported. 如果重新启动后仍然崩溃,则可能是下一个将要导入的EML文件存在问题。 In this case you can just delete the problematic EML. 在这种情况下,您可以删除有问题的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. PS:有时您可以自己打开EML而不会使Outlook崩溃,但根据我的测试,每次EML文件使Outlook崩溃时,它都是不重要的,例如已读回执。

Here follows my VBA code . 这是我的VBA代码 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

You can use Redemption for that. 您可以为此使用赎回 Something along the lines: 大致情况:

  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

Might very well be easier or better ways but one way would probably be to use Interop to automate Outlook. 可能是更好或更简单的方法,但是一种方法可能是使用Interop自动执行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. 可能有些功能可以使用Outlook的内置导入功能,而这将是我尝试寻找的第一件事。 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. 假设这不可能,那么您仍然可以通过读取应用程序中的eml文件,然后通过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. 通常,eml文件只是MIME格式的文本文件,因此只需将它们读取为文本文件并进行解析即可。 Here 's one article about parsing MIME from C# and otherwise just search for "POP3 C#" and you'll find other articles about that. 是一篇有关从C#解析MIME的文章,否则只需搜索“ POP3 C#”,您还将找到有关此内容的其他文章。

Then you use Outlook Interop from the namespace Microsoft.Office.Interop.Outlook as is described here . 然后你从命名空间中使用Outlook互操作Microsoft.Office.Interop.Outlook中被描述为在这里

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. 猜想我会假设您可能必须先创建一个Application对象,然后使用它来获取Store对象(我认为每个PST文件将是一个Store ),然后在其中找到Folder ,然后找到某种创建方法使用您从eml文件中解析的数据来处理MailItem

This article describes using Outlook automation to create contacts and appointments and could probably be useful. 文章描述了使用Outlook自动化创建联系人和约会,并很可能是有用的。

You can find the specifications to the pst file format here . 您可以在此处找到pst文件格式的规范。 But I guess you would spend some time putting it all together to create a eml->pst parser yourself. 但是我想您会花一些时间将它们放在一起以自己创建eml-> pst解析器。 But it should be possible. 但这应该是可能的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM