none
Copy mail attachments as individual outlook items in another folder? RRS feed

  • Question

  • Can I copy MailMessage attachments as individual items into another Outlook folder?  I can do this in the Outlook interface, but I can't figure out how to do this programmatically.  Here's why: I have a forwarding rule from another account that sends a message to my Exchange account.  I'm trying to write an add-in that will detect this new message, and then extract the attachment of this forwarded message (which is the original message from the other account) and save the attachment as an outlook item in a specific folder.  As I mentioned, I can do this in the interface.  When I bring up a forwarded email, I can drag and drop the attachment into a specific folder and outlook will create a new item based on the attachment's type.  Basically, I plan to support only MailMessages and Calendar items.  Here's what I have so far:

    void Application_NewMailEx(string EntryIDCollection)
    {
      Outlook.NameSpace ns = this.Application.GetNamespace("MAPI");
      Outlook.MailItem email = ns.GetItemFromID(EntryIDCollection);
    
      if (String.Compare(email.SenderEmailAddress, "otheracct@place.com", true) == 0 &&
            email.Recipients.Count == 1 &&
            email.Body.Contains("ForwardedFromOtherAccount"))
      {           
        foreach (Outlook.Attachment attachment in email.Attachments)
        {
    
          // create an outlook item based on this attachment and copy it to another outlook folder
        }
      }
    }
    

    Is this possible with VSTO?  How can I do this otherwise?
    Thank you for your help,

    - Dave -

    Wednesday, March 9, 2011 7:56 PM

Answers

  • While there are properties that PropertyAccessor will treat as read-only for Outlook business logic reasons, there are also properties that are read-only even with MAPI after the item is saved for the first time.
     
    When I create a fake sent email I have to set the Sender* properties as well as some others before I first save the item when I use Redemption (a MAPI wrapper).
     
    If you were to use Redemption it also has import functions that allow importing MSG files.

    --
    Ken Slovak
    MVP - Outlook
    http://www.slovaktech.com
    Author: Professional Programming Outlook 2007
     
     
    "- Dave -" <=?utf-8?B?LSBEYXZlIC0=?=> wrote in message news:873233c3-5ad4-43cb-9bdb-334fd217a4e6...

    Hi Ken,

    Thanks for the response.  Your feedback was great.  It wasn't exactly what I was looking for, but it got me on the right track.  With your solution, the items added with Application.CreateItemFromTemplate() would be in "new item - draft" form.  Which then Outlook wouldn't treat them the way I wanted it to.  Specifically, if I went to reply to the message, the subject wouldn't change to include "RE: " at the beginning of it, etc.  But then, I found some examples on how to load a MSG file with Namespace.OpenSharedItem().  Using your solution as a base, I came up with this:

    void Application_NewMailEx(string EntryIDCollection)
    {
     Outlook.NameSpace ns = this.Application.GetNamespace("MAPI");
     Outlook.MAPIFolder inbox = ns.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
     Outlook.MailItem email = ns.GetItemFromID(EntryIDCollection);
          
     if (String.Compare(email.SenderEmailAddress, "account@otheracct.com", true) == 0 &&
        email.Recipients.Count == 1 &&
        email.Body.Contains("ForwardedFromOtherAccount"))
     {
      foreach (Outlook.Attachment attachment in email.Attachments)
      {
       int i = 0;
       string dir = Environment.GetEnvironmentVariable("Temp");
       string filename = string.Empty;
       if(!dir.EndsWith(@"\")) dir += @"\";
    
       do
       {
        filename = string.Format("{0}OTM{1:000}.msg", dir, i++);
       } while (File.Exists(filename));
         
       attachment.SaveAsFile(filename);
       object newItem = ns.OpenSharedItem(filename);
         
       if (newItem is Outlook.MailItem)
       {
        Outlook.MailItem item = newItem as Outlook.MailItem;
    
        item.Save();
        item.UnRead = true;
        item.Move(inbox);
       }
       else if(newItem is Outlook.MeetingItem)
       {
        Outlook.MeetingItem meeting = newItem as Outlook.MeetingItem;
    
        meeting.Save();
        meeting.UnRead = true;
        meeting.Move(inbox);
       }
    
       File.Delete(filename);
      }
    
      email.UnRead = false;
      email.Delete();
     }
    }
    

    This is almost exactly what I needed, except for one small detail.  The Received date does not get populated when I do this, nor can I set this, because the ReceivedDate property is read only in the Outlook object model.  So all of these new messages that my add-in imports appear at the bottom of my inbox.  I've done a little research on this and found that you've already addressed this in other forum posts.

    Is there a way for me to set this property from within the Add-in, without have the current user provide credentials, and without 3rd party libraries?  It looks like you have to use Extended MAPI to get write access to this property?  I've tried the following code from within the add-in, but I can't change that property (due to security permissions, I'm assuming).

    // PR_MESSAGE_DELIVERY_TIME
    item.PropertyAccessor.SetProperty("http://schemas.microsoft.com/mapi/proptag/0x0E060040", DateTime.UtcNow);
    // PR_DELIVER_TIME 
    item.PropertyAccessor.SetProperty("http://schemas.microsoft.com/mapi/proptag/0x00100040", DateTime.UtcNow);
    // PR_ORIGINAL_DELIVERY_TIME 
    item.PropertyAccessor.SetProperty("http://schemas.microsoft.com/mapi/proptag/0x00550040", DateTime.UtcNow);
    

    Is there an easy way to write to the ReceivedDate property from within the Addin?  I know I'm fairly new at all this, but I appreciate your guidance.  Oh, and I've confirmed that if you drag and drop an attachment in the Outlook interface, the message does have a received date.

    Thanks again,
    - Dave - 


    Ken Slovak MVP - Outlook
    Friday, March 11, 2011 3:42 PM

All replies

  • This isn't related to using VSTO or not, it's strictly based on the Outlook object model. There's no way to do that directly using the object model, but you can do it indirectly.
     
    If an attachment is an Outlook item then you can use the SaveAsFile() method with the attachment and save it as a MSG file. Use a file path in a temporary folder and give the attachment a name or use the DisplayName property, then use a "MSG" extension.
     
    Once the file is saved out you can then open it as an Outlook item using Application.CreateItemFromTemplate() using the file path you just created. Then save the item (it will be created and saved in the default folder for that type of item). Then you can leave it there or copy it or move it elsewhere if desired.

    --
    Ken Slovak
    MVP - Outlook
    http://www.slovaktech.com
    Author: Professional Programming Outlook 2007
     
     
    "- Dave -" <=?utf-8?B?LSBEYXZlIC0=?=> wrote in message news:0f029f31-9005-4763-ae31-9b52f51ef7dd...

    Can I copy MailMessage attachments as individual items into another Outlook folder?  I can do this in the Outlook interface, but I can't figure out how to do this programmatically.  Here's why: I have a forwarding rule from another account that sends a message to my Exchange account.  I'm trying to write an add-in that will detect this new message, and then extract the attachment of this forwarded message (which is the original message from the other account) and save the attachment as an outlook item in a specific folder.  As I mentioned, I can do this in the interface.  When I bring up a forwarded email, I can drag and drop the attachment into a specific folder and outlook will create a new item based on the attachment's type.  Basically, I plan to support only MailMessages and Calendar items.  Here's what I have so far:

    void Application_NewMailEx(string EntryIDCollection)
    {
     Outlook.NameSpace ns = this.Application.GetNamespace("MAPI");
     Outlook.MailItem email = ns.GetItemFromID(EntryIDCollection);
    
     if (String.Compare(email.SenderEmailAddress, "otheracct@place.com", true) == 0 &&
        email.Recipients.Count == 1 &&
        email.Body.Contains("ForwardedFromOtherAccount"))
     {      
      foreach (Outlook.Attachment attachment in email.Attachments)
      {
    
       // create an outlook item based on this attachment and copy it to another outlook folder
      }
     }
    }
    

    Is this possible with VSTO?  How can I do this otherwise?
    Thank you for your help,

    - Dave -


    Ken Slovak MVP - Outlook
    Thursday, March 10, 2011 3:41 PM
  • Hi Ken,

    Thanks for the response.  Your feedback was great.  It wasn't exactly what I was looking for, but it got me on the right track.  With your solution, the items added with Application.CreateItemFromTemplate() would be in "new item - draft" form.  Which then Outlook wouldn't treat them the way I wanted it to.  Specifically, if I went to reply to the message, the subject wouldn't change to include "RE: " at the beginning of it, etc.  But then, I found some examples on how to load a MSG file with Namespace.OpenSharedItem().  Using your solution as a base, I came up with this:

    void Application_NewMailEx(string EntryIDCollection)
    {
      Outlook.NameSpace ns = this.Application.GetNamespace("MAPI");
      Outlook.MAPIFolder inbox = ns.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
      Outlook.MailItem email = ns.GetItemFromID(EntryIDCollection);
                
      if (String.Compare(email.SenderEmailAddress, "account@otheracct.com", true) == 0 &&
            email.Recipients.Count == 1 &&
            email.Body.Contains("ForwardedFromOtherAccount"))
      {
        foreach (Outlook.Attachment attachment in email.Attachments)
        {
          int i = 0;
          string dir = Environment.GetEnvironmentVariable("Temp");
          string filename = string.Empty;
          if(!dir.EndsWith(@"\")) dir += @"\";
    
          do
          {
            filename = string.Format("{0}OTM{1:000}.msg", dir, i++);
          } while (File.Exists(filename));
              
          attachment.SaveAsFile(filename);
          object newItem = ns.OpenSharedItem(filename);
              
          if (newItem is Outlook.MailItem)
          {
            Outlook.MailItem item = newItem as Outlook.MailItem;
    
            item.Save();
            item.UnRead = true;
            item.Move(inbox);
          }
          else if(newItem is Outlook.MeetingItem)
          {
            Outlook.MeetingItem meeting = newItem as Outlook.MeetingItem;
    
            meeting.Save();
            meeting.UnRead = true;
            meeting.Move(inbox);
          }
    
          File.Delete(filename);
        }
    
        email.UnRead = false;
        email.Delete();
      }
    }
    

    This is almost exactly what I needed, except for one small detail.  The Received date does not get populated when I do this, nor can I set this, because the ReceivedDate property is read only in the Outlook object model.  So all of these new messages that my add-in imports appear at the bottom of my inbox.  I've done a little research on this and found that you've already addressed this in other forum posts.

    Is there a way for me to set this property from within the Add-in, without have the current user provide credentials, and without 3rd party libraries?  It looks like you have to use Extended MAPI to get write access to this property?  I've tried the following code from within the add-in, but I can't change that property (due to security permissions, I'm assuming).

    // PR_MESSAGE_DELIVERY_TIME
    item.PropertyAccessor.SetProperty("http://schemas.microsoft.com/mapi/proptag/0x0E060040", DateTime.UtcNow);
    // PR_DELIVER_TIME 
    item.PropertyAccessor.SetProperty("http://schemas.microsoft.com/mapi/proptag/0x00100040", DateTime.UtcNow);
    // PR_ORIGINAL_DELIVERY_TIME 
    item.PropertyAccessor.SetProperty("http://schemas.microsoft.com/mapi/proptag/0x00550040", DateTime.UtcNow);
    

    Is there an easy way to write to the ReceivedDate property from within the Addin?  I know I'm fairly new at all this, but I appreciate your guidance.  Oh, and I've confirmed that if you drag and drop an attachment in the Outlook interface, the message does have a received date.

    Thanks again,
    - Dave - 

    Thursday, March 10, 2011 9:40 PM
  • While there are properties that PropertyAccessor will treat as read-only for Outlook business logic reasons, there are also properties that are read-only even with MAPI after the item is saved for the first time.
     
    When I create a fake sent email I have to set the Sender* properties as well as some others before I first save the item when I use Redemption (a MAPI wrapper).
     
    If you were to use Redemption it also has import functions that allow importing MSG files.

    --
    Ken Slovak
    MVP - Outlook
    http://www.slovaktech.com
    Author: Professional Programming Outlook 2007
     
     
    "- Dave -" <=?utf-8?B?LSBEYXZlIC0=?=> wrote in message news:873233c3-5ad4-43cb-9bdb-334fd217a4e6...

    Hi Ken,

    Thanks for the response.  Your feedback was great.  It wasn't exactly what I was looking for, but it got me on the right track.  With your solution, the items added with Application.CreateItemFromTemplate() would be in "new item - draft" form.  Which then Outlook wouldn't treat them the way I wanted it to.  Specifically, if I went to reply to the message, the subject wouldn't change to include "RE: " at the beginning of it, etc.  But then, I found some examples on how to load a MSG file with Namespace.OpenSharedItem().  Using your solution as a base, I came up with this:

    void Application_NewMailEx(string EntryIDCollection)
    {
     Outlook.NameSpace ns = this.Application.GetNamespace("MAPI");
     Outlook.MAPIFolder inbox = ns.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
     Outlook.MailItem email = ns.GetItemFromID(EntryIDCollection);
          
     if (String.Compare(email.SenderEmailAddress, "account@otheracct.com", true) == 0 &&
        email.Recipients.Count == 1 &&
        email.Body.Contains("ForwardedFromOtherAccount"))
     {
      foreach (Outlook.Attachment attachment in email.Attachments)
      {
       int i = 0;
       string dir = Environment.GetEnvironmentVariable("Temp");
       string filename = string.Empty;
       if(!dir.EndsWith(@"\")) dir += @"\";
    
       do
       {
        filename = string.Format("{0}OTM{1:000}.msg", dir, i++);
       } while (File.Exists(filename));
         
       attachment.SaveAsFile(filename);
       object newItem = ns.OpenSharedItem(filename);
         
       if (newItem is Outlook.MailItem)
       {
        Outlook.MailItem item = newItem as Outlook.MailItem;
    
        item.Save();
        item.UnRead = true;
        item.Move(inbox);
       }
       else if(newItem is Outlook.MeetingItem)
       {
        Outlook.MeetingItem meeting = newItem as Outlook.MeetingItem;
    
        meeting.Save();
        meeting.UnRead = true;
        meeting.Move(inbox);
       }
    
       File.Delete(filename);
      }
    
      email.UnRead = false;
      email.Delete();
     }
    }
    

    This is almost exactly what I needed, except for one small detail.  The Received date does not get populated when I do this, nor can I set this, because the ReceivedDate property is read only in the Outlook object model.  So all of these new messages that my add-in imports appear at the bottom of my inbox.  I've done a little research on this and found that you've already addressed this in other forum posts.

    Is there a way for me to set this property from within the Add-in, without have the current user provide credentials, and without 3rd party libraries?  It looks like you have to use Extended MAPI to get write access to this property?  I've tried the following code from within the add-in, but I can't change that property (due to security permissions, I'm assuming).

    // PR_MESSAGE_DELIVERY_TIME
    item.PropertyAccessor.SetProperty("http://schemas.microsoft.com/mapi/proptag/0x0E060040", DateTime.UtcNow);
    // PR_DELIVER_TIME 
    item.PropertyAccessor.SetProperty("http://schemas.microsoft.com/mapi/proptag/0x00100040", DateTime.UtcNow);
    // PR_ORIGINAL_DELIVERY_TIME 
    item.PropertyAccessor.SetProperty("http://schemas.microsoft.com/mapi/proptag/0x00550040", DateTime.UtcNow);
    

    Is there an easy way to write to the ReceivedDate property from within the Addin?  I know I'm fairly new at all this, but I appreciate your guidance.  Oh, and I've confirmed that if you drag and drop an attachment in the Outlook interface, the message does have a received date.

    Thanks again,
    - Dave - 


    Ken Slovak MVP - Outlook
    Friday, March 11, 2011 3:42 PM