Using Aspose To Open PST files & Copy Structure - c#

I have an input folder full of msg email files, within these there are inbox, outbox, sent items etc.
Is there any way I could use aspsoe to open the PST copy the files and structure to an output folder.
I have tried
PersonalStorage personalStorage = PersonalStorage.FromFile(InputFolder);
// Get the folders information
FolderInfoCollection folderInfoCollection = personalStorage.RootFolder.GetSubFolders();
Any ideas?

Inbox, Sent Items, Outbox, etc. are predefined folders and are referred to by StandardIpmFolder. You can use the following code sample to extract messages from these and save to disc.
PersonalStorage pst = PersonalStorage.FromFile("pstfile.pst");
//Get Default Inbox Folder
FolderInfo fiInbox = pst.GetPredefinedFolder(StandardIpmFolder.Inbox);
//the same way you can get StandardIpmFolder.Sent and others
//traverse and save to disc
MessageInfoCollection msgs = fiInbox.GetContents();
foreach (MessageInfo msg in msgs)
{
MapiMessage mapi = pst.ExtractMessage(msg);
mapi.Save(mapi.Subject + ".msg");
}
pst.Dispose();
Please try it and if you still face some issue, you can write to us on Aspose.Email forum along with your sample PST file for further assistance.
I work with Aspose as Developer Evangelist.

To export the entire Structure of the PST i used this recursive traversal:
internal static Dictionary<string, MapiMessage> ReadPstAspose(string pstPath)
{
PersonalStorage pst = PersonalStorage.FromFile(pstPath);
Dictionary<string, MapiMessage> allMessages = new Dictionary<string, MapiMessage>();
GetAllMessagesRecursive(pst, pst.RootFolder, allMessages);
pst.Dispose();
return allMessages;
}
private static void GetAllMessagesRecursive(PersonalStorage pst, FolderInfo folder, Dictionary<string, MapiMessage> allMessages)
{
foreach (var messageEntryId in folder.EnumerateMessagesEntryId())
{
try
{
MapiMessage message = pst.ExtractMessage(messageEntryId);
var key = $"{message.DeliveryTime:ddMMyyyy:hhmmss}\\{folder.RetrieveFullPath()}\\{message.Subject}";
allMessages.Add(key, message);
}
catch (Exception e)
{
throw e;
}
}
foreach (var subFolder in folder.GetSubFolders())
{
GetAllMessagesRecursive(pst, subFolder, allMessages);
}
}
The code ist mostly copied from the excellent documentation at aspose.com.
There's still the issue of re-creating the structure. The key of the dict has the structure in it and you can go from there to rebuild it anyway you like.

Related

sent folder empty using mailkit

I am trying to get the sent folders to display but it shows that the folder has no children in it. All folders are empty except inbox. I am using the following code.
using (var client = new ImapClient())
{
client.Connect(credentials.incoming_host, (int)credentials.incoming_port, credentials.incoming_ssl); //for SSL
client.Authenticate(credentials.email, credentials.password);
client.Inbox.Open(FolderAccess.ReadOnly);
var sentFolder= client.GetFolder(MailKit.SpecialFolder.Sent);
var Folders = client.GetFolders(client.PersonalNamespaces[0]);
client.Disconnect(true);
}
I tried sending an email using the same folder, and then append it like:
var sentFolder = imapclient.GetFolder(SpecialFolder.Sent);
sentFolder.Append(message);
My outlook did detect it and added into the sent folder.
From the MailKit README:
If the IMAP server supports the SPECIAL-USE or the XLIST (GMail) extension, you can get ahold of the pre-defined All, Drafts, Flagged (aka Important), Junk, Sent, Trash, etc folders like this:
if ((client.Capabilities & (ImapCapabilities.SpecialUse | ImapCapabilities.XList)) != 0) {
var drafts = client.GetFolder (SpecialFolder.Drafts);
} else {
// maybe check the user's preferences for the Drafts folder?
}
In cases where the IMAP server does not support the SPECIAL-USE or XLIST extensions, you'll have to come up with your own heuristics for getting the Sent, Drafts, Trash, etc folders. For example, you might use logic similar to this:
static string[] CommonSentFolderNames = { "Sent Items", "Sent Mail", "Sent Messages", /* maybe add some translated names */ };
static IFolder GetSentFolder (ImapClient client, CancellationToken cancellationToken)
{
var personal = client.GetFolder (client.PersonalNamespaces[0]);
foreach (var folder in personal.GetSubfolders (false, cancellationToken)) {
foreach (var name in CommonSentFolderNames) {
if (folder.Name == name)
return folder;
}
}
return null;
}
Using LINQ, you could simplify this down to something more like this:
static string[] CommonSentFolderNames = { "Sent Items", "Sent Mail", "Sent Messages", /* maybe add some translated names */ };
static IFolder GetSentFolder (ImapClient client, CancellationToken cancellationToken)
{
var personal = client.GetFolder (client.PersonalNamespaces[0]);
return personal.GetSubfolders (false, cancellationToken).FirstOrDefault (x => CommonSentFolderNames.Contains (x.Name));
}
Another option might be to allow the user of your application to configure which folder he or she wants to use as their Sent folder, Drafts folder, Trash folder, etc.
How you handle this is up to you.
It is necessary to open the folder otherwise it will appear empty.
IMailFolder personal = client.GetFolder(client.PersonalNamespaces[0]);
foreach (IMailFolder folder in personal.GetSubfolders(false, cancellationToken))
{
folder.Open(FolderAccess.ReadOnly);
Console.WriteLine($"folder.Name = {folder.Name}");
Console.WriteLine($"{folder.Name} messages : {folder.Count}");
}

Extracting information from an outlook contact or a distribution list saved as an *.msg file

I am trying to solve a problem where I have some contact information given as Outlook's *.msg files. I want to parse these files using a script to extract the contact emails and names. I tried couple of solutions:
I tried using Aspose's email library but could not get to the contact details.
If I open the .msg file with Outlook and save the file as a .txt file, the resulting file is a simple text file with the contact information listed and this file I can parse with the IO libraries and extract the information out. However I over hundred of these .msg files. I am using .NET and can't figure out how to implement the "Save As" text which I was able to do manually.
Any suggestions on how to go about this?
Thanks
Suresh
Using Apose.Email API, we can extract the contact email information. You may try this on your end.I tired this and was able to extract those information
MapiMessage message = MapiMessage.FromFile(msgPath);
MapiPropertyCollection properties = message.NamedProperties;
foreach (KeyValuePair<long, MapiProperty> prop in properties)
{
if (((prop.Value).Descriptor).CanonicalName != null)
{
if (((prop.Value).Descriptor).CanonicalName == "PidLidEmail1DisplayName")
{
string email1displayName = prop.Value.ToString();
}
if (((prop.Value).Descriptor).CanonicalName == "PidLidEmail1EmailAddress")
{
string email1Address = prop.Value.ToString();
}
if (((prop.Value).Descriptor).CanonicalName == "PidLidInstantMessagingAddress")
{
string ADD = prop.Value.ToString();
}
}
RDOSession session = RedemptionLoader.new_RDOSession();
session.Logon();
RDOFolder folder = session.GetDefaultFolder(rdoDefaultFolders.olFolderContacts);
Console.WriteLine("Extracting contacts...");
foreach (RDOFolder subFolder in folder.Folders)
{
if (subFolder.Name == "CAS_Notifications")
{
foreach (var rdoItem in subFolder.Items)
{
RDOContactItem contactItem = rdoItem as RDOContactItem;
RDODistListItem distList = rdoItem as RDODistListItem;
if (distList != null)
{
Console.WriteLine("Distribution List");
foreach (RDOAddressEntry rdoAddressEntry in distList.OneOffMembers)
{
Console.WriteLine("Name: {0}; Email: {1}", rdoAddressEntry.Name, rdoAddressEntry.SMTPAddress);
}
}
else if (contactItem != null)
{
Console.WriteLine("Name: {0}; Email: {1}", contactItem.FullName, contactItem.Email1Address);
}
}
}
}
We are very sorry for getting to you on this a little late.
What actual issue are you facing while using Aspose API? The API provides the capability to read Outlook Contact .MSG files as well as Distribution lists without the need of having MS Outlook installed.
Please have a look at the following documentation articles:
Working with Outlook Contacts
If you still face issue while retrieving the desired information with the latest version of the API, you can post your query along with sample MSG files to Aspose.Email forum. We will investigate these at our end and assist you further.
I work with Aspose as Developer evangelist.
If using Redemption is an option (I am its author), something like the following should work for reading contacts or distribution lists saved as msg files:
Redemption.RDOSession session = new Redemption.RDOSession();
Redemption.RDOMail msg = session.GetMessageFromMsgFile(#"c:\temp\TestContact.msg");
//is it really a contact? Could be a regular message or an RDODistListItem (all derived from RDOMail)
Redemption.RDOContactItem contact = msg as Redemption.RDOContactItem;
if (contact != null)
{
MessageBox.Show(contact.FirstName);
}
else
{
Redemption.RDODistListItem dl= msg as Redemption.RDODistListItem;
if (dl != null)
{
MessageBox.Show(dl.FileAs);
}
}

C# Outlook ; After creating folder can't move emails

My application is supposed to send some emails to some destination. After that operation I would like to automatically move sent mails to specific folder ( based on the document type that is in the mail attachment ). If the folder doesn't exist then the program has to create it and then move the mail to the newly created folder. The issue is that after I create a new folder and succcesfully move the mail to it for the first time, then when i sent anothe mails that are supposed to be moved to the said folder the program doesn't see the folder. In fact the Folders method doesn't return any folders at all.
frankly, im out of ideas whats wrong.
when checking in the debugger it says that parentFolder.Folders "Enumeration yielded no results"
I am not sure if I should do anything more after creating the folder in the method createFolder ( ie. something like, update folders list... )
here is my code:
public void moveEmails(string itemType, Boolean itemSent, Outlook.MailItem objMail)
{
Outlook.MAPIFolder folderParent = objMail.Parent as Outlook.MAPIFolder;
Outlook.Folders folders;
Boolean notMoved = true;
objMail.UserProperties.Add("TransferredBy", Outlook.OlUserPropertyType.olText, true, Outlook.OlUserPropertyType.olText);
objMail.UserProperties["TransferredBy"].Value = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
objMail.Save();
if (folderParent.Name != "Inbox")
folderParent = digForInbox(folderParent);
folders = folderParent.Folders;
if (!itemSent)
itemType = "NOT DELIVERED";
foreach (Outlook.MAPIFolder folder in folders)
{
if (folder.Name == itemType)
{
objMail.Move(folder);
notMoved = false;
}
}
if (notMoved)
createFolder(itemType,objMail, folderParent);
}
public void createFolder(string itemType, Outlook.MailItem objMail, Outlook.MAPIFolder folderParent)
{
Outlook.MAPIFolder folderNew;
folderNew = folderParent.Folders.Add( itemType, Outlook.OlDefaultFolders.olFolderInbox ) as Outlook.MAPIFolder;
objMail.Move(folderNew);
}
private Outlook.MAPIFolder digForInbox(Outlook.MAPIFolder folder)
{
Boolean isNotInbox = true;
while(isNotInbox)
{
if(folder.Name != "Inbox")
{
folder = folder.Parent as Outlook.MAPIFolder;
}
else
{
isNotInbox = false;
}
}
return folder;
}
I have found the answer to my question:
https://social.msdn.microsoft.com/forums/windows/en-us/180c000c-524a-45dd-88fe-88b470be3597/accessing-subfolders-within-shared-mailbox?forum=outlookdev
the issue was similar to the one in the link. I didnt imagine that because my mailboxes are mainly shared ones that would affect it in any other way than performance (due to connecting to the exchange server )
Posting this as an answer
I'd suggest using the SaveSentMessageFolder property of the MailItem class. It allows to set a Folder object that represents the folder in which a copy of the e-mail message will be saved after being sent. Also you may find the following articles helpful:
How To: Change an Outlook e-mail message before sending using C# or VB.NET
How To: Create a new folder in Outlook

Replacing a file with a new file of the same name but different content in TFS via C#

i´m currently working on a programm which updates templates on our companies Team Foundation Server. I am having those new templates locally on my disk and want to replace the existing ones on the server. I was trying different approaches and this is my newest version. The problem is that either
the new file is "in use" when accessing it through coding in c#(while not in use when i try to replace it in runtime using the normal explorer).
the replacement is not appearing in the pending changes, the pendingChanges array is initial.
using (var tfs = TeamFoundationServerFactory.GetServer("myserver"))
{
var versionControlServer = tfs.GetService(typeof(VersionControlServer)) as VersionControlServer;
// Create a new workspace for the currently authenticated user.
var workspace = versionControlServer.CreateWorkspace("Temporary Workspace", versionControlServer.AuthorizedUser);
try
{
// Check if a mapping already exists.
var workingFolder = new WorkingFolder("$serverpath", #"c:\tempFolder");
// Create the mapping (if it exists already, it just overides it, that is fine).
workspace.CreateMapping(workingFolder);
workspace.Get(VersionSpec.Latest, GetOptions.GetAll);
string[] paths = new string[1];
paths[0] = "test.pdf";
workspace.PendEdit(paths, RecursionType.Full, null, LockLevel.None);
// Go through the folder structure defined and create it locally, then check in the changes.
CreateFolderStructure(workspace, workingFolder.LocalItem);
// Check in the changes made.
int a = workspace.CheckIn(workspace.GetPendingChanges(), "This is my comment");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
// Cleanup the workspace.
workspace.Delete();
// Remove the temp folder used.
Directory.Delete(#"C:\tempFolder", true);
}
}
}
static void CreateFolderStructure(Workspace workspace, string initialPath)
{
workspace.PendDelete("$serverpath/test.pdf", RecursionType.None);
File.Copy(#"C:\test\testnew.pdf", #"C:\tempfolder\test", true);
workspace.PendAdd(#"C:\tempfolder\test.pdf");
}
I found a solution to the problem. The workspace which was used by "authorizedUser" was obviously not enough.. I found out that a need a TeamFoundationIdentity to do it. Here is a guide on how to fix the issue.
http://blogs.msdn.com/b/taylaf/archive/2010/03/29/using-tfs-impersonation-with-the-version-control-client-apis.aspx

Create/Open existing msg from path to new Outlook.MailItem in c#

Hello I'd like to create a Outlook.MailItem ( I believe ) from an existing one located on disk. I have the path stored in a string, and would like to access to save the body and attachments from it.
I can't seem to figure out how to open it in c# and access it.
currently I have something along the lines of
where fl evaluates out to something like "C:\users\msgs\email.msg"
Thanks for the time
Outlook.Application app = new Outlook.Application();
try
{
foreach (String fl in Directory.GetFiles(docInfo.LocalPath + _preprocessorDirectory))
{
if (Regex.IsMatch(fl.Trim(), _regex, RegexOptions.IgnoreCase))
{
Outlook.MailItem email = new Outlook.MailItem(fl);
SaveAttachments(email);
SaveBody(email);
}
}
}
catch (Exception ex)
{
logger.Error("Error in Process for document " + docInfo.OriginalPath, ex);
callback.Invoke(docInfo, false);
}
return false;
To open an item in outlook try:
var email = (Outlook.MailItem)app.Session.OpenSharedItem(fl)
From there, you can access the Attachments property and Body property as well.
Also, as I mentioned in my comment if the Regex.IsMatch is to determing the file extension, use Path.GetExtension() instead
I used this NuGet package: https://www.nuget.org/packages/MSGReader/
Seems to work fine. I prefer it to the MS OutlookApi library because it doesn't require Outlook to be installed.
I appreciate that it won't create instances of MailItem, as you have asked for in your question - but it will enable you to extract save the individual attachments and the body...

Categories

Resources