Vba vba runtime error -1802485755(94904005) [duplicate] - excel

This question already has answers here:
MailItem.GetInspector.WordEditor in Office 2016 generates Application-defined or object defined error
(4 answers)
Closed 3 months ago.
i have a strange problem, vba return me the error vba runtime error -1802485755(94904005) and i searched on internet and i found nothing, so i am tring to ask here if someone can help me
here is the code
Private Sub CommandButton3_Click()
Dim str As New Classe1
Dim ricerca As String
Dim dmi As outlook.MailItem
Dim UTCdate As Date, UTCdate2 As Date
Dim out As outlook.Application
Dim DATA1 As Date
Dim DATA2 As Date
Dim errorN As Long
On Error GoTo FormatoErrato:
DATA1 = DateAdd("h", 1, Res.DataStart.Value)
DATA2 = DateAdd("h", 23, Res.DataEnd.Value)
On Error GoTo 0
Set out = New outlook.Application
Set dmi = out.CreateItem(olMailItem)
UTCdate = dmi.PropertyAccessor.LocalTimeToUTC(DATA1)
UTCdate2 = dmi.PropertyAccessor.LocalTimeToUTC(DATA2)
ricerca = "#SQL=""urn:schemas:httpmail:subject"" LIKE '%sometext%'" & _
" AND ""urn:schemas:httpmail:datereceived"" <= '" & UTCdate2 & "'" & _
" AND ""urn:schemas:httpmail:datereceived"" >= '" & UTCdate & "'"
str.prova (ricerca)
FormatoErrato:
errorN = Err.Number
If errorN = 13 Then
MsgBox "invalid format", vbCritical
End If
End Sub
this code (in a class module) is on a userform button where you set two dates and then the following code search the emails that strike the requirments
Sub prova(val As String)
Res.Mezzi.Clear
Dim fol As outlook.Folder
Dim arr, arr2
Dim ricerca As String, txt As String
Dim n As Long, s As Long, tot As Long, l As Long
Dim mi As outlook.MailItem
Dim i As Object
Dim doc As Word.Document
Set fol = 'outlook folder path'
s = 0
n = 1
ReDim Preserve arr2(0 To s)
For Each i In fol.Items.Restrict(val)
If i.Class = olMail Then
Set mi = i
Set doc = mi.GetInspector.WordEditor
If doc.Tables.Count > 0 Then
For tot = 1 To doc.Tables.Count
arr2(s) = Application.WorksheetFunction.Clean(doc.Tables(tot).Cell(2, 2).Range.Text)
s = s + 1
ReDim Preserve arr2(0 To s)
Next tot
End If
End If
Next i
For s = 0 To UBound(arr2)
If IsEmpty(arr2(s)) = False And arr2(s) <> "" Then
Res.Mezzi.AddItem arr2(s)
End If
Next s
End Sub
the email that i'm looking for has a table, one or more in it so i used getinspector.wordeditor to check if the table exist and then take the data that i need from it.
the sub works fine if the difference between the dates is just few days if i put a week give that error
coudl you help me to solve the problem or work around it?
thanks in advance

I didn't find any information which Office version is installed on the system. So, if you have a pretty old version of MS Office installed the following case makes sense - the WordEditor property is only valid if the IsWordMail method returns True and the EditorType property is olEditorWord.
The most-likely possible reason for such errors at runtime is security settings when dealing with the Outlook object model. The message body is a protected property in the Outlook object model which can generate errors when Outlook is automated from an external application. You can find the list of protected properties described on the Protected Properties and Methods page.
So, the Object Model Guard warns users and prompts users for confirmation when untrusted applications attempt to use the object model to obtain email address information, store data outside of Outlook, execute certain actions, and send email messages. If, for any reason, the warning is not appropriate or can't be displayed, the Outlook object model may generate errors when accessing protected properties.
In your scenario you can:
Use a low-level API which doesn't trigger security issues in the Outlook object model - Extended MAPI or any other third-party wrapper around that API.
Create a COM add-in which has access to the trusted Application object and which doesn't trigger security issues.
Install any AV with the latest updates.
Use group policy settings to setup security settings to not trigger security issues.

after many trials i think i solved
to avoid to raise the error i should close the inspector.
in this way:
If i.Class = olMail Then
Set mi = i
Set insp = mi.GetInspector
Set doc = insp.WordEditor
If doc.Tables.Count > 0 Then
For tot = 1 To doc.Tables.Count
arr2(s) = Application.WorksheetFunction.Clean(doc.Tables(tot).Cell(2, 2).Range.Text)
s = s + 1
ReDim Preserve arr2(0 To s)
Next tot
End If
End If
insp.Close olSave
now all seems to work fine even with range of 10 days of emails

Related

Automating Text Extraction from Outlook to Excel

I'm a little out of my depth here, and definitely fumbling my way through trying to do this.
Scenario:
Emails arrive in a shared inbox every day for every new hire into the org. This is the full body of one of those emails:
The following are the new user details:
Full Name: Martha Washington
Employee ID: 123456
Department: Nursing Education and Research
Division: 17
RC: 730216
Job Title: Clin Nurse PRN Dept
Location: Medical Office Bldg West
Username: 12345678
I need to make/modify a script that will take only 3 lines out of this email body, and put them into columns in Excel. I need to get the Username value, the Job Title value, and the Location values and put them into separate columns. Then, the next email that arrives needs the same data extracted and put in a new row in Excel.
I want the Excel file to look something like this:
Username
JobTitle
Location
gwashing
President
Michigan
mwashing
Wife
New York
Any and all help is appreciated!
The Outlook object model provides the NewMailEx event of the Application class which is fired when a new message arrives in the Inbox and before client rule processing occurs. Use the Entry ID represented by the EntryIDCollection string to call the NameSpace.GetItemFromID method and process the item. This event fires once for every received item that is processed by Microsoft Outlook. The item can be one of several different item types, for example, MailItem, MeetingItem, or SharingItem. So, in the NewMailEx event you can get an instance of the incoming email where you could extract all the required information from the message body.
The Outlook object model provides three main ways for working with item bodies:
Body.
HTMLBody.
The Word editor. The WordEditor property of the Inspector class returns an instance of the Word Document which represents the message body.
See Chapter 17: Working with Item Bodies for more information.
I have something similar in my outlook application.
So this is Outlook VBA:
Sub Provtagning(msg As Outlook.MailItem)
Dim RE As Object
Dim objFolder As Outlook.MAPIFolder
Dim xExcelFile As String
Dim xExcelApp As Excel.Application
Dim wb As Excel.Workbook
xExcelFile = "Path to file"
' wait for file to be closed (if multiple mails arrive at the same time)
While IsWorkBookOpen(xExcelFile)
WasteTime (1)
Wend
DoEvents
Set xExcelApp = CreateObject("Excel.Application")
Set wb = xExcelApp.Workbooks.Open(xExcelFile)
Set RE = CreateObject("vbscript.regexp")
lrow = wb.Sheets("Sheet1").Cells(wb.Sheets("Sheet1").rows.Count, "A").End(xlUp).Row + 1
RE.Pattern = "Username:\s(\d+)"
Set allMatches = RE.Execute(msg.Body)
username = allMatches.Item(0).SubMatches.Item(0)
RE.Pattern = "Job Title:\s([a-zA-Z ]+)"
Set allMatches = RE.Execute(msg.Body)
title = allMatches.Item(0).SubMatches.Item(0)
RE.Pattern = "Location:\s([a-zA-Z ]+)"
Set allMatches = RE.Execute(msg.Body)
location = allMatches.Item(0).SubMatches.Item(0)
wb.Sheets("Sheet1").Range("A" & lrow).Value = username
wb.Sheets("Sheet1").Range("B" & lrow).Value = title
wb.Sheets("Sheet1").Range("C" & lrow).Value = location
wb.Save
wb.Close
End Sub
Sub WasteTime(Finish As Long)
Dim NowTick As Long
Dim EndTick As Long
EndTick = GetTickCount + (Finish * 1000)
Do
NowTick = GetTickCount
DoEvents
Loop Until NowTick >= EndTick
End Sub
Function IsWorkBookOpen(FileName As String)
Dim ff As Long, ErrNo As Long
On Error Resume Next
ff = FreeFile()
Open FileName For Input Lock Read As #ff
Close ff
ErrNo = Err
On Error GoTo 0
Select Case ErrNo
Case 0: IsWorkBookOpen = False
Case 70: IsWorkBookOpen = True
Case Else: Error ErrNo
End Select
End Function
You may need to adjust the regex patterns if there is something that is different.
Then just create a rule in Outlook to run this script on every email that is from SomeEmail or whatever that is the trigger.

To check if you have replied to client email via vba

Greetings for the day!
I have written a small VBA code to check if my team has responded to the client's email or not. on daily basis we get approx 500+ emails from the client, to track the same I have written the below code to check what all emails are being looked upon.
Dim O As Outlook.Application
Dim R As Long
Sub project2()
Set O = New Outlook.Application
Dim Omail As Outlook.MailItem
Set Omail = O.CreateItem(olMailItem)
Dim ONS As Outlook.Namespace
Set ONS = O.GetNamespace("MAPI")
Dim FOL As Outlook.Folder
Set FOL = ONS.GetDefaultFolder(olFolderInbox).Folders("MD-GPS")
R = 2
For Each Omail In FOL.Items
Cells(R, 1) = Omail.Subject
Cells(R, 2) = Omail.SenderEmailAddress
Call REPLY_STATUS(Omail.Subject, Omail.SenderEmailAddress)
R = R + 1
On Error Resume Next
Next Omail
End Sub
Sub REPLY_STATUS(MailSubject As String, MailSender As String)
Dim SentEmail As Outlook.MailItem
Set SentEmail = O.CreateItem(olMailItem)
Dim ONS2 As Outlook.Namespace
Set ONS2 = O.GetNamespace("MAPI")
Dim FOL2 As Outlook.Folder
Set FOL2 = ONS2.GetDefaultFolder(olFolderSentMail)
Dim check As String
check = "RE: " & MailSubject
For Each SentEmail In FOL2.Items
If check = SentEmail.Subject And MailSender = SentEmail.Recipients(1).Address Then
Cells(R, 3) = "Yes"
Exit For
Else
End If
On Error Resume Next
Next SentEmail
End Sub
But the ending is not that great as it looks, the code is working but
in most cases, the code captures something else rather than capturing the sender's email address in an excel sheet.
As we daily receive 500+ emails, the code becomes too slow as it checks the entire folder from the scratch, is there a possibility I can add a start date that I can mention in the excel sheet and the code will start from that date only.
Not sure why it is also not filling column 3 i.e. if replied however my team has actually replied to those emails.
it is not picking up the latest emails from the defined sub-folder ("MD-GPS"), why is that happening?
Any help on this would be greatly appreciated.
Note: To handle stmp exchange account error, I tried using the following MailItem.Sender.GetExchangeUser.PrimarySmtpAddress but the only drawback is if I change the sub-folder to something else, it doesn't work.
Firstly, you do not need to create SentEmail - get rid of the
Set SentEmail = O.CreateItem(olMailItem)
line.
Secondly, never loop through all items in a folder - use Items.Find/FindNext or Items.Restrict.
Thirdly, you are seeing an EX type address (as opposed to SMTP). Check MailItem.Sender.Type property - if it is "SMTP", use MailItem.Sender.Address. Otherwise (in case of "EX") use MailItem.Sender.GetExchangeUser().PrimarySmtpAddress.
That being said, you can check if anybody replied to the original message at all - check if PR_LAST_VERB_EXECUTED MAPI property (DASL name http://schemas.microsoft.com/mapi/proptag/0x10810003) is present - 103 is EXCHIVERB_REPLYTOALLand 102 is EXCHIVERB_REPLYTOSENDER. If the property is not set at all, there is no reason to search.
To search for a matching subject, use a query like
"[Subject] = ' & MailSubject & "'"
Note that Outlook Object Model will not let you search on the message recipients or attachments. If using Redemption (I am its author) is an option, you can use something like the following. You can specify Recipients as one of the search fields, and Redemption will create a restriction on recipient name / address / SMTP address
set session = CreateObject("Redemption.RDOSession")
session.MAPIOBJECT = O.Session.MAPIOBJECT
set SentEmail = FOL2.Items.Find("""http://schemas.microsoft.com/mapi/proptag/0x0E1D001F"" = '" & MailSubject & "' AND Recipients = '" & MailSender & "'")
Note that most MAPI stores won't search on PR_SUBJECT, only on PR_NORMALIZED_SUBJECT (which is the subject without the RE: or FW: prefix) - which is what the snippet above is using.

Convert Outlook Contact Group early binding Excel VBA to late binding

I am trying to insert a list of email addresses from Excel into a contact group in Outlook.
I found Excel VBA code online. It uses early binding. It is not an option to force the user to go into Tools-> References -> Outlook, when they open the file.
I need to transform the code from early to late binding.
Questions:
I understand that I need to change Outlook.Application to
CreateObject('Outlook.Application') and that I can access
olFolderContacts with the number 10 instead. See code below.
I can't figure out how to access the remaining items such as
CreateItem(olDistributionListItem).
Sub CreateContactGroupfromExcel()
Dim objContactsFolder As Outlook.Folder
Dim objContact As Outlook.ContactItem
Dim objContactGroup As Outlook.DistListItem
Dim objNameCell As Excel.Range
Dim objEmailCell As Excel.Range
Dim strName As String
Dim strEmail As String
Dim objTempMail As Outlook.MailItem
Dim objRecipients As Outlook.Recipients
Set objContactsFolder = Outlook.Application.Session.GetDefaultFolder(olFolderContacts)
Set objContactGroup = Outlook.Application.CreateItem(olDistributionListItem)
'You can change the contact group name
objContactGroup.DLName = "PlaceHolder_VBA"
i = 0
Do While Range("vba_email_outlook").Offset(i, 0).Value <> "":
strName = Range("vba_name_outlook").Offset(i, 0).Value
strEmail = Range("vba_email_outlook").Offset(i, 0).Value
Set objContact = objContactsFolder.Items.Find("[FullName] = '" & strName & "'")
'If there is no such a contact, create it.
If objContact Is Nothing Then
Set objContact = Outlook.Application.CreateItem(olContactItem)
With objContact
.FullName = strName
.Email1Address = strEmail
.Save
End With
End If
'Add the contacts to the new contact group
Set objTempMail = Outlook.CreateItem(olMailItem)
objTempMail.Recipients.Add (strName)
Set objRecipients = objTempMail.Recipients
objContactGroup.AddMembers objRecipients
i = i + 1
Loop
'Use "objContactGroup.Save" to straightly save it
objContactGroup.Display
objTempMail.Close olDiscard
End Sub
Declare object variables as generic Object
Dim objContactsFolder As Object
Determine number values of constants. With early binding, these values can be seen when hovering over constant or in VBA immediate window: ?olMailItem. Then reference number in place of constant or leave constants referenced as they are and declare them as constants with Const statements. Const olMailItem = 0
olFolderContacts = 10
olMailItem = 0
olDistributionListItem = 7
I am not an expert but this code allows you to add the reference when you run the VBA script, but it will mean that if it errors out the code quits running you will not be able to debug.
On Error Resume Next ''' If reference already exist this would cause an error
Application.VBE.ActiveVBProject.References.AddFromFile ("C:\Program Files (x86)\Microsoft Office\Office16\MSOUTL.OLB") ''' Might have to change file path
On Error GoTo 0

Secure PDF's generated with Microsoft Access OutputTo

I have an application in Microsoft Access 2007 which generates PDF files via OutputTo ... acFormatPDF. It works fine, but now, someone has manipulated a generated PDF and I now will add a protection for the PDF's to my program code. How can I do that because the OutputTo seems to have no options for doing that? The only protection I need is for changing the document. All other protections (copy, print, ...) have no relevance.
I found a method for applying protection to PDFs using AcroJS and the list of instantiateable COM classes found here. I use "CreateObject" to perform late binding of the Acrobat objects, but if you have Acrobat installed, you can add a reference in your project by going into the VBA IDE and clicking Tools ---> References... and checking the box next to "Adobe Acrobat x.x Type Library" (where x.x is your version of Acrobat). If you don't see that available, look for "acrobat.tlb" in Program Files and add it via the Browse...
Public Sub ProtectPDF(strFilePath As String, strPolicyName As String)
On Error GoTo ErrHandler
Dim oPDDoc As Object
Dim oJso As Object
Dim oSec As Object
Dim arrPolicies As Variant
Dim PolicyIndex As Integer
Dim i As Integer
Dim success As Boolean
Const PDSaveFull = 1
Set oPDDoc = CreateObject("AcroExch.PDDoc")
If oPDDoc.Open(strFilePath) Then
Set jso = oPDDoc.GetJSObject
Set sec = jso.security
apols = sec.getSecurityPolicies()
PolicyIndex = -1
For i = 0 To UBound(arrPolicies)
If arrPolicies(i).Name = strPolicyName Then
PolicyIndex = i
End If
Next
If Not PolicyIndex = -1 Then
jso.encryptUsingPolicy (arrPolicies(PolicyIndex))
Else
Err.Raise vbObjectError + 1, "ProtectPDF", "Could not find Policy named: """ & strPolicyName & """"
End If
success = oPDDoc.Save(PDSaveFull, strFilePath)
oPDDoc.Close
Else
Err.Raise vbObjectError + 2, "ProtectPDF", "Failed to open " & strFilePath
End If
Exit Sub
ErrHandler:
'Handle any Adobe errors here...
End Sub

Copy email to the clipboard with Outlook VBA

How do I copy an email to the clipboard and then paste it into excel with the tables intact?
I am using Outlook 2007 and I want to do the equivalent of
"Click on email > Select All > Copy > Switch to Excel > Select Cell > Paste".
I have the Excel Object Model pretty well figured out, but have no experience in Outlook other than the following code.
Dim mapi As NameSpace
Dim msg As Outlook.MailItem
Set mapi = Outlook.Application.GetNamespace("MAPI")
Set msg = mapi.Folders.Item(1).Folders.Item("Posteingang").Folders.Item(1).Folders.Item(7).Items.Item(526)
I must admit I use this in Outlook 2003, but please see if it works in 2007 as well:
you can use the MSForms.DataObject to exchange data with the clipboard. In Outlook VBA, create a reference to "Microsoft Forms 2.0 Object Library", and try this code (you can of course attach the Sub() to a button, etc.):
Sub Test()
Dim M As MailItem, Buf As MSForms.DataObject
Set M = ActiveExplorer().Selection.Item(1)
Set Buf = New MSForms.DataObject
Buf.SetText M.HTMLBody
Buf.PutInClipboard
End Sub
After that, switch to Excel and press Ctrl-V - there we go!
If you also want to find the currently running Excel Application and automate even this, let me know.
There's always a valid HTMLBody, even when the mail was sent in Plain Text or RTF, and Excel will display all text attributes conveyed within HTMLBody incl. columns, colors, fonts, hyperlinks, indents etc. However, embedded images are not copied.
This code demonstrates the essentials, but doesn't check if really a MailItem is selected. This would require more coding, if you want to make it work for calendar entries, contacts, etc. as well.
It's enough if you have selected the mail in the list view, you don't even need to open it.
I finally picked it up again and completely automated it. Here are the basics of what I did to automate it.
Dim appExcel As Excel.Application
Dim Buf As MSForms.DataObject
Dim Shape As Excel.Shape
Dim mitm As MailItem
Dim itm As Object
Dim rws As Excel.Worksheet
'code to open excel
Set appExcel = VBA.GetObject(, "Excel.Application")
'...
'code to loop through emails here
Set mitm = itm
body = Replace(mitm.HTMLBody, "http://example.com/images/logo.jpg", "")
Call Buf.SetText(body)
Call Buf.PutInClipboard
Call rws.Cells(i, 1).PasteSpecial
For Each Shape In rws.Shapes
Shape.Delete 'this deletes the empty shapes
Next Shape
'next itm
I removed the logo urls to save time, and when you're dealing with 300 emails, that translates into at least ten minutes saved.
I got the code I needed from a TechRepublic article, and then changed it to suit my needs. Many thanks to the accepted answerer of this question for the clipboard code.
Ok so I will have to make certain assumptions because there is information missing from your question.
Firstly you didn't say what mailformat the message is... HTML would be the easiest, the process will be different for RTF and not possible in plaintext
Since you are refering to tables I will assume they are HTML tables and the mail format is HTML.
Also it is not clear from your question if you want the table content pasted seperately (1 excel cell per table cell) and the rest of the emails bodytext pasted into 1 cell or several?
finally you haven't really said if you want the VBA running from Outlook or Excel (not that important but it affects which intrinsic objects are available.
Anyway code sample:
Outlook code to access the htmlbody prop
Dim mapi As Namespace
Set mapi = Application.Session
Dim msg As MailItem
Set msg = mapi.Folders.Item(1).Folders.Item("Posteingang").Folders.Item(1).Folders.Item(7).Items.Item(526)
Dim strHTML as String
strHTML = msg.HTMLBody
' There is no object model collection for html tables within the htmlbody (which is a string of html) you will need to parse the html and collect the tables before inserting into Excel.
After a while again, I found another way. MailItem.Body is plain text, and has a tab character between table cells. So I used that. Here is the gist of what I did:
Sub Import()
Dim itms As Outlook.Items
Dim itm As Object
Dim i As Long, j As Long
Dim body As String
Dim mitm As Outlook.MailItem
For Each itm In itms
Set mitm = itm
ParseReports (mitm.body) 'uses the global var k
Next itm
End Sub
Sub ParseReports(text As String)
Dim table(1 To 1000, 1 To 11) As String 'I'm not expecting to see a thousand rows!
Dim drow(1 To 11) As String
For Each Row In VBA.Split(text, vbCrLf)
j = 1
For Each Col In VBA.Split(Row, vbTab)
table(i, j) = Col
j = j + 1
Next Col
i = i + 1
Next Row
For i = 1 To l
For j = 1 To 11
drow(j) = table(i, j)
Next j
hws.Range(hws.Cells(k, 1), hws.Cells(k, 11)) = drow
k = k + 1
Next i
End Sub
Average: 77 emails processed per second. I do some minor processing and extracting.

Resources