Okay, I have no problem identifying the .PST file using the Outlook Interop assemblies in a C# app. But as soon as I hit a password protected file, I am prompted for a password.
We are in the process of disabling the use of PSTs in our organization and one of the steps is to unload the PST files from the users' Outlook profile.
I need to have this app run silently and not prompt the user. Any ideas? Is there a way to create the Outlook.Application object with no UI and then just try to catch an Exception on password protected files?
// create the app and namespace
Application olApp = new Application();
NameSpace olMAPI = olApp.GetNamespace("MAPI");
// get the storeID of the default inbox
string rootStoreID = olMAPI.GetDefaultFolder(OlDefaultFolders.olFolderInbox).StoreID;
// loop thru each of the folders
foreach (MAPIFolder fo in olMAPI.Folders)
{
// compare the first 75 chars of the storeid
// to prevent removing the Inbox folder.
string s1 = rootStoreID.Substring(1, 75);
string s2 = fo.StoreID.Substring(1, 75);
if (s1 != s2)
{
// unload the folder
olMAPI.RemoveStore(fo);
}
}
olApp.Quit();
Yes you can automate outlook from another app.
There is a Logon method on the NameSpace object so that you can logon to the profile then you can do anything that you want. But I think that it will just pop up the prompt again as it automation but ..There is a 3rd libray that may help you as well to do this as it does it via mapi instead. checkout profman.dll in the redemption libray
Related
I am having trouble remembering my Outlook PST password, and cannot import that file into Outlook 2016. I have tried several forums, free password recovery software tools, but could not reset/recover the password. After browsing a lot, I found out Aspose.Email for .NET has a backdoor to access the properties of PST file and there's a way to reset password. I have no idea about this, and have never used .NET or C#. Is there someone who can help me out here?
Following are the related links from my browsing results:
Aspose.Email for .NET - https://dzone.com/articles/how-to-check-set-remove-or-update-password-of-pst
PST Password Property - https://msdn.microsoft.com/en-us/library/ff385916(v=office.12).aspx
Please note my PST is UNICODE and not ANSI format, so following is already out of question.
http://www.itninja.com/blog/view/how-to-unlock-password-protected-pst-file-6
This is what I have tried online #https://dotnetfiddle.net/:
using System;
using Aspose.Email.Mapi;
using Aspose.Email.Storage.Pst;
namespace Aspose.Email.Examples.CSharp.Email.Outlook
{
class RemovingPaswordProperty
{
public static void Run()
{
// The path to the File directory.
// ExStart:RemovingPaswordProperty
string dataDir = RunExamples.GetDataDir_Outlook();
PersonalStorage personalStorage = PersonalStorage.FromFile(dataDir + "PersonalStorage1.pst");
if (personalStorage.Store.Properties.ContainsKey(MapiPropertyTag.PR_PST_PASSWORD))
{
MapiProperty property = new MapiProperty(MapiPropertyTag.PR_PST_PASSWORD, BitConverter.GetBytes((long)0));
personalStorage.Store.SetProperty(property);
}
// ExEnd:RemovingPaswordProperty
}
}
}
and I am getting following errors:
Error(s):
Compilation error (line 14, col 30): The name 'RunExamples' does not exist in the current context
I have user myuser that logged in in windows and I open the program with otheruser.
I need that then I open new mail in outlook it will open it with myuser. The code that I'm using is:
Outlook.Application App = new Outlook.Application();
Outlook._MailItem MailItem = (Outlook._MailItem)App.CreateItem(Outlook.OlItemType.olMailItem);
MailItem.To = BossName.Text;
MailItem.CC = ClientName.Text;
MailItem.Display(true);
Start your application in the context of the desired user, or
you may use Impersonation:
WindowsIdentity.Impersonate Method
Be sure that outlook doesn't run in your session already. Outlook can only run once in a session - so it's not possible to logon with different Outlook-MAPI-Sessions in one Windows-Session at the same time. You Always have to reopen outlook.
Multible Outlook-Profiles
Another way is to configure multible Outlook profiles and start outlook via .net and pass the Profilename. But this can be a little bit tricky, because you always have to check if outlook isnt already running in a different profilecontext - because the Profile-Parameter will be ignored if outlook has already been opened.
class Sample
{
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. Or close Outlook to open a new instance with a desired profile
application = Marshal.GetActiveObject("Outlook.Application") as Outlook.Application;
//!! Check if the application is using the right profile - close & reopen if necessary
}
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("profilename", "", Missing.Value, Missing.Value);
nameSpace = null;
}
// Return the Outlook Application object.
return application;
}
}
If possible use EWS
Another approach would be to use EWS-API (Exchange WebServices-API) but this presupposes to have an Exchange or Office365 account. And is only usefull if you want to deal with outlook-items in the background (.Display() is not possible)
If you are using an Exchange-Account (Office365) i would prefer to do it that way...
Get started with EWS Managed API client applications
i write the code in asp.net using c# to delete the file in my computer, but it is not deleting please help me thank u. this is my code, i write in button click event
string path = "E:\\sasi\\delt.doc";
FileInfo myfileinf = new FileInfo(path);
myfileinf.Delete();
public void DeleteFileFromFolder(string StrFilename)
{
string strPhysicalFolder = Server.MapPath("..\\");
string strFileFullPath = strPhysicalFolder + StrFilename;
if (IO.File.Exists(strFileFullPath)) {
IO.File.Delete(strFileFullPath);
}
}
In order to delete a file you must ensure that the account has sufficient permissions. In general ASP.NET applications run under limited permission account such as Network Service. For example if your application runs under IIS 6 you could go to the Administration Console and set a custom account in the application pool properties:
alt text http://i.msdn.microsoft.com/Bb969101.SharePoint_SQL_TshootingFig3%28en-US,SQL.90%29.jpg
You need to ensure that the account is member of the IIS_WPG group.
Make sure the ASP user has permissions to this folder. By default this user is not given access to much of the harddrive..
Is it possible to read a .PST file using C#? I would like to do this as a standalone application, not as an Outlook addin (if that is possible).
If have seen other SO questions similar to this mention MailNavigator but I am looking to do this programmatically in C#.
I have looked at the Microsoft.Office.Interop.Outlook namespace but that appears to be just for Outlook addins. LibPST appears to be able to read PST files, but this is in C (sorry Joel, I didn't learn C before graduating).
Any help would be greatly appreciated, thanks!
EDIT:
Thank you all for the responses! I accepted Matthew Ruston's response as the answer because it ultimately led me to the code I was looking for. Here is a simple example of what I got to work (You will need to add a reference to Microsoft.Office.Interop.Outlook):
using System;
using System.Collections.Generic;
using Microsoft.Office.Interop.Outlook;
namespace PSTReader {
class Program {
static void Main () {
try {
IEnumerable<MailItem> mailItems = readPst(#"C:\temp\PST\Test.pst", "Test PST");
foreach (MailItem mailItem in mailItems) {
Console.WriteLine(mailItem.SenderName + " - " + mailItem.Subject);
}
} catch (System.Exception ex) {
Console.WriteLine(ex.Message);
}
Console.ReadLine();
}
private static IEnumerable<MailItem> readPst(string pstFilePath, string pstName) {
List<MailItem> mailItems = new List<MailItem>();
Application app = new Application();
NameSpace outlookNs = app.GetNamespace("MAPI");
// Add PST file (Outlook Data File) to Default Profile
outlookNs.AddStore(pstFilePath);
MAPIFolder rootFolder = outlookNs.Stores[pstName].GetRootFolder();
// Traverse through all folders in the PST file
// TODO: This is not recursive, refactor
Folders subFolders = rootFolder.Folders;
foreach (Folder folder in subFolders) {
Items items = folder.Items;
foreach (object item in items) {
if (item is MailItem) {
MailItem mailItem = item as MailItem;
mailItems.Add(mailItem);
}
}
}
// Remove PST file from Default Profile
outlookNs.RemoveStore(rootFolder);
return mailItems;
}
}
}
Note: This code assumes that Outlook is installed and already configured for the current user. It uses the Default Profile (you can edit the default profile by going to Mail in the Control Panel). One major improvement on this code would be to create a temporary profile to use instead of the Default, then destroy it once completed.
The Outlook Interop library is not just for addins. For example it could be used to write a console app that just reads all your Outlook Contacts. I am pretty sure that the standard Microsoft Outlook Interop library will let you read the mail - albeit it will probably throw a security prompt in Outlook that the user will have to click through.
EDITS: Actually implementing mail reading using Outlook Interop depends on what your definition of 'standalone' means. The Outlook Interop lib requires Outlook to be installed on the client machine in order to function.
// Dumps all email in Outlook to console window.
// Prompts user with warning that an application is attempting to read Outlook data.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Outlook = Microsoft.Office.Interop.Outlook;
namespace OutlookEmail
{
class Program
{
static void Main(string[] args)
{
Outlook.Application app = new Outlook.Application();
Outlook.NameSpace outlookNs = app.GetNamespace("MAPI");
Outlook.MAPIFolder emailFolder = outlookNs.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderInbox);
foreach (Outlook.MailItem item in emailFolder.Items)
{
Console.WriteLine(item.SenderEmailAddress + " " + item.Subject + "\n" + item.Body);
}
Console.ReadKey();
}
}
}
I went through and did the refactoring for subfolders
private static IEnumerable<MailItem> readPst(string pstFilePath, string pstName)
{
List<MailItem> mailItems = new List<MailItem>();
Microsoft.Office.Interop.Outlook.Application app = new Microsoft.Office.Interop.Outlook.Application();
NameSpace outlookNs = app.GetNamespace("MAPI");
// Add PST file (Outlook Data File) to Default Profile
outlookNs.AddStore(pstFilePath);
string storeInfo = null;
foreach (Store store in outlookNs.Stores)
{
storeInfo = store.DisplayName;
storeInfo = store.FilePath;
storeInfo = store.StoreID;
}
MAPIFolder rootFolder = outlookNs.Stores[pstName].GetRootFolder();
// Traverse through all folders in the PST file
Folders subFolders = rootFolder.Folders;
foreach (Folder folder in subFolders)
{
ExtractItems(mailItems, folder);
}
// Remove PST file from Default Profile
outlookNs.RemoveStore(rootFolder);
return mailItems;
}
private static void ExtractItems(List<MailItem> mailItems, Folder folder)
{
Items items = folder.Items;
int itemcount = items.Count;
foreach (object item in items)
{
if (item is MailItem)
{
MailItem mailItem = item as MailItem;
mailItems.Add(mailItem);
}
}
foreach (Folder subfolder in folder.Folders)
{
ExtractItems(mailItems, subfolder);
}
}
As already mentioned in one of your linked SO questions, I'd also recommend using the Redemption library. I'm using it in a commercial application for processing Outlook mails and performing various tasks with them. It's working flawlessly and prevents showing up the annoying security alerts. It would mean using COM Interop, but that shouldn't be a problem.
There's a library in that package called RDO which is replacing the CDO 1.21, which lets you access PST files directly. Then it's as easy as writing (VB6 code):
set Session = CreateObject("Redemption.RDOSession")
'open or create a PST store
set Store = Session.LogonPstStore("c:\temp\test.pst")
set Inbox = Store.GetDefaultFolder(6) 'olFolderInbox
MsgBox Inbox.Items.Count
You can use pstsdk.net: .NET port of PST File Format SDK library which is open source to read pst file without Outlook installed.
Try Pstxy.
It provide .Net API to read Outlook PST & OST file without need for Outlook installed.
It has a free version to extract mail content (text, html & rtf). The plus version support attachments, too.
For those mentioning that they don't see the Stores collection:
The Stores collection was added in Outlook 2007. So, if you're using an interop library created from an earlier version (in an attempt to be version independent - this is ver common) then this would be why you won't see the Stores collection.
Your only options to get the Stores are to do one of the following:
Use an interop library for Outlook 2007 (this means your code won't work for earlier versions of Outlook).
Enumerate all top level folders with Outlook object model, extract the StoreID of each folder, and then use CDO or MAPI interfaces to get more information about each store.
Enumerate the InfoStores collection of CDO session object, and then use the fields collection of InfoStore object in order to get more information about each store.
Or (the hardest way) use extended MAPI call (In C++): IMAPISession::GetMsgStoresTable.
We are going to use this, to provide a solution that doesn't rely on outlook.
http://www.independentsoft.de/pst/index.html
It is very expensive, but we hope that will lower development time and increase quality.
I found some resources directly from Microsoft which may be helpful for completing this task. A search on MSDN reveals the following.
How to use the Microsoft Outlook Object Library to retrieve a message from the Inbox by using Visual C#
How to use the Microsoft Outlook Object Library to retrieve an appointment by using Visual C#
Note that when you're adding a reference to Microsoft.Office.Interop.Outlook, the documentation insists that you do so via the .NET tab instead of the COM tab.
The MAPI API is what you are looking for. Unfortunately it is not available in .Net so I'm afraid you will have to resort to calling unmanaged code.
A quick Google reveals several wrappers available, maybe they work for you?
This might also be helpful: http://www.wischik.com/lu/programmer/mapi_utils.html
This .NET connector for Outlook might get you started.
Yes, with Independentsoft PST .NET is possible to read/export password protected and encrypted .pst file.
Really usefull code. If you have pst and store your messages in its root (without any directory), then you can use the following in method readPst:
MAPIFolder rootFolder = outlookNs.Stores[pstName].GetRootFolder();
Items items = rootFolder.Items;
foreach (object item in items)
{
if (item is MailItem)
{
MailItem mailItem = item as MailItem;
mailItems.Add(mailItem);
}
}
Yes you can use MS Access and then you either import your pst content or just link it (slow!).
The use case is simple. At a certain point of time, I need to be able to show the user his familiar compose email dialog (Outlook or other) with
fields like from, to, Subject already filled up with certain application determined values.
The email would also have an attachment along with it.
The mail should not be sent unless the user explicitly okays it.
I did this once back in the ol' VB6 days.. can't figure out how now.. I just remember that it was quite easy.
Managed app, C#, .net 3.0+
Update#1: Yeah seems like mailto removed support for attachments (as a security risk?). I tried
You need to include ShellExecute signature as described here. All I got from this was a 5 SE_ERR_ACCESSDENIED and a 2 just for some variety
string sMailToLink = #"mailto:some.address#gmail.com?subject=Hey&body= yeah yeah yeah";
IntPtr result = ShellExecute(IntPtr.Zero, "open", sMailToLink, "", "", ShowCommands.SW_SHOWNORMAL);
Debug.Assert(result.ToInt32() > 32, "Shell Execute failed with return code " + result.ToInt32());
The same MailtoLink works perfectly with Process.Start... but as long as thou shalt not mention attachments.
System.Diagnostics.Process.Start(sMailToLink);
The other options are using the Outlook Object model to do this.. but I've been told that this requires you to add assembly references based to the exact version of Outlook installed. Also this would blow up if the user doesn't prefer MS for email.
The next option are Mapi and something called Mapi33.. Status still IN PROGRESS. Ears still open to suggestions.
You can create a process object and have it call "mailto:user#example.com?subject=My+New+Subject". This will cause the system to act on the mailto with its default handler, however, while you can set subjects and such this wont handle adding an attachment. I'll freely admit im not entirely sure how you'd go about forcing an attachment without writing some mail plugin.
The process code is:
System.Diagnostics.Process.Start("mailto:user#example.com?subject=My+New+Subject");
It's probably not the most efficient or elegant way, but shelling a "mailto:" link will do what you want, I think.
EDIT: Sorry, left out a very important "not".
Since mailto does not support attachments, and since MAPI is not supported within managed code, your best bet is to write (or have someone write) a small non-managed program to call MAPI functions that you can call with command-line arguments. Pity that .NET does not have a cleaner alternative.
See also : MAPI and managed code experiences?
Could it be that you used the mailto: protocol?
Almost all of what you highlight can be done, but I am quite sure, that you cant do attachments.
Microsoft MailTo Documentation
Starting process with mailto: arguments is the simplest approach. Yet, it does not allow anything more or less complex.
Slightly different approach involves creating email template and then feeding it to the Process.Start:
var client = new SmtpClient();
var folder = new RandomTempFolder();
client.DeliveryMethod =
SmtpDeliveryMethod.SpecifiedPickupDirectory;
client.PickupDirectoryLocation = folder.FullName;
var message = new MailMessage("to#no.net",
"from#no.net", "Subject","Hi and bye");
// add attachments here, if needed
// need this to open email in Edit mode in OE
message.Headers.Add("X-Unsent", "1");
client.Send(message);
var files = folder.GetFiles();
Process.Start(files[0].FullName);
Scenarios for the default email handler:
Outlook express opens
Windows: Outlook - does not handle by default, Outlook Express is called instead
Windows: The Bat! - message is opened for viewing, hit Shift-F6 and Enter to send
I've also tested with Mono and it worked more or less.
Additional details are available in this post: Information integration - simplest approach for templated emails
PS: in the end I went for slightly more complex scenario:
Defined interface IEmailIntegraton
Code above went into the DefaultEmailIntegration
Added implementations for OutlookEmailIntegration (automation) and theBat! email integration (using their template format).
Allowed users of the SmartClient to select their scenario from the drop-down (alternatively this could've been implemented as "Check the system for the default email handler and decide automatically")
You're making the assumption that they will have an email client installed, of course.
The option I've taken in the past (in a corporate environment where everyone has at least one version of Outlook installed) was to use the Outlook interop - you only need to reference the earliest version you need to support.
You could look at P/Invoking MAPISendDocuments (which I'd try and avoid, personally), or the other option would be to create your own "compose" form and use the objects from the System.Net.Mail namespace.
you can use a trick if you intend to use Outlook[this code is based on outlook 2010[v14.0.0.]]
Create Outlook MailItem
and transmit file (ie download)
if user opens the file (.msg) the compose message dialog opens automatically
here is the code ...
Microsoft.Office.Interop.Outlook.Application outapp = new Application();
try
{
_NameSpace np = outapp.GetNamespace("MAPI");
MailItem oMsg = (MailItem)outapp.CreateItem(OlItemType.olMailItem);
oMsg.To = "a#b.com";
oMsg.Subject = "Subject";
//add detail
oMsg.SaveAs("C:\\Doc.msg", OlSaveAsType.olMSGUnicode);//your path
oMsg.Close(OlInspectorClose.olSave);
}
catch (System.Exception e)
{
status = false;
}
finally
{
outapp.Quit();
}
then transmit the file you created say "Doc.msg"
string filename ="Doc.msg";//file name created previously
path = "C:\\" + filename; //full path ;
Response.ContentType="application/outlook";
Response.AppendHeader("Content-Disposition", "filename=\"" + filename + "\"");
FileInfo fl = new FileInfo(path);
Response.AddHeader("Content-Length", fl.Length.ToString());
Response.TransmitFile(path,0,fl.Length);
Response.End();