user1765608
user1765608

Reputation: 15

Loop through to copy multiple outlook attachments type mismatch error

I trying to loop through the message to copy multiple attachments, but no success, i'm getting 13 - type mismatch error!!!

Any suggestions will be appreciated.

my code is as follows,

Private Sub Items_ItemAdd(ByVal item As Object)

On Error GoTo ErrorHandler

    'Only act if it's a MailItem
    Dim Msg As Outlook.MailItem
    If TypeName(item) = "MailItem" Then
        Set Msg = item


        'Set folder to save in.
        Dim olDestFldr As Outlook.MAPIFolder
        Dim myAttachments As Outlook.Attachments
        Dim Att As String
        Dim i As Integer
        'location to save in.  Can be root drive or mapped network drive.
        Const attPath As String = "C:\Users\pkshahbazi\Documents\EmailAttachments\"
        i = 0
        'save attachment
        Set myAttachments = item.Attachments
        If Msg.Attachments.Count <> 0 Then
            For Each myAttachments In Msg.Attachments
                Att = myAttachments.item(i).DisplayName
                myAttachments.item(i).SaveAsFile attPath & Att
                'mark as read
                i = i + 1
            Next myAttachments
            Msg.UnRead = False
        End If
    End If

ProgramExit:
  Exit Sub

ErrorHandler:
  MsgBox Err.Number & " - " & Err.Description
  Resume ProgramExit
End Sub

Upvotes: 1

Views: 4316

Answers (2)

AndASM
AndASM

Reputation: 10398

You seem to be confusing two different kinds of loops. For Each...Next and For...Next statements have different structures. You may want to read the documentation and examples in the above linked reference.

In a For Each loop you don't have a counter variable tracking the index. It automatically retrieves each item from the collection for you.

In a For loop you have a counter variable that increases for you, you don't have to increment it.
(e.g. i = i + 1)
However if you are accessing a collection you must retrieve the current item yourself.
(e.g. myAttachments.Item(i), or you can use the shorter equivalent syntax of myAttachments(i) as that the .Item is implied in VBA)

Here is a working example that prints the file names for the currently active message's attachments to the Immediate window using each type of for loop.

Public Sub TestAttachments()
    Dim message As MailItem
    Dim myAttachment As Attachment
    Dim i As Long

    Set message = ThisOutlookSession.ActiveInspector.CurrentItem

    Debug.Print "For Each...Next"
    For Each myAttachment In message.Attachments
      Debug.Print "Filename: " & myAttachment.FileName
    Next myAttachment

    Debug.Print "For...Next Statement"
    For i = 1 To message.Attachments.Count
      Set myAttachment = message.Attachments(i)
      Debug.Print "Index: " & i & " Filename: " & myAttachment.FileName
    Next i
End Sub

As you can see, the For Each loop is far simpler. However the For loop can give you a bit more control and information when accessing indexed collections. Usually you will want to use the For Each loop.

Also note, there is some confusion in the terminology used for collections in VBA. There are multiple different kinds of collections. There are also Collection objects, which are a type of collection but not the only type of collection.

Upvotes: 2

David Zemens
David Zemens

Reputation: 53653

You're using an indexed loop over an iterable collection (myAttachments) which is unnecessary. It is not the source of the error, but the error I see is related to your iteration:

You're getting a mismatch error because you're doing:

For each myAttachments in Msg.Attachments
   '...
Next

You have already assigned myAttachments as Msg.Attachments and it is of type Outlook.Attachments. This is an iterable collection, but you need to iterate using an Outlook.Attachment type variable.

Dim olAttch as Outlook.Attachment

Then, modify your loop like (untested):

    Set myAttachments = Msg.Attachments
        For Each olAttch In myAttachments
            Att = olAttch.DisplayName
            olAttch.SaveAsFile attPath & Att
        Next olAttch
        Msg.UnRead = False

Upvotes: 1

Related Questions