Question

Here is what I am looking for:

I have 20 different folders in outlook, each has same email body structure and format. each email body has 3 to 7 hyperlinks i want to export one of these hyperlinks (its easy to identify as it has a same starting/a specific word within - it doesn't matter if we export this specific hyperlink or all of them because we can later edit them within excel).

I want these hyperlinks to be exported into cells in excel sheet

WHAT I AM DOING RIGHT NOW:

I am using a clipboard to go to each email. right click copy link and then pasting into a notepad or excel.

let me know if you guys have any suggestions. This will really simplify my work.. and surely of any other who may look for similar solutions.

regards,

AA

Was it helpful?

Solution 4

Guys I am using codetwo outlook exporter to perform this task. I somehow stumbled upon it.. Thanks Marc nd Expfresh! your solutions are great but i found another way before even trying them.. This is great that this forum has helpful people. Just for people facing the same problem: USE CODETWO outlook Exporter. - Does the job. regards - Addy

OTHER TIPS

You can export to excel, but before copying to excel,

->You have to select emails in which hyperlinks are present. By selecting emails righclick and select send to one-note.

-> One-note will open. Flip through the page tabs in this section (on the right-hand side)of One-note . select all the mails(pages) and rightclick->copy.

  1. Now you can paste the copied items in notepad.
  2. Now u can copy all contents in notepad to excel.
  3. you can find or apply filter, filter->textfilter->contains required word or phrase (its easy to identify as it has a same starting/a specific word within).

  4. If u directly copy from onenote to excel means all tables, attachment and others will be pasted, then it will be difficult to filter or find required hyperlinks.

  5. since you are saying 20 folders it is not possible to send folders to onenote, u need to open 20 folder then u can select any number of emails in each folder.

:)

I cannot fit my solution in a single answer because it exceeds the size limit. This is part 2 of my answer. It contains a block of code described in part 1. Read Part 1 first.

Option Explicit
Public Type MAPIFolderDtl
  NameParent As String
  Folder As MAPIFolder
  NumMail As Long
  NumMeet As Long
End Type
' -----------------------------------------------------------------------
' ## Insert other routines here
' -----------------------------------------------------------------------
Sub FindInterestingFolders(ByRef IntFolderList() As MAPIFolderDtl, _
                           WantMail As Boolean, WantMeet As Boolean, _
                           NameSep As String, _
                           ParamArray NameFullList() As Variant)

  ' * Return a list of interesting folders.
  ' * To be interesting a folder must be named or be a subfolder of a named
  '   folder and contain mail and or meeting items if wanted.
  ' * Note: a top level folder cannot be returned as interesting because such
  '   folders are not of type MAPIFolder.
  ' * IntFolders()  The list of interesting folders.  See Type MAPIFolderDtl for
  '                 contents.
  ' * WantMail      True if a folder containing mail items is to be classified
  '                 as interesting.
  ' * WantMeet      True if a folder containing meeting items is to be classified
  '                 as interesting.
  ' * NameSep       SubFolder Names in NameList are of the form:
  '                 "Personal Folders" & NameSep & "Inbox"
  '                 NameSep can be any character not used in a folder name.  It
  '                 appears any character could be used in a folder name including
  '                 punctuation characters.  If in doubt, try Tab.
  ' * NameFullList  One or more full names of folders which might themselves be
  '                 interesting or might be the parent an interesting folders.

  Dim InxTLFList() As Long
  Dim InxIFLCrnt As Long
  Dim InxNFLCrnt As Long
  Dim InxTLFCrnt As Variant
  Dim NameFullCrnt As String
  Dim NamePartFirst As String
  Dim NamePartRest As String
  Dim Pos As Long
  Dim TopLvlFolderList As Folders

  InxIFLCrnt = 0        ' Nothing in IntFolderList()
  Set TopLvlFolderList = CreateObject("Outlook.Application").GetNamespace("MAPI").Folders

  For InxNFLCrnt = LBound(NameFullList) To UBound(NameFullList)
    NameFullCrnt = NameFullList(InxNFLCrnt)     ' Get next name
    ' Split name into first part and the rest.  For Example,
    ' "Personal Folders|NHSIC|Commisioning" will be split into:
    '   NamePartFirst:  Personal Folders
    '   NamePartRest:   NHSIC|Commissioning
    Pos = InStr(1, NameFullCrnt, NameSep)
    If Pos = 0 Then
      NamePartFirst = NameFullCrnt
      NamePartRest = ""
    Else
      NamePartFirst = Mid(NameFullCrnt, 1, Pos - 1)
      NamePartRest = Mid(NameFullCrnt, Pos + 1)
    End If

    ' Create list of indices into TopLvlFolderList in
    ' ascending sequence by folder name
    Call SimpleSortFolders(TopLvlFolderList, InxTLFList)

    ' NamePartFirst should be the name of a top level
    ' folder or empty. Ignore if it is not.
    For Each InxTLFCrnt In InxTLFList
      If NamePartFirst = "" Or _
         TopLvlFolderList.Item(InxTLFCrnt).Name = NamePartFirst Then
        ' All subfolders are a different type so they
        ' are handled by FindInterestingSubFolder
        Call FindInterestingSubFolders(IntFolderList, InxIFLCrnt, _
                                      "", TopLvlFolderList.Item(InxTLFCrnt), WantMail, _
                                      WantMeet, NameSep, NamePartRest)
      End If
    Next
  Next

  If InxIFLCrnt = 0 Then
    ' No folders found
    ReDim IntFolderList(0 To 0)
  Else
    ReDim Preserve IntFolderList(1 To InxIFLCrnt)    ' Discard unused entries
    'For InxIFLCrnt = 1 To UBound(IntFolderList)
    '  Debug.Print IntFolderList(InxIFLCrnt).NameParent & "|" & _
    '              IntFolderList(InxIFLCrnt).Folder.Name & " " & _
    '              IntFolderList(InxIFLCrnt).NumMail & " " & _
    '              IntFolderList(InxIFLCrnt).NumMeet
    'Next
  End If

End Sub
Sub FindInterestingSubFolders(ByRef IntFolderList() As MAPIFolderDtl, _
                              InxIFLCrnt As Long, NameParent As String, _
                              MAPIFolderCrnt As MAPIFolder, WantMail As Boolean, _
                              WantMeet As Boolean, NameSep As String, _
                              NameChild As String)

  ' * NameFull = ""
  '     MAPIFolderCrnt and all its subfolders are potentially of interest
  ' * NameFull <> ""
  '     Look further down hierarchy for subfolders of potential interest

  ' This routine can be called repeately by a parent routine to explore different parts
  ' of the folder hierarchy.  It calls itself recursively to work down the hierarchy.

  ' IntFolderList    ' Array of interesting folders.
  ' InxIFLCrnt       ' On the first call, InxIFLCrnt will be zero and the state of
                     ' IntFolderList will be undefined.
  ' NameParent       ' ... Grandparent & NameSep & Parent
  ' MAPIFolderCrnt   ' The current folder that is to be explored.
  ' WantMail         ' True if a folder has to contain mail to be interesting
  ' WantMeet         ' True if a folder has to contain meeting items to be interesting
  ' NameSep          ' The name separator character
  ' NameChild        ' Suppose the original path was xxx|yyy|zzz.  For each recurse down
                     ' a name is removed from the start of NameChild and added to the end
                     ' of NameParent.  When NameChild is blank, the target folder has
                     ' been reached.

  Dim InxSFList() As Long
  Dim InxSFCrnt As Variant
  Dim NameCrnt As String
  Dim NamePartFirst As String
  Dim NamePartRest As String
  Dim NumMail As Long
  Dim NumMeet As Long
  Dim Pos As Long

  Pos = InStr(1, NameChild, NameSep)
  If Pos = 0 Then
    NamePartFirst = NameChild
    NamePartRest = ""
  Else
    NamePartFirst = Mid(NameChild, 1, Pos - 1)
    NamePartRest = Mid(NameChild, Pos + 1)
  End If

  If NameParent = "" Then
    ' This folder has no parent.  It cannot be interesting.
    NameCrnt = MAPIFolderCrnt.Name
  Else
    ' This folder has a parent.  It could be interesting.
    NameCrnt = NameParent & NameSep & MAPIFolderCrnt.Name
    If NamePartFirst = "" Then
      If FolderHasRequiredItems(MAPIFolderCrnt, WantMail, _
                                            WantMeet, NumMail, NumMeet) Then
        ' Debug.Print NameCrnt & " interesting"
        If InxIFLCrnt = 0 Then
          ReDim IntFolderList(1 To 100)
        End If
        InxIFLCrnt = InxIFLCrnt + 1
        If InxIFLCrnt > UBound(IntFolderList) Then
          ReDim Preserve IntFolderList(1 To 100 + UBound(IntFolderList))
        End If
        IntFolderList(InxIFLCrnt).NameParent = NameParent
        Set IntFolderList(InxIFLCrnt).Folder = MAPIFolderCrnt
        IntFolderList(InxIFLCrnt).NumMail = NumMail
        IntFolderList(InxIFLCrnt).NumMeet = NumMeet
      Else
        ' Debug.Print NameCrnt & " not interesting"
      End If
    End If
  End If

  If MAPIFolderCrnt.Folders.Count = 0 Then
    ' No subfolders
  Else
    Call SimpleSortMAPIFolders(MAPIFolderCrnt, InxSFList)
    For Each InxSFCrnt In InxSFList
      If NamePartFirst = "" Or _
        MAPIFolderCrnt.Folders(InxSFCrnt).Name = NamePartFirst Then
        Select Case NamePartFirst
          ' Ignore folders that can cause problems
          Case "Sync Issues"
          Case "RSS Feeds"
          Case "Public Folders"
          Case Else
            ' Recurse to analyse next level down
            Call FindInterestingSubFolders(IntFolderList, InxIFLCrnt, NameCrnt, _
                                          MAPIFolderCrnt.Folders(InxSFCrnt), WantMail, _
                                          WantMeet, NameSep, NamePartRest)
        End Select
      End If
     Next
  End If

End Sub
Function FolderHasRequiredItems(MAPIFolderCrnt As MAPIFolder, WantMail As Boolean, _
                                WantMeet As Boolean, ByRef NumMail As Long, _
                                ByRef NumMeet As Long) As Boolean

  ' Return True if folder is interested.  That is: at least one of the following is true:
  '    WantMail = True And NumMail > 0
  '    WantMeet = True And NumMeet > 0
  ' Values for NumMail and NumMeet are set whether or not the folder is interesting

  Dim FolderItem As Object
  Dim FolderItemClass As Long
  Dim InxItemCrnt As Long

  NumMail = 0
  NumMeet = 0

  ' Count mail and meeting items in folder
  For InxItemCrnt = 1 To MAPIFolderCrnt.Items.Count
    Set FolderItem = MAPIFolderCrnt.Items.Item(InxItemCrnt)

    ' This seems to avoid syncronisation errors
    FolderItemClass = 0
    On Error Resume Next
    FolderItemClass = FolderItem.Class
    On Error GoTo 0

    Select Case FolderItemClass
      Case olMail
        NumMail = NumMail + 1
      Case olMeetingResponsePositive, olMeetingRequest, olMeetingCancellation, _
           olMeetingResponseNegative, olMeetingResponseTentative
        NumMeet = NumMeet + 1
    End Select
  Next

  If WantMail And NumMail > 0 Then
    FolderHasRequiredItems = True
    Exit Function
  End If
  If WantMeet And NumMeet > 0 Then
    FolderHasRequiredItems = True
   Exit Function
  End If
  FolderHasRequiredItems = False

End Function
Sub SimpleSortMAPIFolders(MAPIFolderList As MAPIFolder, _
                                            ByRef InxArray() As Long)

  ' On exit InxArray contains the indices into MAPIFolderList sequenced by
  ' ascending name.  The sort is performed by repeated passes of the list
  ' of indices that swap adjacent entries if the higher come first.
  ' Not an efficient sort but adequate for short lists.

  Dim InxIACrnt As Long
  Dim InxIALast As Long
  Dim NoSwap As Boolean
  Dim TempInt As Long

  Debug.Assert MAPIFolderList.Folders.Count >= 1  ' Must be at least one folder

  ReDim InxArray(1 To MAPIFolderList.Folders.Count)  ' One entry per folder
  ' Fill array with indices
  For InxIACrnt = 1 To UBound(InxArray)
    InxArray(InxIACrnt) = InxIACrnt
  Next

  ' Each repeat of the loop movest the folder with the highest name
  ' to the end of the list.  Each repeat checks one less entry.
  ' Each repeats partially sorts the leading entries and may result
  ' in the list being sorted before all loops have been performed.
  For InxIALast = UBound(InxArray) To 1 Step -1
    NoSwap = True
    For InxIACrnt = 1 To InxIALast - 1
      If MAPIFolderList.Folders(InxArray(InxIACrnt)).Name > _
         MAPIFolderList.Folders(InxArray(InxIACrnt + 1)).Name Then
        NoSwap = False
        ' Move higher entry one slot towards the end
        TempInt = InxArray(InxIACrnt)
        InxArray(InxIACrnt) = InxArray(InxIACrnt + 1)
        InxArray(InxIACrnt + 1) = TempInt
      End If
    Next
    If NoSwap Then
      Exit For
    End If
  Next

End Sub

I cannot fit my solution in a single answer because it exceeds the size limit. This is part 1 of my answer. I have moved one block of code to a second answer.

This is a VBA solution. You give a good specification so I believe this will be close to your requirement. I hope I have included enough comments to allow you to make final adjustments. If not, ask.

This first block of code contains sub-routines written by me for me. They perform tasks I find useful. They include comments but they are comments written to remind me what they do not to help someone else understand them. The macros I have written for you use them and I explain how to use them. For the moment I suggest you do not worry about how these sub-routines do what they do.

I should perhaps warn you that I rarely use the error handling functionality in my own macros because I do not want them to fail gracefully; I want them to stop on the problem statement so I can understand and correct the cause.

Within Outlook, open the VBA Editor, insert a module and copy this first block of code into it. You will also need to click Tools then References. Is "Microsoft Excel nn.n Object Library" near the top and is it ticked? If it is not ticked, you must scroll done the list, find this reference and tick it. The value of "nn.n" will depend on the version of Excel you use. Only if you have more than one version of Excel installed will you have a choice.

Answer continued below code.

This code moved to the second part of the answer.

Below are four macros. The first three are tutorials and the fourth is my solution.

If your Outlook installation is like mine you will have folders Personal Folders, Archive Folders and perhaps others. Within Personal Folders you will have the standard folders Inbox, Outbox and so on. You may have added your own folders within these standard folders or you may have added them to Personal Folders. On my own system I have a variety of folders including !Family and !Tony. Each contains sub-folders and one of the sub-folders within !Tony is Amazon.

In the first macro, the statement you most need to understand it:

 Call FindInterestingFolders(FolderList, True, False, "|", _
         "Personal Folders|!Family", "Personal Folders|!Tony|Amazon")

FindInterestingFolders is one of the sub-routines included in the code above. The second line of this statement specifies, in a style I find convenient, the names of the two folders I mentioned. The macro FindInterestingFolders returns information about these two folders and any sub-folders or sub-sub-folders they may have. You will have to replace these two names with the folders you want searched. If the 20 folders are all under one parent, you can specify that single parent. If the 20 folders are scattered you might have to specify the names of all twenty.

The first macro outputs to the Immediate Window the names of all the folders found by FindInterestingFolders. On my system, it outputs:

Personal Folders|!Family|Chloe & Euan
Personal Folders|!Family|Geoff
Personal Folders|!Family|Lucy & Mark
Personal Folders|!Tony|Amazon
Personal Folders|!Tony|Amazon|Trueshopping Ltd

Copy this macro into the module you created above and play with it until you get it to create a list of the 20 folders you want searched.

Answer continued below code.

Sub ExtractHyperLinks1()

  ' Outputs a sorted list of interesting folders to the Immediate Window.

  Dim FolderList() As MAPIFolderDtl
  Dim InxFL As Long

  ' Set FolderList to a list of interesting folders.
  ' The True means a folder has to containing mail items to be interesting.
  ' The False means I am uninterested in meeting items.
  ' The "|" defines the name separator used in the list of folder names
  ' that follow.
  Call FindInterestingFolders(FolderList, True, False, "|", _
             "Personal Folders|!Family", "Personal Folders|!Tony|Amazon")

  For InxFL = LBound(FolderList) To UBound(FolderList)
    With FolderList(InxFL)
      Debug.Print .NameParent & "|" & .Folder.Name
    End With
  Next

End Sub

Hope that was not too difficult. You will have to copy your amended call of FindInterestingFolders into the following macros.

Macro 2 builds on macro 1. It searches the interesting folders for mail items with Html bodies. For each Html body, it searches for anchor tags and outputs to the Immediate Window each tag and the next 58 characters. The Immediate Window only shows the last 200 or so rows so you may only see the bottom of the output. This doesn't matter; the idea is to give you a first look at what the macro can see. On my system, the output ends:

  Tony Dallimore 13/02/2012 15:42:00 RE: Product details enquiry from Amazon customer ...
    <A HREF="mailto:16dhtcxlxwbh7fx@marketplace.amazon.co.uk">ma
    <A HREF="http://www.amazon.co.uk/gp/help/customer/display.ht
    <A HREF="http://www.amazon.co.uk/gp/help/customer/display.ht
  Trueshopping Ltd - Amazon Marketplace 14/02/2012 09:08:39 RE: Product details enquiry ...
    <A HREF="http://www.amazon.co.uk/gp/help/customer/display.ht
    <A HREF="http://www.amazon.co.uk/gp/help/customer/display.ht

The header lines contain the Sender, ReceivedTime and Subject of the mail item.

Add this macro to the module, copy the amended call of FindInterestingFolders over the top of my call and run it. Almost immediately, you will be warned that a macro is accessing emails. You will have to give permission for the macro to continue and select a period for it to continue. I am assuming you have the security level set to Medium which is standard. If you have set it to something different, you will get different options.

Answer continued below code.

Sub ExtractHyperLinks2()

  ' Gets a list of interesting folders.
  ' Searches the list for mail items with Html bodies that contain an anchor.
  ' For each such mail item it outputs to the Immediate Window:
  '   Name of folder (if not already output for an earlier mail item)
  '     Sender ReceivedTime Subject
  '       First 60 characters of first anchor
  '       First 60 characters of second anchor
  '       First 60 characters of third anchor

  Dim FolderList() As MAPIFolderDtl
  Dim FolderNameOutput As Boolean
  Dim InxFL As Long
  Dim InxItem As Long
  Dim PosAnchor As Long

  Call FindInterestingFolders(FolderList, True, False, "|", _
             "Personal Folders|!Family", "Personal Folders|!Tony|Amazon")

  For InxFL = LBound(FolderList) To UBound(FolderList)
    FolderNameOutput = False
    With FolderList(InxFL).Folder
      For InxItem = 1 To .Items.Count
        With .Items.Item(InxItem)
          If .Class = olMail Then
            If .HtmlBody <> "" Then
              ' This mail item has an Html body so might have a hyperlink.
              If InStr(1, LCase(.HtmlBody), "<a ") <> 0 Then
                ' It has at least one anchor
                If Not FolderNameOutput Then
                  Debug.Print FolderList(InxFL).NameParent & "|" & _
                              FolderList(InxFL).Folder.Name
                  FolderNameOutput = True
                End If
                Debug.Print "  " & .SenderName & " " & _
                            .ReceivedTime & " " & .Subject
                PosAnchor = InStr(1, LCase(.HtmlBody), "<a ")
                Do While PosAnchor <> 0
                  Debug.Print "    " & Mid(.HtmlBody, PosAnchor, 60)
                  PosAnchor = InStr(PosAnchor + 1, LCase(.HtmlBody), "<a ")
                Loop
              End If
            End If
          End If
        End With
      Next
    End With
  Next

End Sub

Again I hope that was easy. I am not sure how useful the next macro is. It was a step in my development but it contains nothing of importance that is not also within the final macro. It may be worth you studying it because the final macro will have two important changes from Macro 2.

What Macro 3 does is extract the URLs from the anchor tag and discard those that start "mailto:". Html allows more variation than I have allowed for because I have never seen an email that took advantage of that flexibility. It is possible you will have to enhance my code if your emails differ from what I expect. You only want one of the URLs from each email so you might want to add the code to discard the others.

Again, add this macro to the module, copy the amended call of FindInterestingFolders over the top of my call and run it. On my system the last few line of the output are:

  Tony Dallimore 13/02/2012 15:42:00 RE: Product details enquiry from ...
    http://www.amazon.co.uk/gp/help/customer/display.html?nodeId=11081621
    http://www.amazon.co.uk/gp/help/customer/display.html?nodeId=3149571
  Trueshopping Ltd - Amazon Marketplace 14/02/2012 09:08:39 RE: Product ...
    http://www.amazon.co.uk/gp/help/customer/display.html?nodeId=11081621
    http://www.amazon.co.uk/gp/help/customer/display.html?nodeId=3149571

Answer continued below code.

Sub ExtractHyperLinks3()

  ' Gets a list of interesting folders.
  ' Searches the list for mail items with Html bodies that contain an
  ' acceptable anchor. An acceptable anchor is one for which the url
  ' does not start "mailto:".
  ' For each acceptable anchor it outputs to the Immediate Window:
  '   Name of folder (if not already output for an earlier mail item)
  '     Sender ReceivedTime Subject (if not already output)
  '       Url from acceptable anchor

  Dim FolderList() As MAPIFolderDtl
  Dim FolderNameOutput As Boolean
  Dim InxFL As Long
  Dim InxItem As Long
  Dim ItemHeaderOutput As Boolean
  Dim LcHtmlBody As String
  Dim PosAnchor As Long
  Dim PosTrailingQuote As Long
  Dim PosUrl As Long
  Dim Quote As String
  Dim Url As String
  Call FindInterestingFolders(FolderList, True, False, "|", _
             "Personal Folders|!Family", "Personal Folders|!Tony|Amazon")

  For InxFL = LBound(FolderList) To UBound(FolderList)
    FolderNameOutput = False
    With FolderList(InxFL).Folder
      For InxItem = 1 To .Items.Count
        ItemHeaderOutput = False
        With .Items.Item(InxItem)
          If .Class = olMail Then
            If .HtmlBody <> "" Then
              ' This mail item has an Html body so might contain hyperlinks.
              LcHtmlBody = LCase(.HtmlBody)
              If InStr(1, LcHtmlBody, "<a ") <> 0 Then
                ' It has at least one anchor
                PosAnchor = InStr(1, LCase(.HtmlBody), "<a ")
                Do While PosAnchor <> 0
                  PosUrl = InStr(PosAnchor, LcHtmlBody, "href=")
                  PosUrl = PosUrl + 5
                  Quote = Mid(LcHtmlBody, PosUrl, 1)  ' Extract quote used in html
                  PosUrl = PosUrl + 1
                  PosTrailingQuote = InStr(PosUrl, LcHtmlBody, Quote)
                  Url = Mid(.HtmlBody, PosUrl, PosTrailingQuote - PosUrl)
                  If Left(LCase(Url), 7) <> "mailto:" Then
                    ' I am interested in this url
                    If Not FolderNameOutput Then
                      Debug.Print FolderList(InxFL).NameParent & "|" & _
                                  FolderList(InxFL).Folder.Name
                      FolderNameOutput = True
                    End If
                    If Not ItemHeaderOutput Then
                      Debug.Print "  " & .SenderName & " " & _
                                 .ReceivedTime & " " & .Subject
                      ItemHeaderOutput = True
                    End If
                    Debug.Print "    " & Url
                  End If
                  PosAnchor = InStr(PosTrailingQuote, LCase(.HtmlBody), "<a ")
                Loop
              End If
            End If
          End If
        End With
      Next
    End With
  Next

End Sub

For the final macro I created a worksheet in one of the workbooks I use for developing answers.

Within the final macro you will find the statement:

  Const WkBkPathFile As String = "C:\DataArea\Play\Combined 10 V02.xls"

You need to replace this with the path and file name of your workbook.

You will also find this statement:

  Const WkShtName As String = "URLs"

I have used worksheet URLs. I suggest you start by creating a worksheet like mine. Once you have got the final macro working, you can adapt it to your requirements.

I have four columns in my worksheet: Folder Name, Sender Name, Received Time and URL. The third column holds the full date and time but I formatted it to only display a short date. There is nothing in your question to suggest you want these extra columns. I thought it was worth demonstrating what you could do and leave you to delete the code if it is not interesting.

I do think you will need to do something with Received Time. Unless you move processed emails out of the 20 folders, each run of the macro will add the full set of URLs again. There are many techniques for not processing emails again. For example, you could add a user category to processed emails. However, I suspect the easiest approach is:

  • Add a hidden worksheet to the workbook.
  • Set cell A1 of this worksheet to "Latest processed email" and set B1 to 1-Jan-2000.
  • Add to the code which discards uninteresting emails, a test for the Received time being after this date/time.
  • Record the latest Received time of any processed email.
  • Write the latest Received time of any processed email to cell B1 of the hidden worksheet.

I have included a lot of comments in the final macro explaining how I accumulate data and write it to the worksheet so I will not repeat myself here. I wish you luck and repeat the instruction at the beginning to ask if anything is unclear.

Again, add this macro to the module, copy the amended call of FindInterestingFolders over the top of my call. This time you will also have to update one or both of the constant statements before running the macro.

Sub ExtractHyperLinks()

  ' Open destination workbook.
  ' Find last used row in destination worksheet.
  ' Gets a list of interesting folders.
  ' Searches the list for mail items with Html bodies that contain an
  ' acceptable anchor. An acceptable anchor is one for which the url
  ' does not start "mailto:".
  ' For each acceptable anchor it outputs to the workbook:
  '   Column 1 := Name of folder
  '   Column 2 := Sender
  '   Column 3 := ReceivedTime
  '   Column 4 := Url

  Dim ExcelWkBk As Excel.Workbook
  Dim FolderList() As MAPIFolderDtl
  Dim FolderName As String
  Dim InterestingURL As Boolean
  Dim InxOutput As Long
  Dim InxFL As Long
  Dim InxItem As Long
  Dim ItemCrnt As MailItem
  Dim LcHtmlBody As String
  Dim OutputValue(1 To 50, 1 To 4)
  Dim PosAnchor As Long
  Dim PosTrailingQuote As Long
  Dim PosUrl As Long
  Dim Quote As String
  Dim RowNext As Long
  Dim TargetAddr As String
  Dim Url As String

  ' Replace constant value with path and file name of your workbook.
  Const WkBkPathFile As String = "C:\DataArea\Play\Combined 10 V02.xls"
  Const WkShtName As String = "URLs"

  Set ExcelWkBk = Application.CreateObject("Excel.Application"). _
                                                   Workbooks.Open(WkBkPathFile)

  With ExcelWkBk
    .Application.Visible = True         ' Slows the macro but helps during testing
    With .Worksheets(WkShtName)
      ' Find last used row in destination worksheet by going to bottom of sheet
      ' then moving up until a non-empty row is found then going down one.
      ' .End(xlUp) is VBA equivalent of Ctrl+Up.
      RowNext = .Cells(Rows.Count, "A").End(xlUp).Row + 1
    End With
  End With

  Call FindInterestingFolders(FolderList, True, False, "|", _
             "Personal Folders|!Family", "Personal Folders|!Tony|Amazon")

  InxOutput = 0

  For InxFL = LBound(FolderList) To UBound(FolderList)

    FolderName = FolderList(InxFL).NameParent & "|" & FolderList(InxFL).Folder.Name

    With FolderList(InxFL).Folder

      For InxItem = 1 To .Items.Count
        With .Items.Item(InxItem)
          If .Class = olMail Then
            If .HtmlBody <> "" Then
              ' This mail item has an Html body so might contain hyperlinks.
              LcHtmlBody = LCase(.HtmlBody)
              If InStr(1, LcHtmlBody, "<a ") <> 0 Then
                ' It has at least one anchor
                PosAnchor = InStr(1, LCase(.HtmlBody), "<a ")
                Do While PosAnchor <> 0
                  PosUrl = InStr(PosAnchor, LcHtmlBody, "href=")
                  PosUrl = PosUrl + 5
                  Quote = Mid(LcHtmlBody, PosUrl, 1)  ' Extract quote used in html
                  PosUrl = PosUrl + 1
                  PosTrailingQuote = InStr(PosUrl, LcHtmlBody, Quote)
                  Url = Mid(.HtmlBody, PosUrl, PosTrailingQuote - PosUrl)
                  InterestingURL = True     ' Assume interesting until find otherwise
                  If Left(LCase(Url), 7) = "mailto:" Then
                    InterestingURL = False
                  End If

                  ' **********************************************************
                  ' Set InterestingURL = False for any other urls you want
                  ' to reject.  If you can tell a URL is ininteresting by
                  ' looking at it, you can use code like mine.
                  ' **********************************************************

                  If InterestingURL Then

                    ' This URL and supporting data is to be output to the
                    ' workbook.
                    ' Rather than output data to the workbook cell by cell,
                    ' which can be slow, I build it up in the array
                    ' OutputValue(1 to 50, 1 To 4).  It is normal in a 2D array
                    ' for the first dimension to be for columns and the second
                    ' for rows. Arrays to be read from or written to a worksheet
                    ' are the other way round.  You can resize the second
                    ' dimension of a dynamic array but not the first so you
                    ' cannot resize an array being built for a workbook.  I
                    ' cannot resize the array so I have fixed its size at
                    ' compile time.
                    ' This code fills the array, writes it out to the workbook
                    ' and resets the array index.  I have 50 rows because I
                    ' wanted to test the filling and refilling of the array. I
                    ' would suggest you make it bigger.

                    InxOutput = InxOutput + 1
                    If InxOutput > UBound(OutputValue, 1) Then
                      ' Array is fill.  Output it to workbook
                      TargetAddr = "A" & RowNext & ":D" & _
                                   RowNext + UBound(OutputValue, 1) - 1
                      ExcelWkBk.Worksheets(WkShtName). _
                                          Range(TargetAddr).Value = OutputValue
                      RowNext = RowNext + 50
                      InxOutput = 1
                    End If
                    OutputValue(InxOutput, 1) = FolderName
                    OutputValue(InxOutput, 2) = .SenderName
                    OutputValue(InxOutput, 3) = .ReceivedTime
                    OutputValue(InxOutput, 4) = Url
                  End If
                  PosAnchor = InStr(PosTrailingQuote, LCase(.HtmlBody), "<a")
                Loop
              End If
            End If
          End If
        End With
      Next
    End With
  Next

  ExcelWkBk.Save             ' Save changes over the top of the original file.
  ExcelWkBk.Close (False)    ' Don't save changes
  Set ExcelWkBk = Nothing    ' Release resource

End Sub
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top