VBA Late Binding for MAC - vba

I need help to make this vba code to work in mac (it's running perfect under windows but I have users that have only mac), the code extracts body data from selected emails in outlook and sends the info to a sheet.
I tried reading all the posts here about late binding and I got how it works, basically not referencing libraries that doesn't exist in mac office versions. I've changed the line that is causing trouble in my code "Dim objMail As Outlook.MailItem" for "Dim objMail As Object" it runs, but the macro goes directly to the msg box line without performing anything (I think ohh is running the code but I've tried debugging it but is not getting any variable or any information when I run it and I didn't get any error msg)
Sub DetailExtraction()
On Error GoTo ErrHandler
Application.ScreenUpdating = False
' SET Outlook APPLICATION OBJECT.
Dim objOutlook As Object
Set objOutlook = CreateObject("Outlook.Application") ' late binding
' CREATE AND SET A NameSpace OBJECT.
Dim objNSpace As Object
' THE GetNameSpace() METHOD WILL REPRESENT A SPECIFIED NAMESPACE.
Set objNSpace = objOutlook.GetNamespace("MAPI")
' CREATE A FOLDER OBJECT.
Dim myFolder As Object
Set myFolder = objNSpace.GetDefaultFolder(olFolderInbox)
Dim Item As Object
Dim iRows, iCols As Integer
iRows = 2
' LOOP THROUGH EACH ITEMS IN THE FOLDER.
'For Each objItem In myFolder.Items
' LOOP THROUGH EACH ITEMS IN THE SELECTION.
For Each objItem In ActiveExplorer.Selection
If objItem.Class = olMail Then
Dim objMail As Outlook.MailItem
Set objMail = objItem
Cells(iRows, 1) = objMail.SenderEmailAddress
Cells(iRows, 2) = objMail.To
Cells(iRows, 3) = objMail.Subject
Cells(iRows, 4) = objMail.ReceivedTime
Cells(iRows, 6) = objMail.Body
Cells(iRows, 6).WrapText = False
'MsgBox Prompt:=objMail.Body
End If
'WRAP UP FILE OFF
' Cells*i.WrapText = False
' SHOW OTHER PROPERTIES, IF YOU WISH.
'Cells(iRows, 6) = objMail.Body
'Cells(iRows, 5) = objMail.CC
'Cells(iRows, 6) = objMail.BCC
'Cells(iRows, 4) = objMail.Recipients(1)
iRows = iRows + 1
Next
Set objMail = Nothing
' RELEASE.
Set objOutlook = Nothing
Set objNSpace = Nothing
Set myFolder = Nothing
ErrHandler:
Debug.Print Err.Description
Application.ScreenUpdating = True
MsgBox "Environments Details Extracted from the Selected Emails (" & iRows - 2 & ")"
End Sub
Thanks in advance!

Related

Working with ".msg" Items in local folder

I'd like to get some attributes from emails stored in a local folder. I know how to do it for emails in Outlook.folder but I guess the methods are not the same in that case.
I can't find a way to work with the .msg items as if they were emails.
I haven't try anything since I understand the problem comes from object class incompatibility, but I don't know what to use. Also, I couldn't find a guide on ".msg" item, could be useful
Private Sub email_listing()
On Error GoTo ErrHandler
' SET Outlook APPLICATION OBJECT.
Dim objOutlook As Object
Set objOutlook = CreateObject("Outlook.Application")
' CREATE AND SET A NameSpace OBJECT.
Dim objNSpace As Object
' THE GetNameSpace() METHOD WILL REPRESENT A SPECIFIED NAMESPACE.
Set objNSpace = objOutlook.GetNamespace("MAPI")
' CREATE A FOLDER OBJECT.
Dim myFolder, fs As Object
Set fs = CreateObject("Scripting.FileSystemObject")
Set myFolder = fs.GetFolder("C:\Users\boris\Desktop\Mail Test\")
Dim Item As Object
Dim iRows, iCols As Integer
iRows = 2
' LOOP THROUGH EACH ITEM IN THE FOLDER.
For Each Item In myFolder.Files
If Item.Type = "Outlook Item" Then
Dim objMail As Outlook.MailItem
Set objMail = Item 'THE BUG
Cells(iRows, 1) = objMail.SenderEmailAddress
Cells(iRows, 2) = objMail.To
Cells(iRows, 3) = objMail.Subject
Cells(iRows, 4) = objMail.ReceivedTime
Cells(iRows, 5) = objMail.Body
End If
iRows = iRows + 1
Next
Set objMail = Nothing
' RELEASE.
Set objOutlook = Nothing
Set objNSpace = Nothing
Set myFolder = Nothing
ErrHandler:
Debug.Print Err.Description
End Sub
I expect to have the attributes for each mail in my spreadsheet.
So far the code stop at line 27
Use Namespace.OpenSharedItem to open standalone MSG files.

Error while trying to gather email statistics using VBA

I'm trying to write a VBA script to gather metrics on a shared mailbox throughout the day. Essentially, I'm wanting to export to Excel how many new, sent, and received messages where detected at different times throughout the day.
I'm working with the code below, however am getting an error when I try running the script. The error states:
"Run-time error '13'" Type mismatch"
Debugging highlights the error at Next olMail.
Does anyone have any ideas on what is causing this error, or if I need to be going at this from another direction? Also, I don't believe I have this setup correctly for my shared mailbox, as my default email is not shared. How do I need to modify Application.GetNamespace("MAPI").GetDefaultFolder(olFolderInbox) for the script to recognize I need it to read the shared box?
I'm using Outlook 2013.
Sub EmailStats()
Dim olMail As MailItem
Dim aOutput() As Variant
Dim lCnt As Long
Dim xlApp As Excel.Application
Dim xlSh As Excel.Worksheet
Dim flInbox As Folder
Set flInbox = Application.GetNamespace("MAPI").GetDefaultFolder(olFolderInbox)
ReDim aOutput(1 To flInbox.Items.Count, 1 To 4)
For Each olMail In flInbox.Items
If TypeName(olMail) = "MailItem" Then
lCnt = lCnt + 1
aOutput(lCnt, 1) = olMail.SenderEmailAddress
aOutput(lCnt, 2) = olMail.ReceivedTime
aOutput(lCnt, 3) = olMail.ConversationTopic
aOutput(lCnt, 4) = olMail.Subject
End If
Next olMail
Set xlApp = New Excel.Application
Set xlSh = xlApp.Workbooks.Add.Sheets(1)
xlSh.Range("A1").Resize(UBound(aOutput, 1), UBound(aOutput, 2)).Value = aOutput
xlApp.Visible = True
End Sub
I figure if I can get the above to work, I can piece together the rest in Excel, though if anyone knows a better way any advice is definitely appreciated.
Lastly, where would I start if I'd like to add the ability to the script to export this information for individual sub-folders and/or categories? Is this possible?
Any point in the right direction I would be very grateful for.
Using the answer given by #Dmitry Streblechenko on this link:Get reference to additional Inbox
I've included the ResolveDisplayNameToSMTP function by Sue Mosher to wrap around the SenderEmailAddress.
Sub EmailStats()
Dim olMail As MailItem
Dim aOutput() As Variant
Dim ns As Outlook.NameSpace
Dim vRecipient As Recipient
Dim lCnt As Long
' Dim xlApp As Excel.Application
' Dim xlSh As Excel.Worksheet
Dim flInbox As Folder
Set ns = Application.GetNamespace("MAPI")
Set vRecipient = ns.CreateRecipient("<top level folder of shared inbox>")
If vRecipient.Resolve Then
Set flInbox = ns.GetSharedDefaultFolder(vRecipient, olFolderInbox)
End If
ReDim aOutput(1 To flInbox.Items.Count, 1 To 4)
For Each olMail In flInbox.Items
If TypeName(olMail) = "MailItem" Then
lCnt = lCnt + 1
aOutput(lCnt, 1) = ResolveDisplayNameToSMTP(olMail.SenderEmailAddress, Outlook.Application)
aOutput(lCnt, 2) = olMail.ReceivedTime
aOutput(lCnt, 3) = olMail.ConversationTopic
aOutput(lCnt, 4) = olMail.Subject
End If
Next olMail
' Set xlApp = New Excel.Application
' Set xlSh = xlApp.Workbooks.Add.Sheets(1)
' xlSh.Range("A1").Resize(UBound(aOutput, 1), UBound(aOutput, 2)).Value = aOutput
' xlApp.Visible = True
End Sub
'----------------------------------------------------------------------------------
' Procedure : ResolveDisplayNameToSMTP
' Author : Sue Mosher - updated by D.Bartrup-Cook to work in Excel late binding.
'-----------------------------------------------------------------------------------
Public Function ResolveDisplayNameToSMTP(sFromName, OLApp As Object) As String
Select Case Val(OLApp.Version)
Case 11 'Outlook 2003
Dim oSess As Object
Dim oCon As Object
Dim sKey As String
Dim sRet As String
Set oCon = OLApp.CreateItem(2) 'olContactItem
Set oSess = OLApp.GetNamespace("MAPI")
oSess.Logon "", "", False, False
oCon.Email1Address = sFromName
sKey = "_" & Replace(Rnd * 100000 & Format(Now, "DDMMYYYYHmmss"), ".", "")
oCon.FullName = sKey
oCon.Save
sRet = Trim(Replace(Replace(Replace(oCon.Email1DisplayName, "(", ""), ")", ""), sKey, ""))
oCon.Delete
Set oCon = Nothing
Set oCon = oSess.GetDefaultFolder(3).Items.Find("[Subject]=" & sKey) '3 = 'olFolderDeletedItems
If Not oCon Is Nothing Then oCon.Delete
ResolveDisplayNameToSMTP = sRet
Case 14 'Outlook 2010
Dim oRecip As Object 'Outlook.Recipient
Dim oEU As Object 'Outlook.ExchangeUser
Dim oEDL As Object 'Outlook.ExchangeDistributionList
Set oRecip = OLApp.Session.CreateRecipient(sFromName)
oRecip.Resolve
If oRecip.Resolved Then
Select Case oRecip.AddressEntry.AddressEntryUserType
Case 0, 5 'olExchangeUserAddressEntry & olExchangeRemoteUserAddressEntry
Set oEU = oRecip.AddressEntry.GetExchangeUser
If Not (oEU Is Nothing) Then
ResolveDisplayNameToSMTP = oEU.PrimarySmtpAddress
End If
Case 10, 30 'olOutlookContactAddressEntry & 'olSmtpAddressEntry
ResolveDisplayNameToSMTP = oRecip.AddressEntry.Address
End Select
End If
Case Else
'Name not resolved so return sFromName.
ResolveDisplayNameToSMTP = sFromName
End Select
End Function

parse the body of an eml file in vba excel

My ultimate goal is to open an eml file in Excel vba and end up with the body of the message in a string that I can then use to search for different parameters. I've found a solution using MailItem and an Outlook application, however the machine I'm working on errors out when running this code:
Set MyOutlook = New Outlook.Application
Set x = MyOutlook.GetNamespace("MAPI")
Outlook 2013 opens, but then gives me an error message saying OLMAPI32.dll and then crashes. Eventually, I receive error 429 "ActiveX component can't create object."
I would like either a solution to this error or a workaround way to get the body of an eml file into a string. I've been successful at getting the subject of the email by using this code:
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objRegEx = CreateObject("VBScript.RegExp")
objRegEx.Pattern = "^Subject:"
Do Until objFile.AtEndOfStream
strSearchString = objFile.ReadLine
Set colMatches = objRegEx.Execute(strSearchString)
If colMatches.Count > 0 Then
Cells(i, n) = strSearchString
i = i + 1
Exit Do
End If
Loop
However, from examining a few random eml files, it doesn't appear like there is a way to flag the body of the text like I can with the subject.
Disregard the i and n, its not really relevant for this question. I'm just placing the subject in a cell determined elsewhere.
Any help is appreciated. Thanks!
Have you tried using the .Body function? This article may help.
Note that this code is performed inside of Outlook, not Excel.
Sub ExportToExcel(MyMail As MailItem) Dim strID As String, olNS As Outlook.Namespace Dim olMail As Outlook.MailItem Dim strFileName As String
'~~> Excel Variables
Dim oXLApp As Object, oXLwb As Object, oXLws As Object
Dim lRow As Long
strID = MyMail.EntryID
Set olNS = Application.GetNamespace("MAPI")
Set olMail = olNS.GetItemFromID(strID)
'~~> Establish an EXCEL application object
On Error Resume Next
Set oXLApp = GetObject(, "Excel.Application")
'~~> If not found then create new instance
If Err.Number <> 0 Then
Set oXLApp = CreateObject("Excel.Application")
End If
Err.Clear
On Error GoTo 0
'~~> Show Excel
oXLApp.Visible = True
'~~> Open the relevant file
Set oXLwb = oXLApp.Workbooks.Open("C:\Sample.xls")
'~~> Set the relevant output sheet. Change as applicable
Set oXLws = oXLwb.Sheets("Sheet1")
lRow = oXLws.Range("A" & oXLApp.Rows.Count).End(xlUp).Row + 1
'~~> Write to outlook
With oXLws
'
'~~> Code here to output data from email to Excel File
'~~> For example
'
.Range("A" & lRow).Value = olMail.Subject
.Range("B" & lRow).Value = olMail.SenderName
.Range("C" & lRow).Value = olMail.Body
'.Range("C" & lRow).Value = olMail.HTMLBody
'
End With
'~~> Close and Clean up Excel
oXLwb.Close (True)
oXLApp.Quit
Set oXLws = Nothing
Set oXLwb = Nothing
Set oXLApp = Nothing
Set olMail = Nothing
Set olNS = Nothing
End Sub

how to pull received time from all emails in outlook mailbox

I have most of this worked out already, but need assistance. I want to store all of the received times of the emails from various outlook folders. All of the folders are inside the same folder so I have an array to go through each of these. I need the times stored into a variable that I can then display in or write.console. There will be hundreds of times to display. The variable is Totalmsg that I want these times stored in, then displayed once complete.
Sub EmailArrivalTimes()
Dim objOutlook As Object, objnSpace As Object, objFolder As MAPIFolder
Dim MailItem
Dim EmailCount() As Integer, arrNames
Set objOutlook = CreateObject("Outlook.Application")
Set objnSpace = objOutlook.GetNamespace("MAPI")
arrNames = Array ("Andrew", "Ashton", "Becca", "Beth", "Bree", "Brittany", "Cecilia", "Chance", "Christina J.", "Christine", "Dustin", "James", "Jeff", "Jenni", "Jennifer W.", "Josh", "Josie", "Kara", "Lisa", "Megan", "Misti", "Nathan", "Paul", "Sam", "Shane", "Shawna") 'add other names here...
ReDim EmailCount(LBound(arrNames) To UBound(arrNames))
For x = LBound(arrNames) To UBound(arrNames)
On Error Resume Next
Set objFolder = objnSpace.Folders("Mailbox - IT Support Center"). _
Folders("Onshore - " & arrNames(x)).Folders("completed")
On Error GoTo 0
ArrivalTime = 0
Dim Totalmsg
If Not objFolder Is Nothing Then
For Each MailItem In objFolder.Items
Totalmsg = MailItem.ReceivedTime
Next
End If
Set OutMail = Nothing
Set OutApp = Nothing
Set objFolder = Nothing
Set objnSpace = Nothing
Set objOutlook = Nothing
End Sub
Right now you are overwriting the value of TotalMsg at each iteration in this loop:
If Not objFolder Is Nothing Then
For Each MailItem In objFolder.Items
Totalmsg = MailItem.ReceivedTime
Next
End If
You will want to append to it, instead:
If Not objFolder Is Nothing Then
For Each MailItem In objFolder.Items
Totalmsg = TotalMsg & vbCRLF & MailItem.ReceivedTime
Next
End If
Debug.Print TotalMsg
'Note: this will likely exceed what can fit in the console window, _
' but you can instead write the string to a text file/etc.

Preserving html format in creating tasks from email

I have a little script that converts an email into a Task in my outlook.
My main frustration is that it won't preserve the html format, and deals with embedded images as attachments. I was wondering if anyone could help. I know it is possible as I've copied the body of an email directly across to the body of a task manually and it is preserved fine.
Sub ConvertSelectedMailtoTask()
Dim objApp As Outlook.Application
Dim objTask As Outlook.TaskItem
Dim objMail As Outlook.MailItem
Set objTask = Application.CreateItem(olTaskItem)
Set objApp = Application
If TypeName(objApp.ActiveWindow) = "Explorer" Then
For Each objMail In Application.ActiveExplorer.Selection
If Left(objMail.Subject, 3) = "RE:" Or Left(objMail.Subject, 3) = "FW:" Then
subj = Right(objMail.Subject, Len(objMail.Subject) - 4)
Else
subj = objMail.Subject
End If
With objTask
.Subject = subj
.Importance = objMail.Importance
.StartDate = objMail.ReceivedTime
.Body = objMail.Body
.DueDate = Date + 3
If objMail.Attachments.Count > 0 Then
CopyAttachments objMail, objTask
End If
.ReminderSet = True
.ReminderTime = Date + 2.5
.Sensitivity = olPrivate
.Save
End With
Next
ElseIf TypeName(objApp.ActiveWindow) = "Inspector" Then
Set objMail = objApp.ActiveInspector.CurrentItem
If Left(objMail.Subject, 3) = "RE:" Or Left(objMail.Subject, 3) = "FW:" Then
subj = Right(objMail.Subject, Len(objMail.Subject) - 4)
Else
subj = objMail.Subject
End If
With objTask
.Subject = subj
.Importance = objMail.Importance
.StartDate = objMail.ReceivedTime
.Body = objMail.Body
.DueDate = Date + 3
If objMail.Attachments.Count > 0 Then
CopyAttachments objMail, objTask
End If
.ReminderSet = True
.ReminderTime = Date + 2.5
.Sensitivity = olPrivate
.Save
End With
End If
Set objTask = Nothing
Set objMail = Nothing
Set objApp = Nothing
End Sub
And here is the script for the attachments
Sub CopyAttachments(objSourceItem, objTargetItem)
Set fso = CreateObject("Scripting.FileSystemObject")
Set fldTemp = fso.GetSpecialFolder(2) ' TemporaryFolder
strPath = fldTemp.Path & "\"
For Each objAtt In objSourceItem.Attachments
strFile = strPath & objAtt.FileName
objAtt.SaveAsFile strFile
objTargetItem.Attachments.Add strFile, , , objAtt.DisplayName
fso.DeleteFile strFile
Next
Set fldTemp = Nothing
Set fso = Nothing
End Sub
Update:
I found a bit of code that uses a word document to preserve the formatting:
Sub CopyFullBody(sourceItem As Object, targetItem As Object)
Dim objDoc As Word.Document
Dim objSel As Word.Selection
Dim objDoc2 As Word.Document
Dim objSel2 As Word.Selection
On Error Resume Next
' get a Word.Selection from the source item
Set objDoc = sourceItem.GetInspector.WordEditor
If Not objDoc Is Nothing Then
Set objSel = objDoc.Windows(1).Selection
objSel.WholeStory
objSel.Copy
Set objDoc2 = targetItem.GetInspector.WordEditor
If Not objDoc2 Is Nothing Then
Set objSel2 = objDoc2.Windows(1).Selection
objSel2.PasteAndFormat wdPasteDefault
Else
MsgBox "Could not get Word.Document for " & _
targetItem.Subject
End If
Else
MsgBox "Could not get Word.Document for " & _
sourceItem.Subject
End If
Set objDoc = Nothing
Set objSel = Nothing
Set objDoc2 = Nothing
Set objSel2 = Nothing
End Sub
This doesn't seem like it would be the only solution hence updating my own post instead of answering my question as this seems a bit long winded (using another application just to give me formatting, when I can copy and paste text manually just fine all in Outlook). If anyone has any other thoughts on this/defining attachment types please carry on answering!
in the line
.Body = objMail.Body
you only ask fot the non-formatted Body. Try instead:
.Body = objMail.htmlBody
and something completely different: I just put reminders onto the emails themselves, so I have no need to create extra Tasks at all...
Keep in mind that Outlook tasks, appointments and tasks work with RTF, not HTML. hence TaskItem, ContactItem and AppointmentItem objects only expose the RtfBody property, but not HTMLBody (like MailItem does).
You will need to either convert HTML to RTF (you can try the Word Object Model for that) or use Redemption (I am its author): unlike Outlook Object Model, it exposes the RDOTaskItem.HTMLBody property and dynamically converts HTML to the native (for tasks) RTF when that property is set.