I need create a outlook .msg file by IIS, it is ok when I run it in "IIS Express", but can not run in IIS even set applicationpool to LocalSystem.
Error message:Operation aborted (Exception from HRESULT: 0x80004004 (E_ABORT)) at Microsoft.Office.Interop.Outlook.Attachments.Add(Object Source, Object Type, Object Position, Object DisplayName)
Environment: Win7 32bit, Office 2010, Vistual Studio Pro 2013
Source code as following:
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
Microsoft does not currently recommend, and does not support, Automation of Microsoft Office applications from any unattended, non-interactive client application or component (including ASP, ASP.NET, DCOM, and NT Services), because Office may exhibit unstable behavior and/or deadlock when Office is run in this environment.
If you are building a solution that runs in a server-side context, you should try to use components that have been made safe for unattended execution. Or, you should try to find alternatives that allow at least part of the code to run client-side. If you use an Office application from a server-side solution, the application will lack many of the necessary capabilities to run successfully. Additionally, you will be taking risks with the stability of your overall solution.
Read more about that in the Considerations for server-side Automation of Office article.
Your options are
Extended MAPI (OpenImsgOnIStg etc.) to create an MSG file and set all the relevant MAPI properties, but it is only accessible from the C++ or Delphi
Use Windows API to build the file explicitly in your code (it's format is documented) - https://msdn.microsoft.com/en-us/library/cc463912(v=exchg.80).aspx
Use Redemption - it is an Extended MAPI wrapper that can be used from a service in any language including C#, VB.Net or VB script:
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
Thanks All, At last I do it as following: 1. Create a template .msg file by outlook manually. 2. Open it and copy to a new stream. Many code for this from intenet. 3. Update my information to this stream, and save as a new .msg file. (Following is source when I update attachment file in .msg file, and you should get other source from 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);
I use System.Net.Mail instead - https://msdn.microsoft.com/en-us/library/system.net.mail(v=vs.110).aspx
You set up a MailMessage, you can add attachments and set importance, and do everything you're doing above.
This works very well for me, and you don't need to install anything on the server.
EDIT
Here's some sample code for you - import the System.Net.Mail
and System.Configuration
namespaces. In this example, I'm sending a log, so I get the to addresses and SMTP relay from App.Config. You can change these for what you need.
This also attaches a file from a location also specified in 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);
User contributions licensed under CC BY-SA 3.0