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...
Related
I have built a small web application to read appointments from outlook calendar and i used Microsoft.Office.Interop.Outlook. Now I want to to able to save the attachments which are inside the appointment.
Here is my code so far :
foreach (var item in AppointmentItems) {
for (int i = 1; i <= item.Attachments.Count; i++) {
var Attachment = item.Attachments[i];
string SavePath = Path.Combine(#"D:\SaveTest", Attachment.FileName);
Attachment.SaveAsFile(SavePath);
}
}
Problem :
Exception thrown: 'System.IO.FileNotFoundException at exactly
Attachment.SaveAsFile(SavePath);
I have already looked everywhere, this method should save the attachment to the path but its somehow trying to read a file.
Assuming that the attachment exist, FileNotFoundExecption is triggered by a not existing part of your path. You can check if the path exist first:
Directory.Exists(#"D:\SaveTest")
Then you can check if you have write rights on the directory:
Try
{
return System.IO.Directory.GetAccessControl(#"D:\SaveTest")
.GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount))
.Cast<System.Security.AccessControl.FileSystemAccessRule>()
.Where(rule => (System.Security.AccessControl.FileSystemRights.Write & rule.FileSystemRights) == System.Security.AccessControl.FileSystemRights.Write)
.Any(rule => rule.AccessControlType == System.Security.AccessControl.AccessControlType.Allow);
} catch(Exception)
{
return false;
}
3 things you could try to do:
Make sure that the directory exists
Check if Attachment.FileName have valid name and extension
Check your write access
System.IO.FileNotFoundExecption means it can't find the file you are looking for or the path you are trying to save to in your case. remove # and try "D:\foldername\" + attachment.filename. although removing # should still work I think you need use plus operator. Would help you can post the whole block of code so we can understand what is going on from top to bottom.
I`m trying to create outlook mails from templates, slightly edit them and then show to user so he can send that mail.
There is no problem in creation of the mail and displaying it. But when I`m trying to read (or edit) HTMLBody of the mail there is a error:
Operation aborted (Exception from HRESULT: 0x80004004 (E_ABORT))
Here is my code:
using Outlook = Microsoft.Office.Interop.Outlook;
...
try
{
var app = new Outlook.Application();
Outlook.MailItem mailItem = app.CreateItemFromTemplate("C:\\Test\\template.oft");
var body = mailItem.HTMLBody; //Here is the exception
mailItem.HTMLBody = body.Replace("#firstname", "Test Testy");
mailItem.To = message.EmailAddress;
mailItem.Display(mailItem);
}
catch (Exception ex)
{
...
}
Added example project on github.
var app = new Outlook.Application();
Before creating a new instance of the Outlook Application class I'd suggest checking whether it is already run and get the running instance then:
if (Process.GetProcessesByName("OUTLOOK").Any())
app = System.Runtime.InteropServices.Marshal.GetActiveObject("Outlook.Application");
Outlook is a singleton. You can't run multiple instances at the same time.
Also I'd suggest saving the newvly created item before accessing the HTMLBody property value:
Outlook.MailItem mailItem = app.CreateItemFromTemplate("C:\\Test\\template.oft");
mailIte.Save();
var body = mailItem.HTMLBody; //Here is the exception
Finally, the Display method doesn't take a MailItem instance. Instead, you can pass true to get the inspector shown as a modal window or just omit the parameter (false is used by default).
BTW Where and when do you run the code?
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
I have the next problem. I've written the solution for MS Outlook 2010 that creates email summary and write it down to an Excel file(.xls) The problem is that on my PC and several others it works correctly but when I sent it to customers, they said that it creates summary only for inbox folder on some PCs and on others it doesn't work at all.
I've also created the possibility to choose the folder to get the emails but the problem left. I'll provide a code snippet of the function choosing folder and getting the list of emails. I save emails in List in private field of my class.
Take a look on this func and please help to get out what is wrong. Thanks.
public void GetTheArrayOfEmails(DateTime startDate, DateTime finishDate)
{
try
{
Outlook.Application oApp = new Outlook.Application();
Outlook.NameSpace oNs = oApp.GetNamespace("mapi");
oNs.Logon(Missing.Value, Missing.Value, false, false);
//Outlook.MAPIFolder folder = oApp.Session.PickFolder();
foreach (Outlook.MailItem oMsg in oApp.Session.PickFolder().Items)
{
if (oMsg.ReceivedTime.ToUniversalTime() > startDate.ToUniversalTime() &&
oMsg.ReceivedTime.ToUniversalTime() < finishDate.ToUniversalTime())
{
MailList.Add(oMsg);
}
}
oNs.Logoff();
releaseObject(oNs);
releaseObject(oApp);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
UPD: Fixed the problem. I missed cast. And tried to cast items which are not of MailItem interface.
I have been trying to find a way to add a folder to a pst file from c#
I have tried a whole bunch of code to try and get this to work and this is the one that seems to be most likly to be correct (as it is whats on the MSDN) but still does not work
Main {
Outlook._Application OutlookObject = new Outlook.Application();
Outlook.Store NewPst = null;
// create the pst file
string pstlocation = "C:\\Users\\Test\\Desktop\\PST\\Test.pst";
try
{
OutlookObject.Session.AddStore(pstlocation);
foreach (Outlook.Store store in OutlookObject.Session.Stores)
{
if (store.FilePath == pstlocation)
{
// now have a referance to the new pst file
NewPst = store;
Console.WriteLine("The Pst has been created");
}
}
}
catch
{ }
// create a folder or subfoler in pst
Outlook.MAPIFolder NewFolder;
NewFolder = NewPst.Session.Folders.Add("New Test Folder", Type.Missing);
}
This code creates a new PST File and then trys to add a folder to it however the last line of code:
New NewFolder = NewPst.Session.Folders.Add("New Test Folder", Type.Missing);
Gets the error "The operation failed." and "Invalid Cast Exception" can some one point out what i am doing wrong
Thanks in advance
You need to use Store.GetRootFolder() to get a handle to the root folder of that store (not Store.Session). So you would use:
// create a folder or subfolder in pst
Outlook.MAPIFolder pstRootFolder = NewPst.GetRootFolder();
Outlook.MAPIFolder NewFolder = pstRootFolder.Folders.Add("New Test Folder");
I recommend bookmarking both of the following: The PIA documentation isn't always complete, so it's worth checking out the COM documentation as well for complete class and member info.
(.NET): Outlook 2007 Primary Interop Assembly Reference
(COM): Outlook Object Model Reference