Copying a rich text table from an Outlook email to Excel using VBA? -


i trying set automated process company work for. have set our hr system send out rich text table (only format) of employees taking time off in near future.

the hr system capable of storing time vacation, pto, & sick time every month. wrote code in sql have system send out monthly table of employees have time off in next month listed.

i attempting take information , have populate our outlook calendars. currently, have set excel sheet populate persons calendar list after information has been copied , pasted sheet.

ideally have information automatically copy excel sheet or set system creates appointments within outlook. i'm bit stumped @ moment.

all of previous attempts accomplish either goal have failed. i'm noob when comes vba, can appreciated. thank you.

the email looks lot of control (the blue row header , information in placed in rows underneath it):
emailform

edit: added improvements suggested @patrickk , added image of spreadsheet.

i figured out. looking @ issue wrong, didn't realize copy entire body of email clipboard , paste in excel spreadsheet without formatting getting wonky. came with, appears work well:

'____________________________________________________________ ' ' author: joshua bryant ' ' version 1.1 ' ' date: 8/16/2016 ' ' routine search system notifier email ' holds leave data. once found, call ' copy_paste_data sub routine take data ' selected email , copy clipboard. once ' copied subroutine paste excel ' leave notifier table workbook. calls add_time ' subroutine adjust start , end time columns of ' worksheet allow more readable calendar. ' routine temporarily disables excel notifications ' public, passes olitem copy_paste_data, returns nothing. ' ' version 1.1: added exit loop if statement, exit  ' loop once email has been found (if found exit for). ' __________________________________________________________ '  public sub get_data() ' declare variables   dim myolapp new outlook.application   dim mynamespace outlook.namespace   dim myinbox outlook.mapifolder   dim myitems outlook.items   dim myitem object   dim found boolean   dim olitem mailitem   dim objinsp outlook.inspector   dim mydate variant   dim datestr string   dim ooutlook object  ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' un-comment following section have program check , ' make sure outlook open before proceeding. not ' necessary program operate effectively: ' '    on error resume next '    set ooutlook = getobject(, "outlook.application") '    on error goto 0 ' '    if ooutlook nothing '        msgbox "outlook mail not open. please open outlook mail , try again." '        exit sub '    end if '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''      ' on error (wrong data type found) skip item ,     ' continue email.     on error resume next     ' initialize objinsp variable inspector item can     ' used search for, , point, items in outlook folder     set objinsp = outlook.application.activeinspector      ' create string item holds todays date in formatted manner.     datestr = cstr(datepart("m", date)) & "/" & cstr(datepart("d", date)) & "/" & cstr(datepart("yyyy", date))      ' initialize variables , select default message folder search.     set mynamespace = myolapp.getnamespace("mapi")     set myinbox = mynamespace.getdefaultfolder(olfolderinbox)     set myitems = myinbox.items      ' set intitial state of found variable false     found = false      ' loop search through items in selected mail folder.     each myitem in myitems         ' if item belongs outlook mail class continue.         ' else continue looking until no items present.         if myitem.class = olmail             ' once mail item found compare it's subject string.             ' if sting matchs hold selected item , set found variable true.             ' else continue looking until no items present.             if instr(1, myitem.subject, datestr & " upcoming leave notifier") > 0                 ' set held item equal mailitem type variable hold later use.                 ' takes object being pointed , saves later use.                 set olitem = myitem                 ' set true "flag" (make found variable true)                 found = true                 if found exit             end if         end if     next myitem      ' once items have been searched check if found "flag" true     ' if true notify end user , procede copying , pasting data worksheept.     ' if false go else.     if found = true          msgbox "data found."         ' if found pass item copy_paste_data , call sub rountine.         copy_paste_data olitem      ' else query end user date when email recieved.     else: ' set point return if item still not found @ user provided date. not_found:         ' prompt user date when email recieved system.         mydate = inputbox("email todays date not found." & chr(13) & chr(13) & "please enter date email recieved in field below. date should written in mm/dd/yyyy format." & chr(13) & chr(13) & "note: not include leading zeros. ex. 01/02/2015 should 1/2/2015" & chr(13))         ' if user not enter value or presses cancle exit routine.         if mydate = "" exit sub          ' repeat search email new date value.         each myitem in myitems             if myitem.class = olmail                 if instr(1, myitem.subject, mydate & " upcoming leave notifier") > 0                     set olitem = myitem                     found = true                     if found exit                 end if             end if         next myitem          ' query again see if email found         if found = true             ' if found pass item copy_paste_data , call sub rountine.             copy_paste_data olitem         ' else, repeat prompt end user.         else:             goto not_found         end if     end if      ' once information has been added run add time index results start , end times.      call add_time  end sub  '____________________________________________________________ ' ' author: joshua bryant ' ' version 1.0 ' ' date: 8/15/2016 ' ' subroutine takes object passed get_data , ' copies data body of email. pastes ' data active excel sheet. ' subroutine temporarily disables excel display alerts ' private, returns nothing. '____________________________________________________________ '  private sub copy_paste_data(olitem)   ' delcare / initialize variable   dim dataobj msforms.dataobject   set dataobj = new msforms.dataobject     ' copy html body of email data object     dataobj.settext olitem.htmlbody     ' copy data object clipboard     dataobj.putinclipboard     ' disable display alerts (e.g. size doesn't match warning)     application.displayalerts = false     ' paste contents of clipboard worksheet (dimensions dont have match exactly)     activesheet.paste destination:=worksheets("leave table").range("a3:g300")     ' notify end user data transfer successful.     msgbox "your data has been transfered successfully."     ' re-enable excel alerts     application.displayalerts = true  end sub   '____________________________________________________________ ' ' author: joshua bryant ' ' version 1.0 ' ' date: 8/15/2016 ' ' subroutine examines items in table , looks ' days multiple employees have requested time off ' on days increment each employees scheduled ' start , end time 30 minutes provide cleaner ' appointment view on calendar. allows names ' appear though listed on days of week ' added to. each new date, routine ' begin appointment start times @ 8:00 , add 30 ' minuted every subsequent employee. ' private, returns nothing. '____________________________________________________________ '  private sub add_time()   ' initialize variables   dim time date   dim holddate date   dim prevrowdate date   dim lastdate date   dim lastname string   dim nextrowdate date    ' set work sheet edited   dim wssrc worksheet   set wssrc = activeworkbook.sheets("leave table")      ' set initial values     holddate = datevalue(wssrc.cells(4, 3))     prevrowdate = datevalue(wssrc.cells(4, 3))     time = timevalue("08:00:00")     ' set values first row (after header) of table (row 3)     wssrc.cells(4, 8).value = timevalue("08:00:00")     wssrc.cells(4, 9).value = timevalue("08:30:00")     r = 4      ' loop find end of list     until trim(wssrc.cells(r, 1).value) = ""         r = r + 1     loop      ' set second last item ending point.     ' not want use last row because throw data type error when end reached.     r = r - 1     lastname = wssrc.cells(r, 1).value     lastdate = datevalue(wssrc.cells(r, 3))      ' begin @ row 4 (rows 1 & 2 headers. beginning @ row 3 include invalid data type row 2)     r = 5      ' repeat loop until second last row reached.         until wssrc.cells(r, 1).value = wssrc.cells(r, 1).value , datevalue(wssrc.cells(r, 3)) = lastdate         ' hold date in current row             holddate = datevalue(wssrc.cells(r, 3))             ' set next date equal date being held.             ' allows next loops conditions met entry do/while loop.             nextrowdate = datevalue(wssrc.cells(r, 3))             ' date previous row , hold comparison held date.             ' done endure add time loop not entered prematurely.             r = r - 1             prevrowdate = datevalue(wssrc.cells(r, 3))             r = r + 1              ' add time loop increment time in calendar 30 minutes             ' while holddate not equal prevrowdate or nextrowdate.             ' note: previous row date holds same value recieved outside of loop.             ' thus, condition relies entirely on nextrowdate.             until holddate <> prevrowdate or holddate <> nextrowdate                 ' date of next row.                 r = r + 1                 nextrowdate = datevalue(wssrc.cells(r, 3))                 r = r - 1                 ' plase current time value + 30 min start time column of row                 wssrc.cells(r, 8).value = cdate(time) + 1 / 48                 ' add 30 min time value                 time = cdate(time) + 1 / 48                 ' plase current time value + 30 min end time column of row                 wssrc.cells(r, 9).value = cdate(time) + 1 / 48                 ' increment row                 r = r + 1             loop             ' reset time 8:00             time = timevalue("08:00:00")             ' place 8:00 in start time column of row             wssrc.cells(r, 8).value = cdate(time)             ' place 8:30 in end time column of row             wssrc.cells(r, 9).value = cdate(time) + 1 / 48             ' increment row             r = r + 1         loop       ' add time values last date in table.      ' begin @ 7:30 simplicity     time = timevalue("07:30:00")      ' repeat loop add start , end times each person on last day of      ' table, adding 30 minutes each time.     until trim(wssrc.cells(r, 1).value) = ""          wssrc.cells(r, 8).value = cdate(time) + 1 / 48          time = cdate(time) + 1 / 48          wssrc.cells(r, 9).value = cdate(time) + 1 / 48          r = r + 1     loop  end sub 

the spreadsheet goes out , finds notification email today's date , copies , pastes spreadsheet can edited , later uploaded directly global calendar using following program:

'____________________________________________________________ ' ' author: joshua bryant ' ' version 1.0 ' ' date: 8/16/2016 ' ' main program call other subs. ' create_outlook sub calls clean_leave_calendar sub ' delete emails leave calendar before attempting ' add new items calendar. once calendar has ' been cleaned , times have been added, program ' creates new appointments items in predetermined outlook ' folder "ofolder". once appointment items have been ' created program notifies end user process ' ran , runs close_workbook subroutine ' close workbook without saving. '____________________________________________________________ '  public sub populate_calendar()   ' initialize variables   dim oapp object   dim onamespace namespace   dim ofolder object   dim wssrc worksheet   set wssrc = sheets("leave table")    ' call subroutines   call clean_leave_calendar      ' start looping @ row 3 (first 2 rows readability)     r = 4     ' do/while set condition     until trim(wssrc.cells(r, 1).value) = ""      ' create outlook session     set oapp = new outlook.application     ' set namespace     set onamespace = oapp.getnamespace("mapi")     ' set folder appointment created in.     set ofolder = onamespace.getfolderfromid("000000007cf129e6c6baa74f9b2ab399fabb280e01006ec36ffc70429b4eae1875321a4609670078c4fa00320000").items.add(olappointmentitem)      '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''     ' use following code in outlook find folder id #:     ' note: calendar want create appointments in     ' selected, press f11 bring outlook macros , run     ' code under "thisoutlooksession"     '     ' private sub getoutlookfolderid()     '     'determines folder id of folder     '    dim olfolder outlook.mapifolder     '    dim olapp outlook.application     '    set olapp = createobject("outlook.application")     '    set olfolder = olapp.getnamespace("mapi").pickfolder     '    olfolder.display     '    msgbox (olfolder.entryid)     '    set olfolder = nothing     '    set olapp = nothing     ' end sub     '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''      ' set block appointment configuration loop    ofolder        ' set subject line of event         .subject = wssrc.cells(r, 1).value & " " & wssrc.cells(r, 2).value        ' set start time         .start = datevalue(wssrc.cells(r, 3)) + wssrc.cells(r, 8).value        ' set end time         .end = datevalue(wssrc.cells(r, 3)) + wssrc.cells(r, 9).value        ' turn reminders off         .reminderset = false        ' set busy status free         .busystatus = 0        ' have body of event read decription leave form in viewpoint         .body = wssrc.cells(r, 4).value        ' save event in owners calendar         .save        ' end block         end        ' move next row         r = r + 1        ' repeat do/while loop until condition no longer valid     loop    ' clean house   set oapp = nothing   set onamespace = nothing   set ofolder = nothing   set wssrc = nothing    msgbox "data added outlook leave calendar." & chr(13) & chr(13) & "excel workbook close."    call closeworkbook  end sub  '____________________________________________________________ ' ' author: joshua bryant ' ' version 1.0 ' ' date: 8/15/2016 ' ' sub close current workbook without saving. ' before closing check make sure there no ' other workbooks open , if there none, ' close excel application well. sub ' temporarily disable displayed "would save ' workbook" notification. ' private, returns nothing. '____________________________________________________________ '  private sub closeworkbook() application.displayalerts = false if workbooks.count < 2 application.quit else thisworkbook.close end if end sub  '____________________________________________________________ ' ' author: joshua bryant ' ' version 1.0 ' ' date: 8/15/2016 ' ' sub call clean_leave_calendar subroutine ' 5 times. clean_leave_calendar subroutine ' appointment items in predefined outlook folder. once ' appointment item identified program ' perminately delete item avoid scheduling conflicts ' new items added. deletion loop runs 10 ' times ensure items removed. ' public, returns nothing '____________________________________________________________ '  public sub power_wash() dim integer = 0 until = 5 call clean_leave_calendar = + 1 loop end sub  '____________________________________________________________ ' ' author: joshua bryant ' ' version 1.0 ' ' date: 8/15/2016 ' ' sub appointment items in predefined ' outlook folder. once appointment item identified ' program perminately delete item avoid schedule ' conflicts new items added. deletion loop ' runs 10 times ensure items removed ' private, returns nothing '____________________________________________________________ '  private sub clean_leave_calendar()   ' initialize variables   dim oapp outlook.application   dim onamespace outlook.namespace   dim oapptitem outlook.appointmentitem   dim ofolder outlook.mapifolder   dim omeetingoapptitem outlook.meetingitem   dim oobject object   dim integer    ' set error states   on error resume next   ' check if outlook running   set oapp = getobject("outlook.application")   if err <> 0     'if outlook not running, start it.     set oapp = createobject("outlook.application")   end if    ' set folder appointments can found in. see main function "create outlook" more details.   set oapp = new outlook.application   set onamespace = oapp.getnamespace("mapi")   set ofolder = onamespace.getfolderfromid("000000007cf129e6c6baa74f9b2ab399fabb280e01006ec36ffc70429b4eae1875321a4609670078c4fa00320000")    ' set initial value of 0   = 0   ' repeat deleting function 10 times make sure apointments have been cleared folder.   until = 10     checkappointment = false     ' each of "objects" appointments , other in folder specified above repeat loop.     ' beacause not of objects appointments ends early,     ' why runs 10 times. (easier coding more stringent code, , not     ' resource demanding).     each oobject in ofolder.items         ' compare each object appoint class , delete objects match found.         if oobject.class = olappointment             set oapptitem = oobject             oapptitem.delete         end if     ' repeat each object / item.     next oobject   ' rinse , repeat.   = + 1   loop    ' clear variables   set oapp = nothing   set onamespace = nothing   set oapptitem = nothing   set ofolder = nothing   set oobject = nothing  end sub 

a subroutine clears shared calendar. main routine uploads new dates. lastly, subroutine closes workbook.

if has suggestions cleaning up, please let me know.

thanks!

also, here image of excel sheet using.


Comments