I need to save permanently some custom information inside an Outlook Mailitem and retrieve them back.
My case scenario is the following: I select an email in Outlook 2013 explorer, write inside that email some information, save it on my disk as .msg file, delete the email from the Inbox Outlook folder, open the .msg file as Outlook.MailItem and read that information in order to keep them or change them.
I'm using the Outlook.ItemProperties.Add() method to add a custom ItemProperty inside the selected MailItem.
When I get a MailItem from the .msg I'm not able to find that properties.
I've used OutlookSpy->Miscellaneous->OpenIMsgOnIstg function to check the .msg and I've noted that all properties are in the GetProps tab.
My question is: How can I read the properties?
Here is the code to write the properties and save the mail as .msg:
Outlook.Application outApp= new Outlook.Application();
Outlook.MailItem mail= null;
try { mail = (Outlook.MailItem)outApp.ActiveInspector().CurrentItem; }
catch {
if (outApp.ActiveExplorer().Selection.Count > 0)
mail = (Outlook.MailItem)outApp .ActiveExplorer().Selection[1];
else { // ERROR }
}
Outlook.ItemProperty prop01 = mail.ItemProperties.Add("MyProperty01", Outlook.OlUserPropertyType.olText);
prop01.Value = "hola";
Outlook.ItemProperty prop02 = mail.ItemProperties.Add("MyProperty02", Outlook.OlUserPropertyType.olNumber);
prop02.Value = 23;
mail.Save();
mail.SaveAs(#"C:\WorkSpace\mail.msg", Outlook.OlSaveAsType.olMSG);
if (mail != null) Marshal.ReleaseComObject(mail);
if (outlookObj != null) Marshal.ReleaseComObject(outApp );
Here is my code to read the properties from the .msg after I've deleted the email in Outlook:
Outlook.Application outApp= new Outlook.Application();
Outlook.MailItem msgMail=(Outlook.MailItem)outApp.CreateItem(Outlook.OlItemType.olMailItem);
msgMail = (Outlook.MailItem)outApp.Session.OpenSharedItem(#"C:\WorkSpace\mail.msg");
Outlook.ItemProperties mailProps = msgMail.ItemProperties;
Outlook.ItemProperty pr = mailProps["MyProperty01"]; // pr IS NULL
But OutlookSpy shows the properties are in the .msg file.
I have solved my problem following this bypassing solution.
Use Mailitem.PropertyAccessor.GetProperty and pass the DASL property name shown by OutlookSpy (I am its author).
Related
I'm trying to add custom UserProperty to MailItem while creating it.
I add an attachement's Hash as UserProperty to my MailItem object.
Then I open my new MailItem in Outlook.
mi = olApp.CreateItem(Outlook.OlItemType.olMailItem) as Outlook.MailItem;
Outlook.UserProperties mailUserProperties = null;
Outlook.UserProperty mailUserProperty = null;
mi.Attachments.Add(file.FilePath);
mailUserProperties = mi.UserProperties;
mailUserProperty = mailUserProperties.Add("AttachementsHash", Outlook.OlUserPropertyType.olText);
mailUserProperty.Value = file.Hash;
mi.Save();
mi.Display();
If I check MailItem.UserProperties using OutlookSpy BEFORE sending I see that my mail has one UserProperty.
Then I click "Send Mail" in Outlook and I check my mail in SentItems folder.
I can see UserProperties.Count == 0.
If anyone knows why my UserProperty disappear, please help me and tell :)
With a lot of effort i resolved my problem.
UserProperties are removed after sending mail. But in stead of UserProperties I used MailItem.PropertyAccessor.SetProperty
MSDN Documentation of Property Accessor
string prop = "http://schemas.microsoft.com/mapi/string/{00020386-0000-0000-C000-000000000046}/PropertyName";
mi.PropertyAccessor.SetProperty(prop, propertyValue.ToString());
And then on event 'ItemAdd' I checked, if item was added to sentItems.
If it Was added to sentItems I read properties using such construction:
Outlook.MailItem AddedMail = item as Outlook.MailItem;
string attachmentProperty = AddedMail.PropertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x007D001E");
And then finnally I parse string in order to get my data.
I hope it will help anyone :)
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'm developing a Visual Studio extension that adds a command to VS to compose a message in Outlook with an attachment. The attachment is simple .csv file that is also produced by the extension.
So when user fires the command, outlook opens a window with an email already composed and attachment added. The user might just click send.
Now I've been asked to add possibility to send those logs compressed with zip. I would like to compose a message with an attachment already compressed, but I don't want any temporary .zip files retained after message is sent (or cancelled). How can I achieve this?
My code that composes the message and opens Outlook window:
using Microsoft.Office.Interop.Outlook;
...
private static bool TrySendMethod1(string subject, string toAddr, string body, string logPath)
{
try
{
Application app = new Application();
MailItem mailItem = app.CreateItem(OlItemType.olMailItem);
mailItem.Subject = subject;
mailItem.To = toAddr;
mailItem.Body = body;
if (logPath != null) mailItem.Attachments.Add(logPath);
mailItem.Importance = OlImportance.olImportanceNormal;
mailItem.Display(false);
return true;
}
catch (System.Exception e)
{
return false;
}
}
update
Once the email is composed, an outlook window with a composed message is displayed (it has the attachment already set). Now, the user might just send it, cancel it or whatever. He might even leave the window opened for hours (although this is not common) and then send it (even after VS has been closed). Again, i don't want any temporary archives to exist on the disk after the message is sent or cancelled.
I added full method that sends the email. It's not much more, but this method is just invoked when user selects a new Visual Studio command that my extension adds to it (tools -> send TFS logs -> from this month). There just an additional method between button handler and it simply sets some parameters for the one presented here (sets the subject, logPath and so on...)
If it's not possible, then I can also accept such an answer.
You can compress a file using this:
public static void Compress(FileInfo fileToCompress, string compressedFileName)
{
using (FileStream originalFileStream = fileToCompress.OpenRead())
{
using (FileStream compressedFileStream = File.Create(compressedFileName)
{
using (GZipStream compressionStream = new GZipStream(compressedFileStream, CompressionMode.Compress))
{
originalFileStream.CopyTo(compressionStream);
}
}
}
}
Modified from: http://msdn.microsoft.com/en-us/library/ms404280(v=vs.110).aspx
For deleting the file afterwards you can attach to the MailItem.Unload Event.
This event occurs after the Close event for the Outlook item occurs,
but before the Outlook item is unloaded from memory, allowing an
add-in to release any resources related to the object. Although the
event occurs before the Outlook item is unloaded from memory, this
event cannot be canceled.
Source: http://msdn.microsoft.com/en-us/library/office/ff868564(v=office.15).aspx
Then you TrySendMethod1 could look like this
private static bool TrySendMethod1(string subject, string toAddr, string body, string logPath)
{
try
{
Application app = new Application();
MailItem mailItem = app.CreateItem(OlItemType.olMailItem);
mailItem.Subject = subject;
mailItem.To = toAddr;
mailItem.Body = body;
string compressedFileName = logpath + ".gz";
CompressedStack(logpath, compressedFileName);
if (logPath != null) mailItem.Attachments.Add( compressedFileName );
mailItem.Importance = OlImportance.olImportanceNormal;
mailItem.Display(false);
mailItem.Unload += (e) => {File.Delete(compressedFileName);};
return true;
}
catch (System.Exception e)
{
return false;
}
}
Exception handling for the File.Delete is missing, and I am not sure 100% certaing about the signature of the Unload event, but have a try and let us know.
This will NOT handle the case where Visual Studio is closed BEFORE the mail is sent! (I think that might not even be possible.)
in my outlook addin I want to add a button on the Ribbon so when user click this button I want to retrieve the current selected email's body , I have this code but it retrieve only the first email from the inbox because the index is 1 :
Microsoft.Office.Interop.Outlook.Application myApp = new Microsoft.Office.Interop.Outlook.Application();
Microsoft.Office.Interop.Outlook.NameSpace mapiNameSpace = myApp.GetNamespace("MAPI");
Microsoft.Office.Interop.Outlook.MAPIFolder myInbox = mapiNameSpace.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderInbox);
String body = ((Microsoft.Office.Interop.Outlook.MailItem)myInbox.Items[1]).Body;
so how to retrieve the current opened email in outlook? , this method work for me but I need to get the index for the current email.
Thanks.
You shouldn’t initialize a new Outlook.Application() instance each time. Most add-in frameworks provide you with an Outlook.Application instance, corresponding to the current Outlook session, typically through a field or property named Application. You are expected to use this for the lifetime of your add-in.
To get the currently-selected item, use:
Outlook.Explorer explorer = this.Application.ActiveExplorer();
Outlook.Selection selection = explorer.Selection;
if (selection.Count > 0) // Check that selection is not empty.
{
object selectedItem = selection[1]; // Index is one-based.
Outlook.MailItem mailItem = selectedItem as Outlook.MailItem;
if (mailItem != null) // Check that selected item is a message.
{
// Process mail item here.
}
}
Note that the above will let you process the first selected item. If you have multiple items selected, you might want to process them in a loop.
On Top add reference to
using Outlook = Microsoft.Office.Interop.Outlook;
Then inside a method;
Outlook._Application oApp = new Outlook.Application();
if (oApp.ActiveExplorer().Selection.Count > 0)
{
Object selObject = oApp.ActiveExplorer().Selection[1];
if (selObject is Outlook.MailItem)
{
Outlook.MailItem mailItem = (selObject as Outlook.MailItem);
String htmlBody = mailItem.HTMLBody;
String Body = mailItem.Body;
}
}
Also you can change the body which will show in outlook before viewing the mail.
I have the below code that I harvested from MSDN. The code seems to have been originally used in an Add In and as such I am having a problem with the this.Application.CreateItem(...) portion. What do I need to do differently to do this from my winform app?
private void AddAttachment(){
Outlook.MailItem mail =this.Application.CreateItem(Outlook.OlItemType.olMailItem)as Outlook.MailItem;
mail.Subject = "An attachment for you!";
OpenFileDialog attachment = new OpenFileDialog();
attachment.Title = "Select a file to send";
attachment.ShowDialog();
if (attachment.FileName.Length > 0)
{
mail.Attachments.Add(
attachment.FileName,
Outlook.OlAttachmentType.olByValue,
1,
attachment.FileName);
mail.Recipients.Add("Armando Pinto ");
((Outlook._MailItem)mail).Send();
}
Make sure you're in a VSTO project so you get the Office References loaded. If it's complaining up there, it's probably because it doesn't know what object you're trying to create.