Reputation: 117
I am coding a small VBA to show all attachments of an email in a list box.
The user can select attachments that should be removed from the email and stored on a target folder.
I am also adding a HTML file to the email that contains a list of all removed files (including a link to each file to the target folder).
I have a problem with images, because they can be
I want to show in my list box only those images, that are attached as files to the email.
Embedded mails should be ignored.
Sub SaveAttachment()
Dim myAttachments As Outlook.Attachments
Dim olMailItem As Outlook.MailItem
Dim lngAttachmentCount As Long
Dim Attachment_Filename As String
Select Case True
Case TypeOf Application.ActiveWindow Is Outlook.Inspector
Set olMailItem = Application.ActiveInspector.CurrentItem
Case Else
With Application.ActiveExplorer.Selection
If .Count Then Set olMailItem = .Item(1)
End With
If olMailItem Is Nothing Then Exit Sub
End Select
Set myAttachments = olMailItem.Attachments
If myAttachments.Count > 0 Then
For lngAttachmentCount = myAttachments.Count To 1 Step -1
'-------------------------------------------------------------------------
' Add the attachment to the list of attachments (form)
'-------------------------------------------------------------------------
Attachment_Filename = myAttachments(lngAttachmentCount).FileName
With UserForm1.lstAttachments
.AddItem (Attachment_Filename)
.List(lngAttachmentListPos, 1) = Attachment_Type_Text
.List(lngAttachmentListPos, 2) = FormatSize(myAttachments(lngAttachmentCount).Size) & " KB"
End With
Next lngAttachmentCount
End If
End Sub
I added only the relevant parts of the code, so I hope I have not forgotten anything.
At the moment I show all attachments (also embedded images).
How would I find out if an attachment is embedded?
I found a possible solution here:
Distinguish visible and invisible attachments with Outlook VBA
The source code provided is not working, it seems like the two URLs in line 2 and 3 no longer exist.
Upvotes: 5
Views: 3080
Reputation: 388
With the help of the answer and comment from @DinahMoeHumm we went with this solution which seems to work:
Function outlook_att_IsEmbedded(Att As outlook.Attachment) As Boolean
Dim PropAccessor As outlook.PropertyAccessor
On Error GoTo outlook_att_IsEmbedded_error
outlook_att_IsEmbedded = False
Set PropAccessor = Att.PropertyAccessor
If PropAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x3712001E") <> "" Or _
PropAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x3713001E") <> "" Then
If PropAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x37140003") = 4 Then
outlook_att_IsEmbedded = True
End If
End If
outlook_att_IsEmbedded_exit:
Set PropAccessor = Nothing
Exit Function
outlook_att_IsEmbedded_error:
outlook_att_IsEmbedded = False
Resume outlook_att_IsEmbedded_exit
End Function
I don't know what the different probtags mean. Or what the 4 is. It seems like you could find a list of them here: https://learn.microsoft.com/en-us/openspecs/exchange_server_protocols/ms-oxprops/f6ab1613-aefe-447d-a49c-18217230b148#published-version (but I didn't)
Upvotes: 0
Reputation: 624
If you have the luxury of working in .NET rather than VBA, and after reading nicely reading outlook mailitem properties I realised that two of these properties can have different values depending on whether the message is in Unicode or not:
//PR_ATTACH_CONTENT_ID 0x3712001E (0x3712001F for Unicode)
//PR_ATTACH_CONTENT_LOCATION 0x3713001E (0x3713001F for Unicode)
which means I should include these in my testing for values:
Dim oPR As Outlook.PropertyAccessor = Nothing
Try
oPR = oAtt.PropertyAccessor
If Not String.IsNullOrEmpty(oPR.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x3712001E")) _
Or Not String.IsNullOrEmpty(oPR.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x3712001F")) _
Or Not String.IsNullOrEmpty(oPR.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x3713001E")) _
Or Not String.IsNullOrEmpty(oPR.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x3713001F")) Then
If CInt(oPR.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x37140003")) = 4 Then
Return True
End If
End If
Catch
Finally
If Not oPR Is Nothing Then
Try
Marshal.ReleaseComObject(oPR)
Catch
End Try
End If
oPR = Nothing
End Try
Return False
I hope that, between this and @Gener4tor 's answer which may be better suited to VBA code (?) a reader can find a solution to their question around this.
Upvotes: 0
Reputation: 624
In the Outlook object model it's very important to marshal your objects correctly. Leaving a PropertyAccessor hanging about is not good, so I would suggest a minor modification to the accepted answer as follows:
Const PR_ATTACH_CONTENT_ID = "http://schemas.microsoft.com/mapi/proptag/0x3712001F"
Function IsEmbedded(Att As Attachment) As Boolean
Dim PropAccessor As PropertyAccessor = Nothing
Try
PropAccessor = Att.PropertyAccessor
Return (PropAccessor.GetProperty(PR_ATTACH_CONTENT_ID) <> "")
Catch
Return False
Finally
If PropAccessor IsNot Nothing
Marshal.ReleaseCOMObject(PropAccessor)
End If
End Catch
End Function
Upvotes: 1
Reputation: 5721
I'm not sure if this is a solution that is valid in all cases, but it works in my environment. That means "test it properly".
Const PR_ATTACH_CONTENT_ID = "http://schemas.microsoft.com/mapi/proptag/0x3712001F"
Function IsEmbedded(Att As Attachment) As Boolean
Dim PropAccessor As PropertyAccessor
Set PropAccessor = Att.PropertyAccessor
IsEmbedded = (PropAccessor.GetProperty(PR_ATTACH_CONTENT_ID) <> "")
End Function
Call it with
If IsEmbedded(myAttachments(lngAttachmentCount)) Then
...
End If
The cryptic url-looking constant is not a url, but a property identifier. You can find a list of them here: https://interoperability.blob.core.windows.net/files/MS-OXPROPS/%5bMS-OXPROPS%5d.pdf
That property is set to the url of the attachment if embedded. If not embedded, then it is empty.
Upvotes: 5