Microsoft.Office.Interop.outlook doesn't work - c#

I am developing a small project where I need to be able to retrieve emails from an Outlook mailbox in order to process the emails received.
I took an old program made in VB.net to rewrite it in C #.
With the project in Vb.net I have no errors
However I have this error: System.IO.FileNotFoundException : 'Could not load file or assembly 'office, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c'. The specified file can not be found.' with the C# project.
My references :
When I compare the Microsoft.Office.Interop.outlook library to the project in Vb.net installed is exactly the same (same version, etc.).
So if you have an idea to solve this problem I am interested :D

You can try the following steps to solve the System.IO.FileNotFoundException problem.
First, you need to change the current framework to .NET Core 3.0.
Second, Select Interop.Microsoft.Office.Interop.Outlook, right click properties and set "Embed Interop Types" to "Yes".
Finally, you can use the following code to retrieve emails from an Outlook mailbox.
using Outlook = Microsoft.Office.Interop.Outlook;
Outlook.Application oApp = null;
oApp = new Outlook.Application();
Outlook.NameSpace nameSpace = oApp.GetNamespace("MAPI");
Outlook.Items items = null;
try
{
// use default profile and DO NOT pop up a window
// on some pc bill gates fails to login without the popup, then we must pop up and lets use choose profile and allow access
nameSpace.Logon("", "", false, Missing.Value);
var folder = nameSpace.Folders["emailaddress"].Folders["Folder"];
items = folder.Items;
foreach (Outlook.MailItem item in items)
{
Console.WriteLine(item.Subject);
}
Console.WriteLine("yes");
Console.ReadKey();
}
catch (Exception)
{
// use default profile and DO pop up a window
nameSpace.Logon("", "", true, true);
}

Related

Precompiled .net 4.0 app wont run on other windows installations (error: trying to load assembly from network address)

Solution: I had to click "Unblock" in the file properties dialog in Windows Explorer.
I made an app in c# because i thought it will work on all windows versions. Today i was at my fathers place and downloaded my precompiled app from github. It was running but totally not as expected! Highlighted rows in a gridview wasnt visible, scollbars on a tabcontrol wasnt working and some other more or less small bugs. I had no time to download visual studio to recompile it but is this usual behavior? My father is running on windows 7 and i saw .NET framework 4.5 was installed - i compiled my app using v4.0 so i thought there should be no compatibility issues. I also created a Windows10 virtual machine at home after that and recognized it was the same behavior. I know highlighted rows or scrollbars are not that important but i also have a plugin system to load and reflect additional libraries and thats a basic feature of my app. And the assembly loader will NOT work either - just on the machine i have compiled on.
Should i compile it on multiple versions to support any "unknown" user and its operationg system? I saw that microsoft say i can determine the users version using https://learn.microsoft.com/en-us/dotnet/framework/migration-guide/how-to-determine-which-versions-are-installed but i can do it after my app is installed so should i create some downloader to download the correct version after installation or how is this meant?
Edit i uploaded a video on youtube to show how it should work and how it accuaally works.. https://www.youtube.com/watch?v=DTQa8WlECa8
Edit I got an error message stating (translated from native german) "It was tried to load an assembly from a network address" but i dont understand this message, i never do so.. I load assemblies using
private void m_btnRegisterModule_Click(object objectSender, EventArgs eventArgs)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Multiselect = true;
openFileDialog.Title = "Register Stack";
openFileDialog.Filter = "Assemblies (*.exe, *.dll)|*.exe;*.dll|All Files (*.*)|*.*";
if (openFileDialog.ShowDialog(this) == DialogResult.Cancel) return;
Assembly assembly = null;
foreach (String file in openFileDialog.FileNames)
{
try
{
assembly = System.Reflection.Assembly.LoadFile(file);
} catch (Exception) { return; }
Type[] arrayTypes = assembly.GetExportedTypes();
foreach (Type type in arrayTypes)
{
if (!typeof(ScriptStack.Runtime.Stack).IsAssignableFrom(type)) continue;
ConstructorInfo constructorInfo = null;
try
{
constructorInfo = type.GetConstructor(new Type[0]);
}
catch (Exception) { continue; }
try
{
object objectHostModule = constructorInfo.Invoke(new object[0]);
ScriptStack.Runtime.Stack hostModule = (ScriptStack.Runtime.Stack)objectHostModule;
m_scriptManager.RegisterHostStack(hostModule);
}
catch (Exception) { continue; }
}
}
UpdateModuleControl();
pluginFilter.Select();
}
I found .net local assembly load failed with CAS policy and try to load it.. otherwise. lets see how. For now i created a messagebox to see the exact exception.
Edit Solution: I had to click "Unblock" in the file properties dialog in Windows Explorer.
Clicking "Unblock" in the file properties dialog in Windows Explorer solved my issue in some way. By "in some way" i mean i cant expect everybody to know this so someone will just think its not working crap and drop the app.. i guess

C# start Outlook in different security context

We have a WPF application need to display a new Outlook item, allow user to edit before send. The application start with administrator privileges, so if user's Outlook opened already, then there's an error when getting Outlook instance. How to solve it? Please help me, thanks.
You can't automate Outlook if it is run under different security context. But you can detect such cases trying to get an Outlook instance using the Marshal.GetActiveObject method which obtains a running instance of the specified object from the running object table (ROT). For example:
Outlook.Application GetApplicationObject()
{
Outlook.Application application = null;
// Check whether there is an Outlook process running.
if (Process.GetProcessesByName("OUTLOOK").Count() > 0)
{
// If so, use the GetActiveObject method to obtain the process and cast it to an Application object.
application = Marshal.GetActiveObject("Outlook.Application") as Outlook.Application;
if(application == null)
MessageBox.Show("You need to run Outlook under the same security context");
}
else
{
// If not, create a new instance of Outlook and log on to the default profile.
application = new Outlook.Application();
Outlook.NameSpace nameSpace = application.GetNamespace("MAPI");
nameSpace.Logon("", "", Missing.Value, Missing.Value);
nameSpace = null;
}
// Return the Outlook Application object.
return application;
}
So, when the Outlook.exe process exists and you can't get the object all you can do is to ask users to run the application under the same security context.
There isn't much you can do short of starting your app in the same security context.

Create outlook .msg file in C#

I am trying to create outlook .msg format file using my C# code.
I have used below 2 code:
Method 1 :
Microsoft.Office.Interop.Outlook.Application objOutlook = new Microsoft.Office.Interop.Outlook.Application();
// Creating a new Outlook message from the Outlook Application instance
Microsoft.Office.Interop.Outlook.MailItem msgInterop = (Microsoft.Office.Interop.Outlook.MailItem)(objOutlook.CreateItem(Microsoft.Office.Interop.Outlook.OlItemType.olMailItem));
// Set recipient information
msgInterop.To = "neha1#gmail.com";
msgInterop.CC = "neha#gmail.com";
// Set the message subject
msgInterop.Subject = "Subject";
// Set some HTML text in the HTML body
msgInterop.HTMLBody = "<h3>HTML Heading 3</h3> <u>This is underlined text</u>";
// Save the MSG file in local disk
string strMsg = #"c:\\temp\TestInterop.msg";
msgInterop.SaveAs(strMsg, Microsoft.Office.Interop.Outlook.OlSaveAsType.olMSG);
Second method :
Redemption.RDOSession Session = new RDOSession();
Redemption.RDOMail Msg = Session.CreateMessageFromMsgFile(#"c:\temp\YourMsgFile.msg");
Msg.Sent = true;
Msg.Subject = "test";
Msg.Body = "test body";
Msg.Recipients.AddEx("the user", "user#domain.demo", "SMTP", rdoMailRecipientType.olTo);
Msg.Save();
Both method gives error on executing as below :
System.Runtime.InteropServices.COMException (0x8004010F): Creating an
instance of the COM component with CLSID
{29AB7A12-B531-450E-8F7A-EA94C2F3C05F} from the IClassFactory failed
due to the following error: 8004010f Exception from HRESULT:
0x8004010F.
I have researched and found some compatibility issue with platform. I tried to change the platform from 32-bit to x64. Still it did not resolve my problem.
Is outlook installed and in a runnable state on the machine you are doing this from? The error is that the com component isn't registered, which usually would mean you just copied dlls from another machine which didn't register the com ones.
So either install outlook, or install this
https://www.microsoft.com/en-us/download/details.aspx?id=1004
I installed Outlook on my system. And the code I had posted above (Microsoft.Office.Interop.Outlook.Application) works like a charm :) .

How to get information about current user distribution list from outlook using WPF business app

In my WPF app, I need to enable/disable functionality based on the team. The team information is configured as outlook distribution list. Now I need retrieve this information from my App.
I googled and found the link
http://msdn.microsoft.com/EN-US/library/office/ff184638(v=office.15).aspx
Unfortunately it doesn't compile as it is. After bit of research I can make it compile by changing it by changing it as
currentUser = new Outlook.Application().Session.CurrentUser.AddressEntry;
However, this works only when outlook is opened, but when outlook is closed it throws the exception. Any idea?
Finally I managed to crack it. Apparently we need to briefly start the outlook application, the solution is explained in the link
https://groups.google.com/forum/#!msg/microsoft.public.outlook.program_vba/lLJwbwwl-XU/gRuQYRpJtxEJ
Hence I modified my code GetCurrentUserMembership() slightly to accomadate this change. Now it's working good. Tested in outlook 2007 and 2010.
The complete solution,
private List<string> GetCurrentUserMembership()
{
Outlook.Application outlook = new Outlook.Application();
Outlook.MailItem oMsg = (Outlook.MailItem)outlook.CreateItem(Outlook.OlItemType.olMailItem);
Outlook.Inspector oInspector = oMsg.GetInspector;
//session.Logon("", "", false, false);
var sb = new List<string>();
Outlook.AddressEntry currentUser = outlook.Session.CurrentUser.AddressEntry;
if (currentUser.Type != "EX") return sb;
var exchUser = currentUser.GetExchangeUser();
if (exchUser == null) return sb;
var addrEntries = exchUser.GetMemberOfList();
if (addrEntries == null) return sb;
foreach (Outlook.AddressEntry addrEntry in addrEntries)
{
sb.Add(addrEntry.Name);
}
return sb;
}
Could you please be more specific? What exception (error message and error code) do you get in the code?
I'd recommend starting from breaking the chain of calls and declare each property or method call on a separate line. Thus, you will find a problematic property or method call which fires an exception.
Most probably you need to call the Logon method of the Namespace class. As an example, you may find the C# app automates Outlook (CSAutomateOutlook) sample project helpful.

Outlook Interop 2010 C# Moving Item to Shared OlDefaultFolders.olFolderSentMail

SOmething odd is happening. I'm trying to copy and move and item from a local MAPI folder to a remtoe Sent Items folder using GetSharedDefaultFolder. It works for the inbox folder but not sent items, even though i have permissions to it. Any ideas would be great thank you.
The Error is 'Could not complete the operation. One or more parameter values are not valid'
The code sample is:
Outlook.MailItem cItem = (mailmsg as Outlook.MailItem).Copy() as Outlook.MailItem;
Outlook.NameSpace ns = this.Application.GetNamespace("MAPI");
//ns.Logon()
Outlook.Recipient recipient = ns.CreateRecipient("realusera#domain.com");
recipient.Resolve();
if (recipient.Resolved)
{
MessageBox.Show("Resolved user");
Outlook.MAPIFolder mapifld = ns.GetSharedDefaultFolder(recipient, Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderSentMail);
cItem = (Outlook.MailItem)cItem.Move(mapifld);
}
According to MS documentation on this API, the olFolderSentMail is one of the default folders that is NOT allowed.
http://msdn.microsoft.com/en-us/library/microsoft.office.interop.outlook._namespace.getshareddefaultfolder.aspx
Excerpt:
FolderType can be one of the following OlDefaultFolders constants: olFolderCalendar, olFolderContacts, olFolderDrafts, olFolderInbox, olFolderJournal, olFolderNotes, or olFolderTasks. (The constants olFolderDeletedItems, olFolderOutbox, olFolderJunk, olFolderConflicts, olFolderLocalFailures, olFolderServerFailures, olFolderSyncIssues, olPublicFoldersAllPublicFolders, olFolderRssSubscriptions, olFolderToDo, olFolderManagedEmail, and olFolderSentMail cannot be specified for this argument.)

Categories

Resources