4

I work on a VSTO in c#. When I click on button I save attachment in a folder. My problem is : when I have a rich email with an image in the signature, I have a element in my attachment. But I don't want save that image. Outlook (application) hide this attachment in the area attachment ! So why not me :-(

My code is very simply :

MailItem MailItemSelected =  this.OutlookItem;   
foreach (Attachment a in MailItemSelected.Attachments)
{
   a.SaveAsFile(path + a.FileName);
}

But I don't find a test for don't save the image of the signature.

Joc02
  • 345
  • 8
  • 18

5 Answers5

7

We had a need to show only the "Mail Attachments" (not the embedded ones that are used for rendering) in an Outlook Add - In, and this is what that works.

 if (mailItem.Attachments.Count > 0)
        {
            // get attachments
            foreach (Attachment attachment in mailItem.Attachments)
            {
                var flags = attachment.PropertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x37140003");

                //To ignore embedded attachments -
                if (flags != 4)
                {
                    // As per present understanding - If rtF mail attachment comes here - and the embeded image is treated as attachment then Type value is 6 and ignore it
                    if ((int)attachment.Type != 6)
                    {

                        MailAttachment mailAttachment = new MailAttachment { Name = attachment.FileName };
                        mail.Attachments.Add(mailAttachment);
                    }

                }

            }
        }
Roopa vr
  • 71
  • 1
  • 2
2

I've find one part of my solution. When you create an email the size of image embed is to 0. So you can exclude this.

But it is not right when I read a email.

MailItem MailItemSelected =  this.OutlookItem;   
foreach (Attachment a in MailItemSelected.Attachments)
{                                    
   if(a.Size != 0)
      a.SaveAsFile(path + a.FileName);
}

When I read email I found a solution, but it is not very nice. So I write it, but if anybody think have better, I like it. In my example I try to get the Flag property with the PropertyAccessor, if it's a embed image, it's ok else I've an exception that be raise.

MailItem MailItemSelected =  this.OutlookItem;   
foreach (Attachment a in MailItemSelected.Attachments)
{
   bool addAttachment = false;
   try
   {
      string schemaPR_ATTACH_FLAGS = "http://schemas.microsoft.com/mapi/proptag/0x37140003"; 
      a.PropertyAccessor.GetProperty(schemaPR_ATTACH_FLAGS);
   }
   catch
   {
      addAttachment = true;
   }

   if (addAttachment && (a.Size != 0))
      a.SaveAsFile(path + a.FileName);
}
Joc02
  • 345
  • 8
  • 18
2

The flags workaround didn't work for me. I'm developing a solution for Outlook 2016 and I managed to filter the attachments using this code:

foreach (Attachment attachment in mailItem.Attachments)
            {
                //exclude inline images
                if (!mailItem.HTMLBody.Contains(attachment.FileName))
                {
                    //the attachment is not an inline attachment, YOUR CODE HERE
                }
    }

which is basically checking in the HTML body if each of the attachments is mentioned in a tag.


EDIT: the previous method may skip an attachment if you type its name in the body. This is less likey to skip false positives

if (!mailItem.HTMLBody.Contains("cid:" + attachment.FileName))
Luca Mozzo
  • 892
  • 2
  • 8
  • 20
  • 2
    Most images are referred in HTML by the content id (cid). You need to look both the file name and the content id (PR_ATTACH_CONTENT_ID MAPI property - take a look at the message with OutlookSpy). Your code will nto work for content ids. If will also falsely flag attachments mentioned in the message body (e.g ."I am attaching TheFile.doc for your review") – Dmitry Streblechenko Apr 19 '17 at 20:08
  • Finally a decent answer that does not rely on old and removed windows schemas! – hansmei Jul 18 '21 at 20:11
1

seeing that this question has some +2k hits and is still not answered, here is my attempt at a static utility method that returns a list of NON INLINE attachments:

/// <summary>
/// Method to get all attachments that are NOT inline attachments (like images and stuff).
/// </summary>
/// <param name="mailItem">
/// The mail item.
/// </param>
/// <returns>
/// The <see cref="List"/>.
/// </returns>
public static List<Outlook.Attachment> GetMailAttachments(Outlook.MailItem mailItem) {
    const string PR_ATTACH_METHOD = "http://schemas.microsoft.com/mapi/proptag/0x37050003";
    const string PR_ATTACH_FLAGS = "http://schemas.microsoft.com/mapi/proptag/0x37140003";

    var attachments = new List<Outlook.Attachment>();

    // if this is a plain text email, every attachment is a non-inline attachment
    if (mailItem.BodyFormat == Outlook.OlBodyFormat.olFormatPlain && mailItem.Attachments.Count > 0) {
        attachments.AddRange(
            mailItem.Attachments.Cast<object>().Select(attachment => attachment as Outlook.Attachment));
        return attachments;
    }

    // if the body format is RTF ...
    if (mailItem.BodyFormat == Outlook.OlBodyFormat.olFormatRichText) {
        // add every attachment where the PR_ATTACH_METHOD property is NOT 6 (ATTACH_OLE)
        attachments.AddRange(
            mailItem.Attachments.Cast<object>().Select(attachment => attachment as Outlook.Attachment).Where(thisAttachment => (int)thisAttachment.PropertyAccessor.GetProperty(PR_ATTACH_METHOD) != 6));
    }

    // if the body format is HTML ...
    if (mailItem.BodyFormat == Outlook.OlBodyFormat.olFormatHTML) {
        // add every attachment where the ATT_MHTML_REF property is NOT 4 (ATT_MHTML_REF)
        attachments.AddRange(
            mailItem.Attachments.Cast<object>().Select(attachment => attachment as Outlook.Attachment).Where(thisAttachment => (int)thisAttachment.PropertyAccessor.GetProperty(PR_ATTACH_FLAGS) != 4));
    }

    return attachments;
}
lightxx
  • 1,037
  • 2
  • 11
  • 29
  • If you are interested please commit for this :http://stackoverflow.com/documentation/outlook-addin/commit – Kushan Randima Jul 28 '16 at 04:35
  • This code only checks for inline attachments. The question is to differentiate between signature attachments such as a logo image in the signature and other attachments where the „other attachments “ may be inline or normal. – darbid Aug 03 '20 at 10:35
0

New answer for Outlook 365 in 2022

The flags answers didn't work for me, so I set about investigating what was going on in the debugger.

What I found is that Microsoft have evidently changed the rules for flags, as I was seeing values in the debugger that didn't match those given in the older flags solutions.

To get it to work today in Outlook 365, just ignore attachments where flags is not 0:

    var flags = attachment.PropertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x37140003");

    if (flags == 0)
    {
      //
      // Normal attachment, not embedded image etc, so save it
      //
    }
Reg Edit
  • 6,719
  • 1
  • 35
  • 46