I am writing a macro in excel to export outlook emails to excel. The code works fine but the date format of 'Flag Completed Date' field changes when the data is exported to excel.
In outlook the format is "dd-mm-yyyy hh:mm" (Example: 21 January 2015 12:42).
When the emails are exported to excel, the format of this field changes to 21 January 2015 00:00
There are other date fields, their formats are correctly showing up in excel. Only this field is having the format issue.
Please help!
Thank you!
KSP
Here is the code that I am using:
Sub InboxToExcel()
Dim objOL As Outlook.Application
Dim objNS As Outlook.Namespace
Dim objInbox As Outlook.Folder
Dim objTable As Outlook.Table
Dim objRow As Outlook.Row
Dim objMsg As Outlook.MailItem
Dim objWB As Excel.Workbook
Dim objWS As Excel.Worksheet
Dim objRange As Excel.Range
Dim strFind As String
Dim strProps As String
Dim arr() As String
Dim val As Variant
Dim i As Integer
Dim intRow As Integer
strProps = _
"SenderName,To,Subject,SentOn,ReadReceiptRequested"
Set objOL = Application
Set objNS = objOL.Session
Set objInbox = objNS.GetDefaultFolder(olFolderInbox)
Set objTable = objInbox.GetTable
Set objWB = GetExcelWB()
Set objWS = objWB.Sheets(1)
objWS.Name = "Inbox"
arr = Split(strProps, ",")
intRow = 1
For i = 0 To UBound(arr)
objWS.Cells(intRow, i + 1) = arr(i)
objTable.Columns.Add arr(i)
Next
Set objRange = objWS.Range _
(objWS.Cells(1, 1), objWS.Cells(1, i + 1))
objRange.Font.Bold = True
Do Until objTable.EndOfTable
intRow = intRow + 1
Set objRow = objTable.GetNextRow
For i = 0 To UBound(arr)
val = objRow(arr(i))
Select Case VarType(val)
Case vbDate
val = DateToExcel(val)
Case vbBoolean
val = YesNoToString(val)
End Select
objWS.Cells(intRow, i + 1) = val
Next
Loop
For i = 1 To (UBound(arr) + 1)
objWS.Columns(i).EntireColumn.AutoFit
Next
objWS.Application.Visible = True
objWS.Activate
Set objOL = Nothing
Set objNS = Nothing
Set objRow = Nothing
Set objWB = Nothing
Set objWS = Nothing
Set objRange = Nothing
End Sub
Function DateToExcel(propVal)
Dim dteDate 'As Date
If IsDate(propVal) Then
dteDate = CDate(propVal)
If dteDate = #1/1/4501# Then
DateToExcel = Null
Else
DateToExcel = dteDate
End If
End If
End Function
Function YesNoToString(propVal)
If propVal = "True" Then
YesNoToString = "Yes"
Else
YesNoToString = "No"
End If
End Function
Related
I want to export e-mail data from a specific folder by a range of dates.
The macro exports the received date and the body of the email.
The objective is to search for certain data that comes from the extracted body and show them in other rows.
Due to the 32767 character limit that Excel has in a cell, the bodies of some emails are not being fully exported.
Is there a way to export the body in two rows instead of one to avoid the Excel limitation?
Other suggestions to accomplish this process are appreciated.
Sub ImportEmails()
Dim OutlookApp As Outlook.Application
Dim OutlookNamespace As Outlook.Namespace
Dim IFolder As Outlook.MAPIFolder
Dim OutlookMail As Variant
Dim i As Integer
Dim wb As Workbook
Dim ws As Worksheet
Dim rng As Range
Set OutlookApp = New Outlook.Application
'Outlook connection
Set OutlookNamespace = OutlookApp.GetNamespace("MAPI")
Set wb = ThisWorkbook
'Select the folder to export emails, depending on the userĀ“s folder name you must change it
Set IFolder = OutlookNamespace.GetDefaultFolder(olFolderInbox).Folders("Test")
Set ws = wb.Sheets("Imported")
i = 0
Application.ScreenUpdating = False
ws.Cells.Clear
'Create headers
ws.Range("A1").Value = "Date Time"
ws.Range("B1").Value = "Body"
'Condition to select the today date in case of blank and export the emails
If IsEmpty(Range("end_date").Value) = True Then
Range("end_date").Value = "=today()"
End If
'Exporting proccedure
For Each OutlookMail In IFolder.Items
'Date validation
If DateValue(OutlookMail.ReceivedTime) >= DateValue(Range("start_date")) And DateValue(OutlookMail.ReceivedTime) <= DateValue(Range("end_date")) Then
'Fill the worksheet cells with the emails
ws.Range("A2").Offset(i, 0).Value = OutlookMail.ReceivedTime
ws.Range("B2").Offset(i, 0).Value = OutlookMail.Body
i = i + 1
End If
Next OutlookMail
Application.ScreenUpdating = True
Set IFolder = Nothing
Set OutlookNamespace = Nothing
Set OutlookApp = Nothing
LRimpr = LastRow(ws)
Set rng = ws.Range("A2:B" & LRimpr)
'Sort the columns by newest to oldest using the worksheet last row
With rng
.Sort Key1:=.Cells(1), Order1:=xlDescending, _
Orientation:=xlTopToBottom, Header:=xlNo
End With
MsgBox "Emails are successfully imported", vbInformation, "Import complete"
ws.Activate
End Sub
If you would be happy exporting the email body in multiple cells in a single row then replace your line
ws.Range("B2").Offset(i, 0).Value = OutlookMail.Body
with
Const CHUNK_SIZE As Long = 32000
Dim segment As Long
segment = 0
Do While True
ws.Range("B2").Offset(i, segment).Value = Mid$(OutlookMail.Body, segment * CHUNK_SIZE + 1, CHUNK_SIZE)
segment = segment + 1
If segment * CHUNK_SIZE > Len(OutlookMail.Body) Then Exit Do
Loop
Adjust the value for CHUNK_SIZE to your requirements ... it controls the number of characters that will be put into each cell, with the last cell having the 'remaining' characters (or all the characters if the body has less characters than CHUNK_SIZE)
To split the body into cells in a column.
Option Explicit
Sub ImportEmails_SplitBody_MultipleRows()
' Reference Microsoft Outlook nn.n Object Library
Dim OutlookApp As Outlook.Application
Dim iFolder As Outlook.Folder
Dim iFolderItems As Outlook.Items
Dim j As Long
Dim OutlookItem As Object
Dim lenBody As Long
Dim maxLen As Long
Dim i As Long
Dim wb As Workbook
Dim ws As Worksheet
Dim rng As Range
Set OutlookApp = New Outlook.Application
' Select folder
Set iFolder = Session.GetDefaultFolder(olFolderInbox).Folders("Test")
' Sort items
Set iFolderItems = iFolder.Items
iFolderItems.Sort "[ReceivedTime]", True
Set wb = ThisWorkbook
Set ws = wb.Sheets("Imported")
i = 0
' Application is Excel. No impact on Outlook
'Application.ScreenUpdating = False
ws.Cells.Clear
'Create headers
ws.Range("A1").Value = "Date Time"
ws.Range("B1").Value = "Body"
'Condition to select today's date in case of blank
If IsEmpty(Range("end_date").Value) = True Then
Range("end_date").Value = "=today()"
End If
'Debug.Print Range("start_date")
'Debug.Print Range("end_date")
'Exporting procedure
maxLen = 32767
'Debug.Print " maxLen: " & maxLen
For j = 1 To iFolderItems.Count
'Date validation
If iFolderItems(j).Class = olMail Then
Set OutlookItem = iFolderItems(j)
'Debug.Print OutlookItem.Subject
If DateValue(OutlookItem.ReceivedTime) >= DateValue(Range("start_date")) And _
DateValue(OutlookItem.ReceivedTime) <= DateValue(Range("end_date")) Then
lenBody = Len(OutlookItem.Body)
Dim txt As String
txt = OutlookItem.Body
Dim lenTxt As Long
lenTxt = Len(txt)
Do Until lenTxt = 0
'Fill the worksheet cells with the emails
'Debug.Print " Len(txt): " & Len(txt)
If lenTxt > maxLen Then
ws.Range("A2").Offset(i, 0).Value = OutlookItem.ReceivedTime
ws.Range("B2").Offset(i, 0).Value = Left(txt, maxLen)
txt = Right(txt, Len(txt) - maxLen)
Else
ws.Range("A2").Offset(i, 0).Value = OutlookItem.ReceivedTime
ws.Range("B2").Offset(i, 0).Value = txt
txt = ""
End If
i = i + 1
lenTxt = Len(txt)
Loop
Set OutlookItem = Nothing
End If
End If
Next
Application.ScreenUpdating = True
Set iFolder = Nothing
Set iFolderItems = Nothing
Set OutlookApp = Nothing
MsgBox "Emails are successfully imported", vbInformation, "Import complete"
ws.Activate
End Sub
I have code that loops through all Outlook emails under a subfolder and extracts the body of the email based on the subject. Code takes a lot of time to loop through all emails as there are thousands of them.
How do I modify the code to append data, extracted from the latest emails, to the existing file instead of looping through all the emails and overwriting again & again?
Let's say I want to run the code every day to get the prior day's email data.
Option Explicit
Sub FinalMacro()
Application.DisplayAlerts = False
Dim iCounter As Integer
'iCounter = 1
Dim wkb As Workbook
Set wkb = ThisWorkbook
Sheets("Sheet1").Cells.Clear
' point to the desired email
Const strMail As String = "emailaddress#outlook.com"
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").Folders("Other mails")
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
Dim t As Long, r As Long, c As Long
Dim eRow As Long
For t = 0 To tables.Length - 1
eRow = Sheets(1).Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Row
For r = 0 To (tables(t).Rows.Length - 1)
For c = 0 To (tables(t).Rows(r).Cells.Length - 1)
Range("A" & eRow).Offset(r, c).Value = tables(t).Rows(r).Cells(c).innerText
Next c
Next r
eRow = Sheets(1).Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Row
Next t
Cells(eRow, 1) = "Date & Time of Receipt:" & " " & oItem.ReceivedTime
Cells(eRow, 1).Interior.Color = vbRed
Cells(eRow, 1).Font.Color = vbWhite
Cells(eRow, 1).Columns.AutoFit
Set oApp = Nothing
Set oMapi = Nothing
Set HTMLdoc = Nothing
Set tables = Nothing
wkb.Save '"C:\Users\Desktop\Trial_1.xlsm"
End If
Next oItem
Application.DisplayAlerts = True
End Sub
To quickly select (filter) latest emails, you can use Items.Restrict.
To use your workbook for the accumulative storage of information, you just need not to erase the sheet, but to find the last filled line and add the content from the letters after it.
Smth like (not tested):
Set oMapi = oApp.GetNamespace("MAPI").Folders(strMail).Folders("inbox").Folders("Other mails")
Set wkb = ThisWorkbook
Set append_ws = wkb.Sheets("Sheet1") ' this worksheet is for appending
'Sheets("Sheet1").Cells.Clear ' - remove this statement
' set filter to: non-flagged mailitems received < 1 day ago
flt = "[FlagStatus] <> 1 And [MessageClass]='IPM.Note' And [ReceivedTime]>='" & _
Format(Now - 1, "ddddd 0:00") & "'"
Set Restricted = oMapi.Items.Restrict(flt)
For I = Restricted.Count To 1 Step -1
Set oItem = Restricted(I)
If oItem.Subject = "Volume data" Then
content_from_email = "smth from letter" ' get the content from the letter
lastrow = append_ws.Cells(append_ws.Rows.Count, 1).End(xlUp).row + 1
append_ws.Cells(lastrow, 1).Value = content_from_email
oItem.MarkAsTask olMarkComplete ' set flag to the processed items
oItem.Save
End If
Next I
I am trying output a list of everyone that has emailed me, and the count of emails they sent.
I have two email accounts set up on Outlook (account A and account B). The below VBA outputs a count of users from the inbox folder for account A.
Is there a way to retrieve this data from a folder called 'Done' for Account B?
Sub CountInboxEmailsbySender()
Dim objDictionary As Object
Dim objInbox As Outlook.Folder
Dim i As Long
Dim objMail As Outlook.MailItem
Dim strSender As String
Dim objExcelApp As Excel.Application
Dim objExcelWorkbook As Excel.Workbook
Dim objExcelWorksheet As Excel.Worksheet
Dim varSenders As Variant
Dim varItemCounts As Variant
Dim nLastRow As Integer
Set objDictionary = CreateObject("Scripting.Dictionary")
Set objInbox = Outlook.Application.Session.Accounts.Item("edr.hub#bt.com")
For i = objInbox.Items.Count To 1 Step -1
If objInbox.Items(i).Class = olMail Then
Set objMail = objInbox.Items(i)
strSender = objMail.SenderEmailAddress
If objDictionary.Exists(strSender) Then
objDictionary.Item(strSender) = objDictionary.Item(strSender) + 1
Else
objDictionary.Add strSender, 1
End If
End If
Next
Set objExcelApp = CreateObject("Excel.Application")
objExcelApp.Visible = True
Set objExcelWorkbook = objExcelApp.Workbooks.Add
Set objExcelWorksheet = objExcelWorkbook.Sheets(1)
With objExcelWorksheet
.Cells(1, 1) = "Sender"
.Cells(1, 2) = "Count"
End With
varSenders = objDictionary.Keys
varItemCounts = objDictionary.Items
For i = LBound(varSenders) To UBound(varSenders)
nLastRow = objExcelWorksheet.Range("A" & objExcelWorksheet.Rows.Count).End(xlUp).Row + 1
With objExcelWorksheet
.Cells(nLastRow, 1) = varSenders(i)
.Cells(nLastRow, 2) = varItemCounts(i)
End With
Next
objExcelWorksheet.Columns("A:B").AutoFit
End Sub
I am exporting Outlook emails in custom table view to Excel. There are custom formula fields in the custom view. All the custom fields export except the formula field.
This is the formula field:
'AssignedDate' formula field: IIf([RequestAssigned]=True,Now(),"")
'RequestAssigned' is a checkbox field, when checked AssignedDate field will capture the date and time when it is checked.
I get a run-time error message-
Run-time error '-2147024809(8070057)':
could not complete the operation. One or more parameter values are not valid
If I remove that formula field the macro works.
Sub InboxToExcel()
Dim objOL As Outlook.Application
Dim objNS As Outlook.Namespace
Dim objInbox As Outlook.Folder
Dim objTable As Outlook.Table
Dim objRow As Outlook.Row
Dim objMsg As Outlook.MailItem
Dim objWB As Excel.Workbook
Dim objWS As Excel.Worksheet
Dim objRange As Excel.Range
Dim strFind As String
Dim strProps As String
Dim arr() As String
Dim val As Variant
Dim i As Integer
Dim intRow As Integer
strProps = _
"SenderName,To,Subject,SentOn,ReadReceiptRequested"
Set objOL = Application
Set objNS = objOL.Session
Set objInbox = objNS.GetDefaultFolder(olFolderInbox)
Set objTable = objInbox.GetTable
Set objWB = GetExcelWB()
Set objWS = objWB.Sheets(1)
objWS.Name = "Inbox"
arr = Split(strProps, ",")
intRow = 1
For i = 0 To UBound(arr)
objWS.Cells(intRow, i + 1) = arr(i)
objTable.Columns.Add arr(i)
Next
Set objRange = objWS.Range _
(objWS.Cells(1, 1), objWS.Cells(1, i + 1))
objRange.Font.Bold = True
Do Until objTable.EndOfTable 'POINTING HERE WHILE DEBUGGING
intRow = intRow + 1
Set objRow = objTable.GetNextRow
For i = 0 To UBound(arr)
val = objRow(arr(i))
objWS.Cells(intRow, i + 1) = val
Next
Loop
For i = 1 To (UBound(arr) + 1)
objWS.Columns(i).EntireColumn.AutoFit
Next
objWS.Application.Visible = True
objWS.Activate
Set objOL = Nothing
Set objNS = Nothing
Set objRow = Nothing
Set objWB = Nothing
Set objWS = Nothing
Set objRange = Nothing
End Sub
You cannot check the value of a checkbox directly in a formula. The following link shows you how to set a surrogate cell to store the answer.
http://blog.contextures.com/archives/2013/07/09/use-check-box-result-in-excel-formula/
I'm not an expert in VBA, got an error which I can't figure out, can you please help advise?
I need an excel macro to copy from all the emails in a folder to my excel, googled and found the below code. The code runs fine for some emails, after that there will be a runtime error 440: array index out of bounds at this line.
abody = Split(objfolder.Items(i).Body, vbNewLine)
Most of the time I just record macro and edit from there so I don't really understand what is array index out of bounds.
Really hope you can enlighten me, thank you so much in advance for your help... =)
Full code can be found below...
Added in the part where the macro will get the details of the email it's processing... But what is baffling me is the received details of the email does not match the body. Can anyone please help advise?
Sub test()
Dim olApp As Object
Dim olNS As Object
Dim olFldr As Object
Dim olMail As Object
Dim i As Integer
Dim j As Long
Dim abody() As String
Dim Cnt As Long
Dim arrData() As Variant
Set olApp = CreateObject("Outlook.Application")
Set olNS = olApp.GetNamespace("MAPI")
Set olFldr = olNS.GetDefaultFolder(olFolderInbox).Folders("temp")
Cnt = 0
For Each olMail In olFldr.Items
On Error GoTo errorhandler
Cnt = Cnt + 1
abody = Split(olFldr.Items(Cnt).Body, vbNewLine)
For j = 0 To UBound(abody)
Sheet1.Cells(65000, 1).End(xlUp).Offset(1, 0).Value = abody(j)
Next
ReDim Preserve arrData(1 To 1, 1 To Cnt)
arrData(1, Cnt) = olMail.ReceivedTime
Cells(1, 1).Value = arrData(1, Cnt)
Cells(1, 1).NumberFormat = "dd/mm/yyyy hh:mm:ss AM/PM"
olFldr.Items(Cnt).Move olNS.GetDefaultFolder(6).Folders("Processed")
Next
Set olApp = Nothing
Set olNS = Nothing
Set olFldr = Nothing
errorhandler:
Application.CutCopyMode = False
Set olApp = Nothing
Set olNS = Nothing
Set olFldr = Nothing
Exit Sub
End Sub
updated code:
Sub test()
Dim olApp As Object
Dim olNS As Object
Dim olFldr As Object
Dim olMail As Object
Dim i As Integer
Dim j As Long
Dim abody() As String
Dim Cnt As Long
Dim arrData() As Variant
Dim ws As Worksheet
Set olApp = CreateObject("Outlook.Application")
Set olNS = olApp.GetNamespace("MAPI")
Set olFldr = olNS.GetDefaultFolder(olFolderInbox).Folders("temp")
Set ws = ThisWorkbook.Sheets("Sheet1")
EmailCount = olFldr.Items.Count
MsgBox "Number of emails in the folder: " & EmailCount, , "email count"
Cnt = 1
For Each olMail In olFldr.Items
abody = Split(olMail.Body, vbNewLine)
For j = 0 To UBound(abody)
ws.Cells(65000, 1).End(xlUp).Offset(1, 0).Value = abody(j)
Next
ReDim Preserve arrData(1 To 1, 1 To Cnt)
arrData(1, Cnt) = olMail.ReceivedTime
ws.Cells(1, 1).Value = arrData(1, Cnt)
ws.Cells(1, 1).NumberFormat = "dd/mm/yyyy hh:mm:ss AM/PM"
olMail.Move olNS.GetDefaultFolder(6).Folders("Processed")
Cnt = Cnt + 1
Next
Set olApp = Nothing
Set olNS = Nothing
Set olFldr = Nothing
End Sub
Can you try to change your looping part to this.
Also add the declaration and variable assignment for the target Worksheet.
Dim ws as Worksheet
Set ws = ThisWorkbook.Sheets("Sheet1") 'added this to avoid the subscript out of range
Cnt = 1
For Each olMail In olFldr.Items
On Error GoTo errorhandler
abody = Split(olMail.Body, vbNewLine) 'changed this to olMail.Body since you are already iterating each mail
For j = 0 To UBound(abody)
ws.Cells(65000, 1).End(xlUp).Offset(1, 0).Value = abody(j) 'use the declared ws here
Next
ReDim Preserve arrData(1 To 1, 1 To Cnt)
arrData(1, Cnt) = olMail.ReceivedTime
ws.Cells(1, 1).Value = arrData(1, Cnt) 'use ws here as well if same Sheet1
ws.Cells(1, 1).NumberFormat = "dd/mm/yyyy hh:mm:ss AM/PM"
olMail.Move olNS.GetDefaultFolder(6).Folders("Processed") 'change to olMail as well
Cnt = Cnt + 1
Next
This is untested so i leave the testing to you. :)