1

Everyday I receive emails like this

ID | Name |  Price | QTY | Valid
 1 | ABC  | 100.50 |   5 | Y
 2 | XYZF |  28.34 |   8 | Y

I then copy the content of my email to an excel spreadsheet that I have.

Now what I want to achieve is run a Macro that will read this email and

  1. Create the columns so ID, Name, Price, QTY and Valid
  2. apply the valid values under the right column.

Is this achievable?

From my limited knowledge I have a macro which extracts the whole outlook message but how do I make them into columns and then apply the correct values to correct columns?

Macro

Sub ExportToExcel()
    On Error GoTo ErrHandler

    Dim appExcel As Excel.Application
    Dim wkb As Excel.Workbook
    Dim wks As Excel.Worksheet

    Dim rng As Excel.Range
    Dim strSheet As String
    Dim strPath As String

    Dim intRowCounter As Integer
    Dim intColumnCounter As Integer

    Dim msg As Outlook.MailItem
    Dim nms As Outlook.NameSpace
    Dim fld As Outlook.MAPIFolder

    Dim itm As Object
    strSheet = "test.xlsx"
    strPath = "C:\test\"
    strSheet = strPath & strSheet

    Debug.Print strSheet

    'Select export folder
    Set nms = Application.GetNamespace("MAPI")
    Set fld = nms.PickFolder

    'Handle potential errors with Select Folder dialog box.
    If fld Is Nothing Then
        MsgBox "There are no mail messages to export", vbOKOnly, "Error"
        Exit Sub
    ElseIf fld.DefaultItemType <> olMailItem Then
        MsgBox "There are no mail messages to export", vbOKOnly, "Error"
        Exit Sub
    ElseIf fld.Items.Count = 0 Then
        MsgBox "There are no mail messages to export", vbOKOnly, "Error"
        Exit Sub
    End If

    'Open and activate Excel workbook.
    Set appExcel = CreateObject("Excel.Application")
    appExcel.Workbooks.Open (strSheet)
    Set wkb = appExcel.ActiveWorkbook
    Set wks = wkb.Sheets(1)
    wks.Activate
    appExcel.Application.Visible = True

    'Copy field items in mail folder.
    For Each itm In fld.Items
        intColumnCounter = 1
        Set msg = itm
        intRowCounter = intRowCounter + 1
        Set rng = wks.Cells(intRowCounter, intColumnCounter)
        rng.Value = msg.To
        intColumnCounter = intColumnCounter + 1
        Set rng = wks.Cells(intRowCounter, intColumnCounter)
        rng.Value = msg.SenderEmailAddress
        intColumnCounter = intColumnCounter + 1
        Set rng = wks.Cells(intRowCounter, intColumnCounter)
        rng.Value = msg.Subject
        intColumnCounter = intColumnCounter + 1
        Set rng = wks.Cells(intRowCounter, intColumnCounter)
        rng.Value = msg.SentOn
        intColumnCounter = intColumnCounter + 1
        Set rng = wks.Cells(intRowCounter, intColumnCounter)
        rng.Value = msg.ReceivedTime
    Next itm

    Set appExcel = Nothing
    Set wkb = Nothing
    Set wks = Nothing
    Set rng = Nothing
    Set msg = Nothing
    Set nms = Nothing
    Set fld = Nothing
    Set itm = Nothing

    Exit Sub
ErrHandler:  
    If Err.Number = 1004 Then
        MsgBox strSheet & " doesn't exist", vbOKOnly, "Error"
    Else
        MsgBox Err.Number & "; Description: ", vbOKOnly, "Error"
    End If

    Set appExcel = Nothing
    Set wkb = Nothing
    Set wks = Nothing
    Set rng = Nothing
    Set msg = Nothing
    Set nms = Nothing
    Set fld = Nothing
    Set itm = Nothing
End Sub

Email example

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
ssrsnoob
  • 11
  • 3
  • 1
    the macro is now added – ssrsnoob Apr 03 '18 at 12:32
  • 1
    Thanks @Peh: I was struggling to read that code :). ssrsnoob: can you provide a sample of the email? Also, I'm presuming that your macro sits in **Outlook** and not **Excel**? – Zac Apr 03 '18 at 12:43
  • You could paste the table from the mail content into a temporary sheet and use [Range.TextToColumns Method](https://msdn.microsoft.com/en-us/vba/excel-vba/articles/range-texttocolumns-method-excel) to split it into columns. Then re-arrange the columns and copy paste the data into the desired worksheet. – Pᴇʜ Apr 03 '18 at 12:47
  • @Zac yes it sits in Outlook. The sample is in my post (ID,Name, Price, Quantity) – ssrsnoob Apr 03 '18 at 12:51
  • @Pᴇʜ I see but that is manual work.. I'm trying to achieve everything via code if possible – ssrsnoob Apr 03 '18 at 12:52
  • @ssrsnoob Everything in my comment can be done by code: Read the email content by code, create a temporary sheet by code, paste mail content by code … – Pᴇʜ Apr 03 '18 at 12:57
  • Also, does the expected email come in your **InBox** or some other folder? I suspect it's your **InBox** but didn't want to assume. @Pᴇʜ has your answer. If I get time, I'll put something together – Zac Apr 03 '18 at 13:03
  • @Zac yep it comes to inbox. What i want to do is let it come to inbox run the macro. End of the day I have a rule to move all these emails to another folder – ssrsnoob Apr 03 '18 at 13:08
  • @Zac - the part `Set fld = nms.PickFolder` allows the user to pick up a folder, thus it is not the **Inbox** by default. – Vityata Apr 03 '18 at 13:08
  • @Pᴇʜ Ok great. Sorry I misunderstood the original comment. How hard is it to do something like that? I just do know how to split the email into relevant columns.. But would be great to see an example of your method if you have any – ssrsnoob Apr 03 '18 at 13:09
  • @Vityata. it originally comes to inbox. I've only added the pickfolder because end of the day i have a rule which moves to another folder and there maybe times i will need to run from new folder – ssrsnoob Apr 03 '18 at 13:11
  • @ssrsnoob hard to say if we don't see the full body of a real email. Can you add one to your question? Or add a screenshot? – Pᴇʜ Apr 03 '18 at 13:15
  • @Pᴇʜ.. Added the exact email I just received for your reference.. I removed the to and from for security. Thanks – ssrsnoob Apr 03 '18 at 13:47
  • Well I recommend playing around with the macro recorder and the text to columns function in the data ribbon. Create a new worksheet paste your email content in A1 and use something like `Columns("A:A").TextToColumns Destination:=Range("A1"), DataType:=xlDelimited, TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=True, Tab:=True, Semicolon:=False, Comma:=False, Space:=True, Other:=True, OtherChar:= "|", FieldInfo:=Array(Array(1, 1), Array(2, 1), Array(3, 1), Array(4, 1), Array(5, 1)), TrailingMinusNumbers:=True` to split it into columns. Then extract your data. this should help. – Pᴇʜ Apr 03 '18 at 15:02
  • @ssrsnoob, in what "form" is the content of the email extracted? I mean: 1) what type of variable is holding it 2) is it a long `string` with linefeed to separate rows? – DisplayName Apr 03 '18 at 15:20
  • @DisplayName it is all stored as string – ssrsnoob Apr 03 '18 at 16:10
  • @ssrsnoob, in “one” string? – DisplayName Apr 03 '18 at 16:21
  • @DisplayName my mistake.. Its stored in an excel range – ssrsnoob Apr 04 '18 at 09:21

1 Answers1

0
  • You can delete the lines starting with Set appExcel = Nothing ending with Set itm = Nothing. They are useless, as far as at the end of the "macro", the routine variables are set to Nothing anyhow.

  • It is a good idea not to use Integer in VBA - Why Use Integer Instead of Long?

  • This line Set nms = Application.GetNamespace("MAPI") could be written like this, to make the code a bit more robust: Set nms = Outlook.Application.GetNamespace("MAPI")

At the end, your question is more like "how can I extract a string from this":

ID | Name |  Price | QTY | Valid
 1 | ABC  | 100.50 |   5 | Y
 2 | XYZF |  28.34 |   8 | Y

to some Excel table. To get the corresponding string, you have to use the .Body. See yourself, changing the loop:

For Each itm In fld.Items
    lines = Split(itm.Body, vbCrLf)
    For Each line In lines
        If Len(line) - Len(Replace(line, "|", "")) > 3 Then
            Cells(Row, Column) = Split(line, "|")(0)
            Cells(Row, Column + 1) = Split(line, "|")(1)
            Cells(Row, Column + 2) = Split(line, "|")(2)
            Cells(Row, Column + 3) = Split(line, "|")(3)
        End If
    Next
Next itm

Once you have 4 or more | per line, then you do Split(line,"|") and you pass each one of the elements of the array to the corresponding column.

Vityata
  • 42,633
  • 8
  • 55
  • 100
  • thanks for your answer? So how does this create columns? – ssrsnoob Apr 03 '18 at 14:24
  • @ssrsnoob - after the `If Len(line)...` condition, it reads the line and depending on it, it writes in specific columns. The `Row`, `Column` are variables, which you can iterate over. It needs some adjusting in order to understand which value goes where. – Vityata Apr 03 '18 at 14:29
  • 1
    ok i see.. I appreciate your help.. I will play around with it to match my requirements – ssrsnoob Apr 03 '18 at 14:37
  • the above code doesnt work. As soon as it hits `Cells(Row, Column) = Split(line, "|")(0)` it hits my error handler – ssrsnoob Apr 04 '18 at 15:40
  • @ssrsnoob - what are the values of `Row`, `Column` and `line`? – Vityata Apr 04 '18 at 15:42
  • Line - "ID | Name| Price |QTY | Valid" Row and column are empty – ssrsnoob Apr 05 '18 at 08:53
  • @ssrsnoob - `Row` and `Column` should not be empty. They should be with values, based on the specific `row` and `column`. These values should be assigned to them somehow, most probably through a loop. – Vityata Apr 05 '18 at 08:57
  • do have an example? – ssrsnoob Apr 05 '18 at 15:48
  • @ssrsnoob - from your code - `Cells(intRowCounter, intColumnCounter)`. The intRowCounter is `Row` and the `intColumnCounter` is `Column`. – Vityata Apr 05 '18 at 16:26