I'm trying to extract first table of each mail of a specific folder to Excel. If there is more than one table in the mail we can exclude it and move to next mail item. Below is the code I have at the moment. Could you please help?
Public Sub Import_Tables_From_Outlook_Emails()
Dim oApp As Outlook.Application, oMapi As Outlook.MAPIFolder
Dim oMail As Outlook.MailItem, HTMLdoc As MSHTML.HTMLDocument
Dim tables As MSHTML.IHTMLElementCollection, table As MSHTML.HTMLTable
Dim objExcelApp As Excel.Application, x As Long, y As Long, destCell As Range
Dim objExcelWorkbook As Excel.Workbook, objExcelWorksheet As Excel.Worksheet
Set objExcelApp = CreateObject("Excel.Application") 'Create a new excel workbook
Set objExcelWorkbook = objExcelApp.Workbooks.Add
objExcelApp.Visible = True
Set destCell = ActiveSheet.Cells(Rows.Count, "A").End(xlUp)
On Error Resume Next
Set oApp = GetObject(, "OUTLOOK.APPLICATION")
If oApp Is Nothing Then Set oApp = CreateObject("OUTLOOK.APPLICATION")
On Error GoTo 0
Set oMapi = oApp.GetNamespace("MAPI").PickFolder
If Not oMapi Is Nothing Then
For Each oMail In oMapi.items
'Get HTML tables from email object
Set HTMLdoc = New MSHTML.HTMLDocument
With HTMLdoc
.Body.innerHTML = oMail.HTMLBody
Set tables = .getElementsByTagName("table")
End With
For Each table In tables
For x = 0 To table.Rows.Length - 1
For y = 0 To table.Rows(x).Cells.Length - 1
destCell.Offset(x, y).Value = _
table.Rows(x).Cells(y).innerText
Next y
Next x
Sheets.Add After:=ActiveSheet
Range("A1").Activate
Set destCell = ActiveSheet.Range("A1")
Next
Next
End If
Set oApp = Nothing
Set oMapi = Nothing
Set oMail = Nothing
Set HTMLdoc = Nothing
Set tables = Nothing
MsgBox "Finished"
End Sub
The following macro prompts the user to select a folder from Outlook, loops though each item in the folder, and copies the first table from each item to a separate worksheet in a newly created workbook.
Edit
The code has been edited to 1) restrict the mail items based on ReceivedTime, 2) sort the restricted items by ReceivedTime, and in descending order, 3) loop through the items from earliest to latest date.
Option Explicit
Public Sub Import_Tables_From_Outlook_Emails()
Dim oMapiFolder As Folder
Dim oMail As Object
Dim oMailItems As Object
Dim oRestrictItems As Object
Dim oHTMLDoc As Object
Dim oHTMLTable As Object
Dim xlApp As Object
Dim xlWkb As Object
Dim r As Long
Dim c As Long
Dim i As Long
Set oMapiFolder = Application.GetNamespace("MAPI").PickFolder
If oMapiFolder Is Nothing Then
Exit Sub
End If
On Error Resume Next
Set xlApp = GetObject(, "Excel.Application")
If xlApp Is Nothing Then
Set xlApp = CreateObject("Excel.Application")
xlApp.Visible = True
End If
On Error GoTo 0
Set xlWkb = xlApp.workbooks.Add(-4167) 'xlWBATWorksheet
Set oHTMLDoc = CreateObject("htmlfile")
Set oMailItems = oMapiFolder.Items
Set oRestrictItems = oMailItems.Restrict("[ReceivedTime] >= '" & Format("1/1/17 12:00am", "ddddd h:nn AMPM") & "'")
oRestrictItems.Sort "[ReceivedTime]", olDescending
For i = 1 To oRestrictItems.Count
Set oMail = oRestrictItems(i)
With oHTMLDoc
.Body.innerHTML = oMail.HTMLBody
Set oHTMLTable = .getElementsByTagName("table")(0)
End With
If Not oHTMLTable Is Nothing Then
xlWkb.Worksheets.Add after:=xlWkb.activesheet
For r = 0 To oHTMLTable.Rows.Length - 1
For c = 0 To oHTMLTable.Rows(r).Cells.Length - 1
xlWkb.activesheet.Range("A1").Offset(r, c).Value = _
oHTMLTable.Rows(r).Cells(c).innerText
Next c
Next r
Set oHTMLTable = Nothing
End If
Next i
xlApp.DisplayAlerts = False
xlWkb.Worksheets(1).Delete
xlApp.DisplayAlerts = True
Application.ActiveExplorer.Activate
Set oMapiFolder = Nothing
Set oMail = Nothing
Set oHTMLDoc = Nothing
Set oHTMLTable = Nothing
Set xlApp = Nothing
Set xlWkb = Nothing
MsgBox "Finished"
End Sub
Related
My code as below to extract all inbox, folder and subfolder. Is working fine for main mailbox. but when I input to extract from shared mailbox is only extracting Inbox. Any wrong with my code below? I able to extract Inbox, folder and subfolder if I remove this part "Set olShareName = Ns.CreateRecipient("Shared Email Address")"
Public xlSht As Excel.Worksheet
Sub DocumentFolders(objParent As Folder, lRow As Long)
Dim objItm As Object
Dim objFolder As Folder
On Error Resume Next
With xlSht
For Each objItm In objParent.Items
.Cells(lRow, 1) = objParent
.Cells(lRow, 2) = objItm.Subject
.Cells(lRow, 3) = objItm.ReceivedTime
lRow = lRow + 1
Next
End With
On Error GoTo 0
If objParent.folders.Count > 0 Then
For Each objFolder In objParent.folders
Call DocumentFolders(objFolder, lRow)
Next
End If
End Sub
Sub ExportInformation()
Dim xlApp As Excel.Application
Dim xlWb As Excel.Workbook
Dim Ns As Outlook.Namespace
Dim olShareName As Outlook.Recipient
Dim OutlookFolder As Outlook.Folder
Set Ns = Outlook.Application.GetNamespace("MAPI")
Set olShareName = Ns.CreateRecipient("Shared Email Address")
olShareName.Resolve
Set OutlookFolder = Ns.GetSharedDefaultFolder(olShareName, olFolderInbox) '.folders("FolderName")
Set xlApp = New Excel.Application
Set xlWb = xlApp.Workbooks.Add
Set xlSht = xlWb.Sheets(1)
With xlSht
.Cells(1, 1) = "Folder"
.Cells(1, 2) = "Subject"
.Cells(1, 3) = "Received Time"
End With
Call DocumentFolders(Session.GetSharedDefaultFolder(olShareName, olFolderInbox), 2)
xlApp.Visible = True
Set xlSht = Nothing
Set xlWb = Nothing
Set xlApp = Nothing
End Sub
I have code that extracts the body of email which has the subject line "Volume data".
Let's say I have 10 emails in my inbox folder which has the subject line "Volume data".
I want to loop through all the emails, find which email has subject line "Volume data" and then extract the email body from those 10 emails.
My code is stopping at the first instance where it finds the mentioned subject.
Option Explicit
Sub impOutlookTable()
Dim wkb As Workbook
Set wkb = ThisWorkbook
Sheets("Sheet1").Cells.ClearContents
' point to the desired email
Const strMail As String = "emailaddress"
Dim oApp As Outlook.Application
Dim oMapi As Outlook.MAPIFolder
Dim oMail As Outlook.MailItem
Dim x As Long, y As Long
Dim destCell As Range
Dim i As Long
Dim oItem As Object
With ActiveSheet
Set destCell = .Cells(Rows.Count, "A").End(xlUp)
End With
On Error Resume Next
Set oApp = GetObject(, "OUTLOOK.APPLICATION")
If (oApp Is Nothing) Then Set oApp = CreateObject("OUTLOOK.APPLICATION")
On Error GoTo 0
Set oMapi = oApp.GetNamespace("MAPI").Folders(strMail).Folders("inbox")
Set oMail = oMapi.Items(oMapi.Items.Count)
For Each oItem In oMapi.Items
If oItem.Subject = "Volume data" Then
Exit For
End If
Next oItem
If Not oItem Is Nothing Then
' get html table from email object
Dim HTMLdoc As MSHTML.HTMLDocument
Dim tables As MSHTML.IHTMLElementCollection
Dim table As MSHTML.HTMLTable
Set HTMLdoc = New MSHTML.HTMLDocument
With HTMLdoc
.Body.innerHTML = oItem.HTMLBody
Set tables = .getElementsByTagName("table")
End With
'import in Excel
For Each table In tables
For x = 0 To table.Rows.Length - 1
For y = 0 To table.Rows(x).Cells.Length - 1
destCell.Offset(x, y).Value = table.Rows(x).Cells(y).innerText
Next y
Next x
Set destCell = destCell.Offset(x)
Next
End If
Set oApp = Nothing
Set oMapi = Nothing
Set oMail = Nothing
Set HTMLdoc = Nothing
Set tables = Nothing
wkb.SaveAs "C:\Users\Desktop\New_email.xlsm"
End Sub
Put all of the "Action" code inside the If statement inside your loop instead of after it, and then remove the Exit For.
You will also need a counter or something so that you aren't just saving overtop of the same file for each iteration.
UNTESTED
Option Explicit
Sub impOutlookTable()
Dim iCounter As Integer
iCounter = 1
Dim wkb As Workbook
Set wkb = ThisWorkbook
Sheets("Sheet1").Cells.ClearContents
' point to the desired email
Const strMail As String = "emailaddress"
Dim oApp As Outlook.Application
Dim oMapi As Outlook.MAPIFolder
Dim oMail As Outlook.MailItem
Dim x As Long, y As Long
Dim destCell As Range
Dim i As Long
Dim oItem As Object
With ActiveSheet
Set destCell = .Cells(Rows.Count, "A").End(xlUp)
End With
On Error Resume Next
Set oApp = GetObject(, "OUTLOOK.APPLICATION")
If (oApp Is Nothing) Then Set oApp = CreateObject("OUTLOOK.APPLICATION")
On Error GoTo 0
Set oMapi = oApp.GetNamespace("MAPI").Folders(strMail).Folders("inbox")
Set oMail = oMapi.Items(oMapi.Items.Count)
For Each oItem In oMapi.Items
If oItem.Subject = "Volume data" Then
' get html table from email object
Dim HTMLdoc As MSHTML.HTMLDocument
Dim tables As MSHTML.IHTMLElementCollection
Dim table As MSHTML.HTMLTable
Set HTMLdoc = New MSHTML.HTMLDocument
With HTMLdoc
.Body.innerHTML = oItem.HTMLBody
Set tables = .getElementsByTagName("table")
End With
'import in Excel
For Each table In tables
For x = 0 To table.Rows.Length - 1
For y = 0 To table.Rows(x).Cells.Length - 1
destCell.Offset(x, y).Value = table.Rows(x).Cells(y).innerText
Next y
Next x
Set destCell = destCell.Offset(x)
Next
Set oApp = Nothing
Set oMapi = Nothing
Set oMail = Nothing
Set HTMLdoc = Nothing
Set tables = Nothing
wkb.SaveAs "C:\Users\Desktop\New_email_" & iCounter & ".xlsm"
iCounter = iCounter + 1
End If
Next oItem
End Sub
I used this code from https://www.slipstick.com/developer/vba-copy-outlook-email-excel-workbook/ and modified it to extract a string from email body.
Instead of using it in Outlook, I run it from my target Excel workbook after including the MS Outlook 16.0 Object Library.
It worked the first time I fired it, but later that day I received
run-time error 91 - "Object variable or With block variable not set"
on line
Set xlSheet = xlWB.Sheets("IMPORT")
I deduced this error occurs when code is launched from the target workbook. It works when fired from Outlook or different workbook.
Option Explicit
Private Const xlUp As Long = -4162
Sub Extract_string_from_email_body()
Dim objOL As Outlook.Application
Dim objItems As Outlook.Items
Dim objFolder As Outlook.MAPIFolder
Dim olItem As Outlook.MailItem
Dim xlApp As Object
Dim xlWB As Object
Dim xlSheet As Object
Dim vText, vText2, vText3, vText4, vText5 As Variant
Dim sText As String
Dim rCount As Long
Dim bXStarted As Boolean
Dim enviro As String
Dim strPath As String
Dim Reg1 As Object
Dim M1 As Object
Dim M As Object
'original code to run from Outlook and output string to existing workbook
'enviro = CStr(Environ("USERPROFILE"))
'strPath = enviro & "\Documents\test.xlsx"
'my target workbook I've launched my code from
strPath = "X:\02 Workbooks\Workbook.xlsm"
On Error Resume Next
Set xlApp = GetObject(, "Excel.Application")
If Err <> 0 Then
Set xlApp = CreateObject("Excel.Application")
bXStarted = True
End If
On Error GoTo 0
Set xlWB = xlApp.Workbooks.Open(strPath)
Set xlSheet = xlWB.Sheets("IMPORT") 'error occurs here
rCount = xlSheet.Range("Q" & xlSheet.Rows.Count).End(xlUp).Row
rCount = rCount + 1
Set objOL = Outlook.Application
Set objFolder = objOL.Session.GetDefaultFolder(olFolderInbox).Parent.Folders("Data").Folders("Register")
Set objItems = objFolder.Items
For Each olItem In objItems
On Error Resume Next
With olItem
sText = olItem.Body
Set Reg1 = CreateObject("VBScript.RegExp")
With Reg1
.Pattern = "((OPO\/\d{2}\/[CLRPWBDFGIMSKT]\/\S{10}\/[SO|DL|MM]{2}\/\d{3}))"
End With
If Reg1.test(sText) Then
Set M1 = Reg1.Execute(sText)
For Each M In M1
vText = Trim(M.SubMatches(1))
Next
xlSheet.Range("Q" & rCount) = vText
rCount = rCount + 1
End If
End With
Next
xlWB.Close 1
If bXStarted Then
xlApp.Quit
End If
Set M = Nothing
Set M1 = Nothing
Set Reg1 = Nothing
Set xlApp = Nothing
Set xlWB = Nothing
Set xlSheet = Nothing
Set objItems = Nothing
Set objFolder = Nothing
Set objOL = Nothing
End Sub
First of all, if you run the code in Excel there is no need to get an Excel Application instance or create a new one in the code:
Set xlApp = GetObject(, "Excel.Application")
If Err <> 0 Then
Set xlApp = CreateObject("Excel.Application")
bXStarted = True
End If
On Error GoTo 0
Use the Applicaiton property availble for VBA macros out of the box.
Second, you need to initialize the Outlook Application properly:
Set objOL = Outlook.Application
But it should be:
Set objOL = New Outlook.Application
You can read more about that in the Automating Outlook from a Visual Basic Application article.
I want to export messages to Excel. However, when I try running the macro, I don't see it in the list.
I just copied the code below from http://www.slipstick.com/developer/vba-copy-outlook-email-excel-workbook
Option Explicit
Const xlUp As Long = -4162
Sub CopyToExcel(olItem As Outlook.MailItem)
Dim xlApp As Object
Dim xlWB As Object
Dim xlSheet As Object
Dim rCount As Long
Dim bXStarted As Boolean
Dim strPath As String
Dim M1 As Object
Dim M As Object
Dim lgLastRow As Long 'specify the last data row
lgLastRow = Range("A1048576").End(xlUp).Row 'Take Note: very useful!!
enviro = CStr(Environ("username"))
'the path of the workbook
strPath = enviro & "C:\Desktop\Project\SR History File.xlsx"
On Error Resume Next
Set xlApp = GetObject(, "Excel.Application")
If Err <> 0 Then
Application.StatusBar = "Please wait while Excel source is opened ... "
Set xlApp = CreateObject("Excel.Application")
bXStarted = True
End If
On Error GoTo 0
'Open the workbook to input the data
Set xlWB = xlApp.Workbooks.Open(strPath)
Set xlSheet = xlWB.Sheets("Sheet1")
'Find the next empty line of the worksheet
rCount = lgLastRow = Range("A1048576").End(xlUp).Row + 1
xlSheet.Range("A" & rCount) = olItem.SentOn
xlSheet.Range("B" & rCount) = olItem.SenderEmailAddress
xlSheet.Range("C" & rCount) = olItem.Subject
xlWB.Close 1
If bXStarted Then
xlApp.Quit
End If
Set M = Nothing
Set M1 = Nothing
Set Reg1 = Nothing
Set xlApp = Nothing
Set xlWB = Nothing
Set xlSheet = Nothing
End Sub
The code cannot run without a parameter, olItem.
Open a mailitem then run this, which will be in the list.
Option Explicit
Sub CopyToExcel_Test
Dim currItem as mailitem
Set currItem = ActiveInspector.currentitem
CopyToExcel currItem
ExitRoutine:
Set currItem = Nothing
End Sub
I have an Excel file where when the user presses a button:
A range is selected and copied to the clipboard
An Outlook message is created based on a template
E-mail will be sent "on behalf of" instead of the user's name/account
The user adds a date in the e-mail and pastes the copied range into the template.
This is all working but Outlook adds the user's signature and that is unwanted.
Sub SelectArea()
Application.ScreenUpdating = False
lastCol = ActiveSheet.Range("a1").End(xlToRight).Column - 2
lastRow = ActiveSheet.Cells(500, lastCol).End(xlUp).Row
ActiveSheet.Range("a1", ActiveSheet.Cells(lastRow, lastCol)).Copy
Dim OutApp As Outlook.Application
Dim OutMail As Outlook.MailItem
Set OutApp = CreateObject("Outlook.Application")
Set OutMail = OutApp.CreateItemFromTemplate("\\network\path\to\the\MailTemplate.oft")
With OutMail
.SentOnBehalfOfName = """DepartmentX"" <DepartmentX#company.com>"
.Display
End With
Application.ScreenUpdating = True
End Sub
Currently there is no DeleteSig sub. It used to be inside With OutMail. I tested the example from the Microsoft site 1:1 but could not get it to work.
The code from Microsoft:
Sub TestDeleteSig()
Dim objOL As Outlook.Application
Dim objMsg As Outlook.MailItem
Set objOL = CreateObject("Outlook.Application")
Set objMsg = objOL.CreateItem(olMailItem)
objMsg.Display
Call DeleteSig(objMsg)
Set objMsg = Nothing
End Sub
Sub DeleteSig(msg As Outlook.MailItem)
Dim objDoc As Word.Document
Dim objBkm As Word.Bookmark
On Error Resume Next
Set objDoc = msg.GetInspector.WordEditor
Set objBkm = objDoc.Bookmarks("_MailAutoSig")
If Not objBkm Is Nothing Then
objBkm.Select
objDoc.Windows(1).Selection.Delete
End If
Set objDoc = Nothing
Set objBkm = Nothing
End Sub
It opens a new e-mail message with signature and gives a compile error.
"User-defined type not defined".
It marks Sub DeleteSig(msg As Outlook.MailItem) in yellow and highlights objDoc As Word.Document in blue.
This will remove the signature from an email template
The last Sub will place a selected range from Excel into the body of the template
Option Explicit
Public Sub TestDeleteSig()
Dim olApp As Object, olMsg As Object
Set olApp = CreateObject("Outlook.Application")
Set olMsg = olApp.CreateItem(0)
olMsg.Display
DeleteSig olMsg
InsertRng olMsg
Set olMsg = Nothing
End Sub
Private Sub DeleteSig(msg As Object)
Dim wrdDoc As Object, wrdBkm As Object
On Error Resume Next
Set wrdDoc = msg.GetInspector.WordEditor
Set wrdBkm = wrdDoc.Bookmarks("_MailAutoSig")
If Not wrdBkm Is Nothing Then wrdBkm.Range.Delete
Set wrdDoc = Nothing
Set wrdBkm = Nothing
End Sub
Private Sub InsertRng(msg As Object)
Dim rng As Range
Set rng = Selection.SpecialCells(xlCellTypeVisible)
If Not rng Is Nothing Then
If rng.Rows.Count = 1 And rng.Columns.Count = 1 Then
If Len(rng) = 0 Then Set rng = ActiveSheet.UsedRange.Cells(1)
End If
rng.Copy
msg.GetInspector.WordEditor.Content.PasteSpecial xlPasteAll
Application.CutCopyMode = False
End If
End Sub
If only one cell is selected and is empty, it will paste the first cell with data from ActiveSheet
So, this is the VBA code that is currently running.
It selects the range, copies it to a blank e-mail, pastes it there and deletes the users' signature.
The "problem" is that it should open a new e-mail based on an existing template (.oft) and paste it where it reads "<insert table/overview>". The oft has an image header and some (html/formatted) text in it.
I'm startin to wonder if what I'm trying to accomplish is even possible.
Sub DeleteSig()
Dim olApp As Object, olMsg As Object
Set olApp = CreateObject("Outlook.Application")
Set olMsg = olApp.CreateItemFromTemplate("\\myserver\my_template.oft")
olMsg.Display
DeleteSig_action olMsg
InsertRng olMsg
Set olMsg = Nothing
End Sub
Sub DeleteSig_action(msg As Object)
Dim wrdDoc As Object, wrdBkm As Object
On Error Resume Next
Set wrdDoc = msg.GetInspector.WordEditor
Set wrdBkm = wrdDoc.Bookmarks("_MailAutoSig")
If Not wrdBkm Is Nothing Then wrdBkm.Range.Delete
Set wrdDoc = Nothing
Set wrdBkm = Nothing
End Sub
Sub InsertRng(msg As Object)
Dim rng As Range
lastCol = ActiveSheet.Range("a1").End(xlToRight).Column - 2
lastRow = ActiveSheet.Cells(500, lastCol).End(xlUp).Row
Set rng = ActiveSheet.Range("a1", ActiveSheet.Cells(lastRow, lastCol))
rng.Copy
msg.GetInspector.WordEditor.Content.PasteSpecial xlPasteAll
Application.CutCopyMode = False
End Sub
Hers is the complete working code which removes signature from the mail template.
Option Explicit
Sub openEmail()
Dim cfgFromEmail As String
Dim cfgNotice As String
Dim cfgTemplate As String
Dim appOutlook As Outlook.Application
Dim newEmail As Outlook.MailItem
Dim rownum As Integer
Dim colnum As Integer
rownum = 6
cfgFromEmail = Sheets("Email").Range("O5").Value
cfgNotice = Sheets("Email").Cells(rownum, 10) '10 = column J
cfgTemplate = Sheets("Email").Cells(rownum, 11) '11 = column K
Set appOutlook = CreateObject("Outlook.Application")
Set newEmail = appOutlook.CreateItemFromTemplate(ThisWorkbook.Path & "\" & cfgTemplate & ".oft")
'Set template = mailApp.CreateItem(olMailItem) 'Creates a blank email
If cfgNotice <> "null" Then 'If is not blank
MsgBox cfgNotice, vbInformation, "Before you send the email"
End If
Dim objDoc As Word.Document
Dim objBkm As Word.Bookmark
On Error Resume Next
Set objDoc = newEmail.GetInspector.WordEditor
Set objBkm = objDoc.Bookmarks("_MailAutoSig")
If Not objBkm Is Nothing Then
objBkm.Select
objDoc.Windows(1).Selection.Delete
End If
Set objDoc = Nothing
Set objBkm = Nothing
With newEmail
.SentOnBehalfOfName = cfgFromEmail
.Display 'Show the email
End With
Set newEmail = Nothing
Set appOutlook = Nothing
End Sub