ASP.NET无法调用outlook函数来创建.msg文件

时间:2015-04-17 12:02:40

标签: asp.net outlook msg

我需要通过IIS创建一个outlook .msg文件,当我在" IIS Express"中运行它时可以,但是无法在IIS中运行,甚至将应用程序池设置为LocalSystem。

错误消息:Microsoft.Office.Interop.Outlook.Attachments.Add(对象源,对象类型,对象位置,对象显示名称)中的操作已中止(来自HRESULT的异常:0x80004004(E_ABORT))

环境:Win7 32位,Office 2010,Vistual Studio Pro 2013

源代码如下:

    Try
        Dim oApp As Interop.Outlook._Application
        Dim oMsg As Interop.Outlook._MailItem
        oApp = New Interop.Outlook.Application
        oMsg = oApp.CreateItem(Interop.Outlook.OlItemType.olMailItem)
        oMsg.Subject = "Test Subject"
        oMsg.Body = "Test Body"
        oMsg.To = ""

        Dim attachedFilePath As String = "C:\\temp\\A1234563A.zip"
        If String.IsNullOrEmpty(attachedFilePath) = False Then
            Dim sBodyLen As Integer = Int(oMsg.Body)
            Dim oAttachs As Interop.Outlook.Attachments = oMsg.Attachments
            Dim oAttach As Interop.Outlook.Attachment
            oAttach = oAttachs.Add(attachedFilePath, , sBodyLen, "A1234563A.zip")
        End If
        oMsg.SaveAs("c:\\temp\\abcd.msg", Microsoft.Office.Interop.Outlook.OlSaveAsType.olMSG)

    Catch ex As System.Exception
        'xxxxx
    Finally
       GC.Collect()
       GC.WaitForPendingFinalizers()
    End Try

4 个答案:

答案 0 :(得分:2)

Microsoft目前不建议也不支持从任何无人参与的非交互式客户端应用程序或组件(包括ASP,ASP.NET,DCOM和NT服务)自动化Microsoft Office应用程序,因为Office在此环境中运行Office时,可能会出现不稳定的行为和/或死锁。

如果要构建在服务器端上下文中运行的解决方案,则应尝试使用已为安全无人值守执行的组件。或者,您应该尝试找到允许至少部分代码在客户端运行的替代方法。如果从服务器端解决方案使用Office应用程序,则应用程序将缺少许多成功运行的必要功能。此外,您将承担整体解决方案稳定性的风险。

Considerations for server-side Automation of Office文章中详细了解相关内容。

答案 1 :(得分:1)

您的选择

  1. 扩展MAPI(OpenImsgOnIStg等)以创建MSG文件并设置所有相关的MAPI属性,但只能从C ++或Delphi访问

  2. 使用Windows API在代码中显式构建文件(文档格式已记录) - https://msdn.microsoft.com/en-us/library/cc463912(v=exchg.80).aspx

  3. 使用Redemption - 它是一个扩展MAPI包装器,可以使用任何语言的服务使用,包括C#,VB.Net或VB脚本:

  4. 
    
          set Session = CreateObject("Redemption.RDOSession")
          set Msg = Session.CreateMessageFromMsgFile("C:\Temp\test.msg")
          Msg.Sent = true
          set recip = Msg.Recipients.AddEx("This user", "this.user@domain.demo", "SMTP", olTo)
          Msg.Subject = "fake received message"
          Msg.Body = "just a test"
          Msg.SentOn = Now
          Msg.ReceivedTime = Now
          'set the sender related properties
          vSenderEntryId = Session.CreateOneOffEntryID("Joe The Sender", "SMTP", "joe@domain.demo", false, true)
          'PR_SENDER_xyz
          Msg.Fields("http://schemas.microsoft.com/mapi/proptag/0x0C1E001F") = "SMTP"
          Msg.Fields("http://schemas.microsoft.com/mapi/proptag/0x0C1F001F") = "joe@domain.demo"
          Msg.Fields("http://schemas.microsoft.com/mapi/proptag/0x0C190102") = vSenderEntryId
          Msg.Fields("http://schemas.microsoft.com/mapi/proptag/0x0C1A001F") = "Joe The Sender"
          'PR_SENT_REPRESENTING_xyz
          Msg.Fields("http://schemas.microsoft.com/mapi/proptag/0x0064001F") = "SMTP"
          Msg.Fields("http://schemas.microsoft.com/mapi/proptag/0x0065001F") = "joe@domain.demo"
          Msg.Fields("http://schemas.microsoft.com/mapi/proptag/0x00410102") = vSenderEntryId
          Msg.Fields("http://schemas.microsoft.com/mapi/proptag/0x0042001F") = "Joe The Sender"
          'all done
          Msg.Save
    
    
    

答案 2 :(得分:1)

谢谢大家,最后我按照以下方式做到: 1.手动创建模板.msg文件。 2.打开它并复制到新流。很多来自intenet的代码。 3.将我的信息更新到此流,并另存为新的.msg文件。 (当我在.msg文件中更新附件文件时,以下是源代码,您应该从OutlookStorage.cs获取其他源代码)。

//create a ILockBytes (unmanaged byte array) and then create a IStorage using the byte array as a backing store
NativeMethods.CreateILockBytesOnHGlobal(IntPtr.Zero, true, out memoryStorageBytes);
                    NativeMethods.StgCreateDocfileOnILockBytes(memoryStorageBytes, NativeMethods.STGM.CREATE | NativeMethods.STGM.READWRITE | NativeMethods.STGM.SHARE_EXCLUSIVE, 0, out memoryStorage);

//copy the save storage into the new storage
saveMsg.storage.CopyTo(0, null, IntPtr.Zero, memoryStorage);

//Attachments (37xx):
//0x3701: Attachment data       <- This is the binary attachment
//0x3703: Attach extension
//0x3704: Attach filename
//0x3707: Attach long filenm
//0x370E: Attach mime tag
//0x3712: Attach ID (?)

// replace attachment with myself file
var myNameIdSourceStorage = memoryStorage.OpenStorage(OutlookStorage.ATTACH_STORAGE_PREFIX + "00000000", IntPtr.Zero, NativeMethods.STGM.READWRITE | NativeMethods.STGM.SHARE_EXCLUSIVE,IntPtr.Zero, 0);
                                     myNameIdSourceStorage.DestroyElement("__substg1.0_37010102");

// Create the property stream again and write in the padded version
var pStream = myNameIdSourceStorage.CreateStream("__substg1.0_37010102",
                        NativeMethods.STGM.READWRITE | NativeMethods.STGM.SHARE_EXCLUSIVE, 0, 0);
pStream.Write(newFileByte, newFileByte.Length, IntPtr.Zero);

// Open stream from the storage
var mystream = myNameIdSourceStorage.OpenStream("__properties_version1.0", IntPtr.Zero,
                        NativeMethods.STGM.READWRITE | NativeMethods.STGM.SHARE_EXCLUSIVE, 0);

System.Runtime.InteropServices.ComTypes.STATSTG elementStats;
mystream.Stat(out elementStats, 0);                    

// Read the stream into a managed byte array
var iStreamContent = new byte[elementStats.cbSize];
mystream.Read(iStreamContent, iStreamContent.Length, IntPtr.Zero);
iStreamContent[0xc0] = (byte)(newFileByte.Length & 0xFF);
iStreamContent[0xc1] = (byte)(newFileByte.Length >> 8);
iStreamContent[0xc2] = (byte)(newFileByte.Length >> 16);
iStreamContent[0xc3] = (byte)(newFileByte.Length >> 24);
mystream.Write(iStreamContent, 0, IntPtr.Zero);

//0x3704: Attach filename
myNameIdSourceStorage.DestroyElement("__substg1.0_3704001F");
pStream = myNameIdSourceStorage.CreateStream("__substg1.0_3704001F",
                        NativeMethods.STGM.READWRITE | NativeMethods.STGM.SHARE_EXCLUSIVE, 0, 0);
pStream.Write(newProps, 8, IntPtr.Zero);

答案 3 :(得分:0)

我使用System.Net.Mail代替 - https://msdn.microsoft.com/en-us/library/system.net.mail(v=vs.110).aspx

您设置了一个MailMessage,您可以添加附件并设置重要性,并执行您在上面执行的所有操作。

这对我来说效果很好,而且您不需要在服务器上安装任何东西。

修改

以下是一些示例代码 - 导入System.Net.MailSystem.Configuration命名空间。在这个例子中,我发送一个日志,所以我从App.Config获取地址和SMTP中继。您可以根据需要更改这些。

这也会从App.Config中指定的位置附加文件。

string[] recipients = ConfigurationManager.AppSettings["recipients"].ToString().Split(',');


            MailMessage msg = new MailMessage();
            msg.From = new MailAddress("noreply@somewhere.com");
            msg.Subject = "Log Error Report";

            foreach (string addr in recipients)
            {
                msg.To.Add(new MailAddress(addr));
            }

            string body = System.Environment.NewLine + "Please check these logs for errors.";
            body += System.Environment.NewLine + "Message line 2";

            msg.Body = body;
            msg.Priority = MailPriority.High;

            String attchMnts = ConfigurationManager.AppSettings["logfile"].ToString();
            String[] attchPaths = attchMnts.Split(',');

            foreach (string path in attchPaths)
            {
                Attachment atch = new Attachment(path);
                msg.Attachments.Add(atch);
            }

            SmtpClient client = new SmtpClient(ConfigurationManager.AppSettings["smtpRelay"].ToString());
            client.Send(msg);