Automation error in global address list lookup - vba

I'm trying to look up a person's email address using the Outlook global address list. Here is the VBA code I use to do it.
'Snip
If firstName <> "" Then
Dim o, AddressList, AddressEntry
Dim AddressName, Address, Address2 As String
Set o = CreateObject("Outlook.Application")
Set AddressList = o.Session.AddressLists("Global Address List")
AddressName = firstName
For Each AddressEntry In AddressList.AddressEntries
If AddressEntry.Name = AddressName Then
Address = AddressEntry.GetExchangeUser.PrimarySmtpAddress
Exit For
End If
Next AddressEntry
End If
'Snip
The variable "firstName" is in the format Last name, first name. This seemingly only works half of the time I try to use it. For example if I put my own name in it work perfectly fine every time but if I put in my co-worker's name I get a little pop up bubble from Outlook saying "outlook is trying to retrieve data from the Microsoft exchange server *.com" and then I get an automation error. I couldn't find anything in common between the names that don't work and the same for those that do. Any help would be very much appreciated.
EDIT: Another note I just thought of is that when I hit debug on the error window it highlights the "Next AddressEntry" line.

Do not loop through all items in GAL - some GALs contain tens of thousand of entries, and you will nto be able to loop through them.
Call Application.Session.CreateRecipient (returns Recipient object), call Recipient.Resolve, then use Recipient.AddressEntry.GetExchangeUser.
UPDATE:
if the name is ambiguous, you will get back an error from Recipient.Resolve - Outlook Object Model does not let you recover from that - there is no way to get the list of matches and select the one you want. If using Redemption (I am its author) is an option, you can use is RDOAddressBook.ResolveNameEx method - it returns a list of matches (of one entry if the name is not ambiguous). You can also use RDIAddressList.ResolveName / ResolveNameEx if you want to resolve against a particular container only (e.g. GAL).
Set o = CreateObject("Outlook.Application")
...
set Session = CreateObject("Redemption.RDOSession")
Session.MAPIOBJECT = o.Session.MAPIOBJECT
set AdrrEntries = Session.AddressBook.ResolveNameEx("John")
MsgBox AdrrEntries.Count & " names were returned by ResolveNameEx:"
for each AE in AdrrEntries
MsgBox AE.Name
next

Related

How to Search Phone number in Address book?

There are options to get a contact detail from Mail id or Contact's Name using
Namespace.CreateRecipient / Recipient.Resolve
Is there any option to perform a direct search on Outlook Addressbook with Phone number or Company name etc.?
I am able to get many VBA coding options to loop through each contact in addressbook & find matching contact for phone number.
Please, try the next function. It should return the account name, searching by a phone number.
I played some minutes with my Outlook settings, because it used to not return any Address Book, even if it has a custom one from where it suggests the accounts address when start typing in the To box. If a similar problem in your case, I will try explaining what I did. But you maybe are luckier:
Function nameByPhoneNo(strPhNo As String) As String
Dim olApp As Outlook.Application, olNS As Outlook.NameSpace
Dim olGAL As Outlook.AddressList, olAdLs As Outlook.AddressLists
Dim olEntry As Outlook.AddressEntries, olMember As Outlook.AddressEntry
Set olApp = Outlook.Application
Set olNS = olApp.GetNamespace("MAPI")
Set olAdLs = olNS.AddressLists
Set olGAL = olAdLs.item(1) 'Your "Contacts" address book must be the first!
'the code can be adapted to search in all of them, if many...
If olGAL.AddressEntries.count < 1 Then
MsgBox "You must set ""Contacts"" folder as ""Outlook Address Book"", from its ""Properties""."
nameByPhoneNo = "No Address Book coould be found..."
Exit Function
End If
Set olEntry = olGAL.AddressEntries
For Each olMember In olEntry
If InStr(olMember.GetContact.BusinessTelephoneNumber, strPhNo) > 0 Or _
InStr(olMember.GetContact.HomeTelephoneNumber, strPhNo) > 0 Or _
InStr(olMember.GetContact.MobileTelephoneNumber, strPhNo) > 0 Then
nameByPhoneNo = olMember.GetContact.fullName: Exit Function
End If
Next
End Function
The function can be adapted to also search by "Company Name" etc.
It can be tested in this way:
Sub testNameByPhoneNo()
Debug.Print nameByPhoneNo("123252900") 'use it as string (between double quotes)
End Sub
Unlike message store providers, most address book providers do not support arbitrary searches (only because Outlook does not use them), so on the low level most of them support simple PR_ANR searches, which is what CreateRecipient / Resolve use AFAIK - it is essentially "here is a string, find the best match that makes sense to you".
Some address book providers (such as GAL) expose search templates (you can see its UI in the Outlook address book if you click "Advanced Search". That functionality is available either in Extended MAPI (C++ or Delphi only) or in Redemption (I am its author - any language - see RDOAddressListSearch object). Unfortunately, phone number is not one of the supported search fields for GAL - only fist/last names, department, company, city, etc. are.

Outlook custom script to flag messages with a value less than 40 in the subject field

I get thousands of e-mail alerts in my inbox daily, but many of them are actually trivial. I want to check whether the text of these alerts contains numbers below a certain threshold; if the numbers are lower than that threshold, alert me to the message and display a message box.
I'm using Outlook 2010 and have found several tutorials on writing Outlook macros in VB, including one about programmatically creating a rule to move messages to different folders.
But I don't want to check for keywords, I want to check if a number in the message (subject field) text is = to or less than a threshold value. For example, if the text of a message contains the following, id be alerted to it and a message box is displayed:-
The bit I need help with is there any way of writing a code that will only call the message box if the value in the e-mail subject field is below 45kohm?
I can do this in the rule but I’d have to include all values below i.e. 39.99, 39.98, 39.97 and that’s far too long!
You could use a VBA macro similar to the following:
Sub SubjectCheckerMessageRule(newMail As Outlook.mailItem)
' "script" routine to be called for incoming mail messages
' This subroutine has to be linked to this mail type using Outlook's rule assistant
Dim EntryID As String
Dim StoreID As Variant
Dim mi As Outlook.mailItem
Dim s As String
Dim x As Double
Const Prefix = "Resistance,"
Const Threshold = 40.0 ' or is it 45.0
' http://www.vboffice.net/en/developers/security-model-part-1/
' In 2003, not 2007 or later
' we have to access the new mail via an application reference
' to avoid security warnings
'
EntryID = newMail.EntryID
StoreID = newMail.Parent.StoreID
Set mi = Application.Session.GetItemFromID(EntryID, StoreID)
If InStr(mi.Subject, Prefix) = 1 Then
s = Mid(mi.Subject, Len(Prefix) + 1)
If IsNumeric(s) Then
x = CDbl(s)
If x <= Threshold Then
MsgBox x & " <= " & Threshold, vbInformation, "Attention!"
End If
End If
End If
End Sub
Use Outlook's Rule Assistant to define this macro as Script for the incoming mails of interest. Define keywords for the subject like "Resistance," to make sure that the macro is only called for the relevant mails. Add some error checking.

Outlook does not recognize one or more names

I have following vba code which reads a mailbox and sends reply to any users who send a invalid code as a reply to the mailbox, but sometimes the run time error (Outlook does not recognize one or more names) is received. My questions are,
Will creation of new MAPI profile resolve the issue or do i need to add a code that resolves the address and ignores if the email id no longer exist. if yes how do i do that?
Also in general whats the parameter to not send emails for specific condition?
Below is the code that we currently have:
Sub ResponseCodeError(Item As Outlook.MailItem)
'If not a valid code then send email to the User
If (Left(Item.Subject, 2) <> "S;" And Left(Item.Subject, 2) <> "N;") Then
Dim outobj, mailobj
Set outobj = CreateObject("Outlook.Application")
Set mailobj = outobj.CreateItem(0)
With mailobj
.To = Item.SenderEmailAddress
.Subject = "Invalid Code"
.Body = "Please use a valid CODE"
.Send
End With
'Move Email to Error Folder
mailboxNameString = "mailboxname"
FolderName = "Error"
Dim olApp As New Outlook.Application
Dim olNameSpace As Outlook.NameSpace
Dim olCurrExplorer As Outlook.Explorer
Dim olCurrSelection As Outlook.Selection
Dim olDestFolder As Outlook.MAPIFolder
Set olNameSpace = olApp.GetNamespace("MAPI")
Set olCurrExplorer = olApp.ActiveExplorer
Set olCurrSelection = olCurrExplorer.Selection
Set olDestFolder = olNameSpace.Folders(mailboxNameString).Folders(FolderName)
Item.Move olDestFolder
End If
Set outobj = Nothing
Set mailobj = Nothing
End Sub
I had once the same error, and I resolved it after 5 hours searching like crazy in the code. But it was much simpler: 1 email address had an error missing the .(dot) in the domain name.
Instead of setting the To property, call MailItem.Recipients.Add (returns Recipient object). Call Recipient.Resolve - it will return false if the name cannot be resolved.
The issue might be due to incorrect names, extra characters or spaces in some property of Item.(especially To, BCC, CC or collective property Recipients)
It might also be due to names not resolved yet before sending the mail. I am not sure but would assume that the error was due to trying to resolve names while sending the mail and probably being unable to resolve them due to some issue. Explicitly resolving names like the code below before the mail is sent should solve the issue.
Item.Recipient.ResolveAll can be used to resolve the names before sending the mail. It returns true if all names were successfully resolved.
Code: (Reference)
If Not myRecipients.ResolveAll Then
For Each myRecipient In myRecipients
If Not myRecipient.Resolved Then
MsgBox myRecipient.Name
End If
Next
End If
I have tested the code without adding and resolving recipients 1 by 1.(suggested by Dmitry)
I used Item.To, Item.BCC properties. Then used ResolveAll and send the mail only if all names are resolved.
I just ran into this error; code that had been working for years suddenly triggered the "Outlook does not recognize one or more names" error.
I discovered that the recipient was an Outlook shared folder name, ie. "My Shared Folder" and whether it is an Access 2016 or Outlook issue, the name could no longer resolve to its associated email address. Changing the recipient to "mysharedfolder#blahblah.com" resolved the issue for me.
SOLVED In my case in Outlook I had several contacts with the same e-mail (two companies that are run by one contact/e-mail) and that created the problem. I deleted one of the contacts so no e-mail is repeated in the contact list in Outlook and now it works. Note that my batch still sends an e-mail twice to that contact which info for each company which is what I wanted it.

Checkbox to SQL Database

I have a problem which I'm struggling to fix.
I have a form with many checkboxes containing email addresses, the result of which is sent to another page.
This page will send out newsletters.
This is working at the moment, but what I would like to do is include their name.
From the form received I get the results (xx#xx.com, yy#yy.com etc...)
I have managed to separate the results and put them into an array, but now I need to access the SQL db and find the names to the email address. This is where I'm struggling. Here is the code that I've tried to use:
name = request.form("list")
If name = "" Then
Response.redirect ("batchselect.asp")
End If
Dim your_name()
Dim mode
Dim mode_a
Dim i
mode=Request("list")
mode_a=split(mode,",")
For i=LBound(mode_a) to UBound(mode_a)
Next
i = i - 1
Redim PRESERVE your_name(i)
For t = 0 to i
Set conn = Server.CreateObject("ADODB.Connection")
conn.open connStr
strSQL = "SELECT name FROM emails WHERE emails = '" & mode_a(t) & "'"
Set rs = conn.Execute(strSQL)
your_name(t) = rs("name")
Next
If I try and run this I get this error:
Error Type:
ADODB.Field (0x800A0BCD)
Either BOF or EOF is True, or the current record has been deleted. Requested operation requires a current record.
I know the problem is in the SQL Query 'mode_a(t)', because if take out the for... next and change this to mode_a(0) or mode_a(1) it works no problem.
I'm using MS SQL and classic asp
Thanks in advance
Not sure why you are doing this:
For i=LBound(mode_a) to UBound(mode_a)
Next
i = i - 1
Surely this would be enough, and you get rid of any ambiguity in the value of i:
i = UBound(mode_a) - 1
If you are not dealing with too many email addresses I would consider trying to use an IN statement with sql and just bring back all the records for the emails. It would be so much quicker and save you a number of db calls.
If you did this then you could just return the email address with the name in the recordset row and use that to match up.
As for your actual question though I would check the value of i and make sure that it is not being set to -1 or some other value that doesn't actually point to an index. Because your error is happening because there are no results being returned. You should consider checking for EOF before you actually use the recordset.

Permanently Delete MailMessage in Outlook with VBA?

I am looking for a way to permanently delete a MailMessage from Outlook 2000 with VBA code. I'd like to do this without having to do a second loop to empty the Deleted items.
Essentially, I am looking for a code equivalent to the UI method of clicking a message and hitting SHIFT+DELETE.
Is there such a thing?
Try moving it first then deleting it (works on some patchs in 2000) or use RDO or CDO to do the job for you (you will have to install them)
Set objDeletedItem = objDeletedItem.Move(DeletedFolder)
objDeletedItem.Delete
CDO way
Set objCDOSession = CreateObject("MAPI.Session")
objCDOSession.Logon "", "", False, False
Set objMail = objCDOSession.GetMessage(objItem.EntryID, objItem.Parent.StoreID)
objMail.Delete
RDO
set objRDOSession = CreateObject("Redemption.RDOSession")
objRDOSession.MAPIOBJECT = objItem.Session.MAPIOBJECT
set objMail = objRDOSession.GetMessageFromID(objItem.EntryID>)
objMail.Delete
You could also mark the message first before you delete it and the loop through the deleted items folder and find it an dthe call delete a second time. Mark it using a Userproperty.
objMail.UserProperties.Add "Deleted", olText
objMail.Save
objMail.Delete
loop through you deleted items look for that userprop
Set objDeletedFolder = myNameSpace.GetDefaultFolder(olFolderDeletedItems)
For Each objItem In objDeletedFolder.Items
Set objProperty = objItem.UserProperties.Find("Deleted")
If TypeName(objProperty) <> "Nothing" Then
objItem.Delete
End If
Next
Simplest solution of all, similar to the first way:
FindID = deleteme.EntryID
deleteme.Delete
set deleteme = NameSpace.GetItemFromID(FindID)
deleteme.Delete
Do it twice and it'll be gone for good, and no performance killing loop. (NameSpace can be a particular namespace variable, if not in the default store.) Note this only works if you don't delete across stores, which can change the EntryID or remove it entirely.
I know this is an old thread, but since I recently had cause to write a macro that does this, I thought I'd share. I found that the Remove method appears to be a permanent deletion. I'm using this snippet:
While oFilteredItems.Count > 0
Debug.Print " " & oFilteredItems.GetFirst.Subject
oFilteredItems.Remove 1
Wend
I begin with a list of items that have been filtered by some criteria. Then, I just delete one at a time until it's gone.
HTH
You can use the following approach, basically you delete all of your email messages as you are currently doing, then call this one line to empty the deleted items folder. The code is in jscript, but I can translate if you really need me to :)
var app = GetObject("", "Outlook.Application"); //use new ActiveXObject if fails
app.ActiveExplorer().CommandBars("Menu Bar").Controls("Tools").Controls('Empty "Deleted Items" Folder').Execute();
Recently I had to permamentnly delete all contacts. This worked for me (Outlook 2016). You have obtain new reference to the item in the trash folder, otherwise it says "already deleted" or something like that. Just go from the end and the recently moved items will be there. Then calling Delete achieves permanent deletion. This snippet can be used in a loop.
myContacts(i).Move (trashFolder)
trashCount = trashFolder.Items.Count
For j = trashCount To 1 Step -1
Set trashItem = trashFolder.Items(j)
If trashItem.MessageClass = "IPM.Contact" Then
trashItem.Delete
Else
Exit For
End If
Next