VBA Outlook script error: an object could not be found - vba

I am trying to use a VBA script to pull info from the emails in Inbox into an excel spreadsheet:
'Subject
'To Address
'From Address
'CC Addresses
it fails for senders who have already left the organization and they're no longer in O365.
This is the code bit:
Function X400toSMTP(strAdr As String) As String
Dim olkRcp As Outlook.Recipient, olkUsr As Outlook.ExchangeUser
Set olkRcp = Session.CreateRecipient(strAdr)
If olkRcp.AddressEntry = Empty Then
X400toSMTP = strAdr
ElseIf olkRcp.AddressEntry.AddressEntryUserType = olExchangeUserAddressEntry Then
olkRcp.Resolve
Set olkUsr = olkRcp.AddressEntry.GetExchangeUser
X400toSMTP = olkUsr.PrimarySmtpAddress
End If
Set olkRcp = Nothing
Set olkUsr = Nothing
End Function
I ran the debug and it stops at AddressEntry : The attempted operation failed. An object could not be found
I'm trying to find a way to make the script leave the address field empty for those senders who cannot be found on O365 anymore and further process the rest of the items in the Inbox.
I have tried the below:
If IsNull(olkRcp.AddressEntry) Then
X400toSMTP = strAdr
but am still getting the same error for AddressEntry.
I am just a VBA noob so would very much appreciate your advice.
Many thanks!

Make sure the recipient is resolved before accessing the AddressEntry property - call olkRcp.Resolve.

Related

Digital sign of Email - VBA

I have received a macro which was written by someone else and I need to repair it. It should digital sign e-mail. I have identified that this function causes an error:
Private Function AddControll(piIcon As Integer) As Boolean
Dim oContr As Object
Dim oCBs As Object
Set oContr = gmyMail.GetInspector.CommandBars.FindControl(, piIcon)
If oContr Is Nothing Then
Set oCBs = gmyMail.GetInspector.CommandBars
Set oContr = oCBs.Item("Standard").Controls.Add(, piIcon, , , True)
End If
End Function
gmyMail is type Outlook.MailItem and when should be e-mail signed digitally then this function is called with piIcon=719
I cannot find out what is wrong. Somewhere I have read that this codes for CommandBars changed since Outlook 2010 but I cannot find actual codes and also I am not sure what exactly this CommandBars should do... Does it assign an icon into the e-mail?

How can I program Outlook to send an email in advance and send another if a reply isn't sent?

I'd like to program Outlook to send an email in advance, and, if no reply is sent to the target email by x date, send another email.
I've attempted experimentation, dabbling into Excel VBAs, but haven't found a solution.
I'm really quite unsure of how to do this, though I do have programming experience.
I'd like to program Outlook to send an email in advance
That is a very straightforward task. A lot of samples are available over the internet, for example, sample code in VB.NET:
Private Sub CreateSendItem(OutlookApp As Outlook._Application)
Dim mail As Outlook.MailItem = Nothing
Dim mailRecipients As Outlook.Recipients = Nothing
Dim mailRecipient As Outlook.Recipient = Nothing
Try
mail = OutlookApp.CreateItem(Outlook.OlItemType.olMailItem)
mail.Subject = "A programatically generated e-mail"
mailRecipients = mail.Recipients
mailRecipient = mailRecipients.Add("Eugene Astafiev")
mailRecipient.Resolve()
If (mailRecipient.Resolved) Then
mail.Send()
Else
System.Windows.Forms.MessageBox.Show(
"There is no such record in your address book.")
End If
Catch ex As Exception
System.Windows.Forms.MessageBox.Show(ex.Message,
"An exception is occured in the code of add-in.")
Finally
If Not IsNothing(mailRecipient) Then Marshal.ReleaseComObject(mailRecipient)
If Not IsNothing(mailRecipients) Then Marshal.ReleaseComObject(mailRecipients)
If Not IsNothing(mail) Then Marshal.ReleaseComObject(mail)
End Try
End Sub
Read more about that in the following articles:
How To: Create and send an Outlook message programmatically
How To: Fill TO,CC and BCC fields in Outlook programmatically
How to create and show a new Outlook mail item programmatically: C#, VB.NET
if no reply is sent to the target email by x date, send another email.
You can set the following properties on the email:
MailItem.TaskDueDate which sets a Date value that represents the due date of the task for this MailItem.
MailItem.ReminderSet which sets a Boolean value that is True if a reminder has been set for this item.
MailItem.ReminderTime which sets a Date indicating the date and time at which the reminder should occur for the specified item.
In the Application.Reminder event handler you may check whether the mail item was replied or forwarded by reading a low-level property value. The property you would read would be PR_LAST_VERB_EXECUTED (0x10810003). Values are listed below:
EXCHIVERB_REPLYTOSENDER = 102
EXCHIVERB_REPLYTOALL = 103
EXCHIVERB_FORWARD = 104
Please remember that you can use the PropertyAccessor for that:
lastVerbExecuted = mailItem.PropertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x10810003")

Adding attendees to Outlook AppointmentItem (VB.NET)

I am trying to make an application in which i can send appointments to co-workers.
My code is as follows:
Public Sub SendAppointment()
Dim TempApp As Outlook.Application = New Outlook.Application()
'An AppointmentItem 'TempAppItem' object represent one appointment
Dim TempAppItem As Outlook.AppointmentItem = TempApp.CreateItem(Outlook.OlItemType.olAppointmentItem)
TempAppItem.Subject = Onderwerp.SelectedItem
TempAppItem.Body = Opmerking.Text
'Set Location
'TempAppItem.Location = "No Location"
'Set start and end date and times
TempAppItem.Start = Convert.ToDateTime(Btijd.SelectedItem)
TempAppItem.End = Convert.ToDateTime(Etijd.SelectedItem)
'Save to Calendar.
TempAppItem.RequiredAttendees("some#emailaddress.com")
TempAppItem.Send()
TempAppItem.Save()
TempApp = Nothing
TempAppItem = Nothing
End Sub
If I leave out:
TempAppItem.RequiredAttendees("some#emailaddress.com")
It creates the appointment in my own calendar. This proves the rest of the code works. But somehow no matter which argument i add to RequiredAttendees, I keep getting errors. Mostly saying "Too many arguments to 'Property RequiredAttendees As String'.
In my eyes the easiest would be if I can just use the users e-mailaddress as a value to a variable, but somehow it seems vb.net only uses the stored name of said contact, which doesn't seem to work :\
I can't find any explanation of how to properly set the RequiredAttendees property and I am starting to break my head over this. Can anyone help me out or at least push me in the right direction?

Best way to change the "From" address on an arriving email in Outlook's VBA script?

My overall goal is to change the "From" sender on an incoming email to something else. Specifically, I get chat logs from Zopim chat and they're all coming from Zopim's "no-reply" email. However, I want these chat logs to be associated with in my CRM and thus I want them associated to people who we chat with.
I've created this VBA script, it runs without errors, however, no change is done to the incoming email. What am I doing wrong?
Option Explicit
Sub ZopimChatMessageRule(Item As Outlook.MailItem)
Dim body As String
Dim sndr As String
On Error GoTo Finally
body = Trim(Right(Item.body, Len(Item.body) - (InStrRev(Item.body, "EMAIL") + 5)))
sndr = Trim(Left(body, InStr(body, vbCrLf) - 1))
Item.sender.Address = sndr
Item.sender.Name = sndr
Item.sender.Update
Item.Recipients.ResolveAll
Item.Save
Finally:
End Sub
Your code is updating the name and address of a one-off address entry that does not exist anywhere. What you need to do is change the Sender and SentOnBehalfOf properties, which are read-only in the Outlook Object Model.
You can use MailItem.PropertyAccessor.SetProperty to update dozen or so PR_SENDER_xyz and PR_SENT_REPRESENTING_xyz MAPI properties - take a look at a message with OutlookSpy (I am its author - click IMessage button). Keep in mind that SetProperty will prevent you from modifying some properties Outlook considers "special".
If using Redemption is an option (I am also its author), you can set the Sender and SentOnBehalfOf properties directly:
set rSession = CreateObject("Redemption.RDOSession")
rSession.MAPIOBJECT = Application.Session.MAPIOBJECT
set Msg = rSession.GetRDOObjectFromOutlookObject(Item )
strEntryID = rSession.AddressBook.CreateOneOffEntryID("Fake User", "SMTP", "someuser#fake.domain.com", false, true)
set addressEntry = rSession.AddressBook.GetAddressEntryFromID(strEntryID)
Msg.Sender = addressEntry
Msg.SentOnBehalfOf = addressEntry
Msg.Save

How to get the email address of the current logged-in user?

I'm new to VBA and trying to get an automated word document working. At the moment there is a Button in the document that which upon pressing, will fire off an email with the document attached.
However I need to also get the email address of the current user sending the email, so I can place it inside the document before sending it off. My searches on the internet have not resulted in any usable code that meets my situation. My current code is below.
Set OL = CreateObject("Outlook.Application")
Set EmailItem = OL.CreateItem(olMailItem)
Set Doc = ActiveDocument
Doc.Save
With EmailItem
.Subject = "Requesting Authorization Use Overtime"
.Body = "Please review the following request for overtime" & vbCrLf & _
"" & vbCrLf & _
"Thanks"
.To = "toemail#test.com"
.Importance = olImportanceNormal
.Attachments.Add Doc.FullName
.Send
End With
Not sure if this is relevant, but when the document is being used, the Outlook application will always be open with a user signed in. Im used to having intellisense help in these sorts of situations so I can fool around with methods and properties, but there seems to be very little help from intellisense.
It all depends on the definition of "the current user address".
The address of the primary account in Outlook can be retrieved from Appication.Session.CurrentUser (returns Recipient object). Use Recipient.Address property. Note however that for an Exchange account (Recipient.AddressEntry.Type == "EX") you will receive an EX type address. To retrieve the SMTP address, use Recipient.AddressEntry.GetExchangeUser().PrimarySmtpAddress. Be prepared to handle nulls/exceptions in case of errors. This is what you most likely need in your particular case.
On the Extended MAPI level (C++ or Delphi), use IMAPISession::QueryIdentity (you can test it in OutlookSpy (I am its author) - click IMAPISession button, then QueryIdentity). You can then read the PR_ADDRTYPE property ("EX" vs "SMTP") and PR_EMAIL_ADDRESS (when PR_ADDRTYPE = "SMTP") or (in case of Exchange) PR_SMTP_ADDRESS (not guaranteed to be present) and PR_EMS_AB_PROXY_ADDRESSES (multivalued property will Exchange addresses, including all proxy (alias) addresses).
In case of multiple accounts in the profile, an email can be sent or received through multiple accounts. In that case use MailItem.SendUsingAccount (returns Account object, can be null - in that case use Application.Session.CurentUser). This is valid both for received, sent or emails being composed (Application.ActiveInspector.CurrentItem or Application.ActiveExplorer.ActiveInlineResponse).
All accounts in a given profile can be accessed using the Namespace.Accounts collection (Application.Session.Accounts). Account's address can be accessed using Account.SmtpAddress property.
Note that the Outlook Object Model only exposes mail accounts. Some store accounts (such as PST) are not in the collection since they do not have an intrinsic user identity even if some other accounts (such as POP3/SMTP) can deliver to that store. If you want to access all accounts, you can use Redemption (I am its author) and its RDOSession.Accounts collection (RDOAccounts object).
On the Extended MAPI level, the accounts are exposed through the IOlkAccountManager interface. You can play with it in OutlookSpy if you click the IOlkAccountManager button.
In case of delegate Exchange stores, the store owner is not exposed through the Outlook Object Model. You can either use Extended MAPI (note that the PR_MAILBOX_OWNER_ENTRYID property is only exposed by the online store, it is not available in a cached store). You can parse the Exchange store entry id and extract the EX type address from it. You can then construct the GAL object entry id given the EX address. You can also access the store owner using Redemption and its RDOExchangeMailboxStore object and its Owner property.
Usually, the email address is the name assigned to Outlook Mail Folders.
So try this:
'~~> add these lines to your code
Dim olNS As Outlook.NameSpace
Dim olFol AS Outlook.Folder
Set olNS = OL.GetNamespace("MAPI")
Set olFol = olNS.GetDefaultFolder(olFolderInbox)
MsgBox olFol.Parent.Name '~~> most cases contains the email address
This is assuming your are using Early Bind with the object reference properly set.
Another way to access such info is directly use Namespace properties.
MsgBox olNS.Accounts.Item(1).DisplayName '~~> usually email address
MsgBox olNS.Accounts.Item(1).SmtpAddress '~~> email address
MsgBox olNS.Accounts.Item(1).UserName '~~> displays the user name
I hope any of the above somehow helps.
This answer is for Late Binding so you don't need to have reference libraries. Place the following code in a module:
Dim OL As Object, olAllUsers As Object, oExchUser As Object, oentry As Object, myitem As Object
Dim User As String
Set OL = CreateObject("outlook.application")
Set olAllUsers = OL.Session.AddressLists.Item("All Users").AddressEntries
User = OL.Session.CurrentUser.Name
Set oentry = olAllUsers.Item(User)
Set oExchUser = oentry.GetExchangeUser()
msgbox oExchUser.PrimarySmtpAddress
Functional Approach
To make this a bit more reusable, try any return the email from a function.
Late Binding Example
''
' Creates a new instance of Microsoft Outlook to get the current users
' email address.
' Late Binding Demo.
'
' #exception If any errors it will return an optional parameter for fallback values
''
Public Function GetUsersOutlookEmail(Optional ByVal errorFallback As String = "") As String
On Error GoTo catch
With CreateObject("outlook.application")
GetUsersOutlookEmail = .GetNamespace("MAPI").GetDefaultFolder(olFolderInbox).Parent.Name
End With
Exit Function
catch:
GetUsersOutlookEmail = errorFallback
End Function
Early Binding Example
''
' Creates a new instance of Microsoft Outlook to get the current users
' email address.
' Late Binding Demo.
'
' #reference Microsoft Outlook 16.0 Object Reference
' #exception If any errors it will return an optional parameter for fallback values
''
Public Function GetUsersOutlookEmail(Optional ByVal errorFallback As String = "") As String
On Error GoTo catch
With New Outlook.Application
GetUsersOutlookEmail = .GetNamespace("MAPI").GetDefaultFolder(olFolderInbox).Parent.Name
End With
Exit Function
catch:
GetUsersOutlookEmail = errorFallback
End Function
Error Handling
Anytime you are making an API call like this, there is always a potential for errors to occur. The method I choose for these demos is to provided an optional parameter for a fallback email. This make is dynamic as you can check to see if it is null, or you could provide something such as username Environ("Username") & "#outlook.com"