Excel VBA array of strings to Outlook email "To" field - vba

I am trying to create a macro that will take a column of email addresses from my Excel sheet and populate the "To" field in an Outlook email. I have the basics working, and I am able to create a new Outlook email message with the various field values I have specified - however, I cannot figure out how to populate multiple email addresses into the "To" field, for a single email.
As of right now, I am able to create an array with all of the desired email addresses, but can't figure out how to populate the array values into the Outlook "To" field.

This is based on Eugene's answer, edited to include the excel implementation
Sub CreateStatusReportToBoss(addRng as Excel.Range)
Dim myItem As Outlook.MailItem
Dim myRecipient As Outlook.Recipient
Set myItem = Application.CreateItem(olMailItem)
For Each cell in addRng
Set myRecipient = myItem.Recipients.Add(cell.Value)
Next cell
myItem.Subject = "Status Report"
myItem.Display
End Sub

You can use the Recipients property of the MailItem class for adding multiple recipients. It also allows to specify the type of the Recipient: To, CC or BCC.
Sub CreateStatusReportToBoss()
Dim myItem As Outlook.MailItem
Dim myRecipient As Outlook.Recipient
Set myItem = Application.CreateItem(olMailItem)
Set myRecipient = myItem.Recipients.Add("Dan Wilson")
myItem.Subject = "Status Report"
myItem.Display
End Sub

This might help but the concept is bit different as to the items. Hope this helps out- have used in the past for similar case but ofcourse, will only provide maproad.
Sub CreateMail()
Dim objOutlook As Object
Dim objMail As Object
Dim rngTo As Range
Dim rngCc As Range
Dim rngSubject As Range
Dim rngBody As Range
Set objOutlook = CreateObject("Outlook.Application")
Set objMail = objOutlook.CreateItem(0)
With ActiveSheet
Set rngTo = .Range("B1")
Set rngCc = .Range("B2")
Set rngSubject = .Range("B3")
Set rngBody = .Range(.Range("B4"), .Range("B4").End(xlDown))
End With
rngBody.Copy
With objMail
.To = rngTo.Value
.Cc = rngCc.Value
.Subject = rngSubject.Value
.Display
End With
SendKeys "^({v})", True
Set objOutlook = Nothing
Set objMail = Nothing
Set rngTo = Nothing
Set rngCc = Nothing
Set rngSubject = Nothing
Set rngBody = Nothing
End Sub

Related

Cannot find default inbox after updating to Office 365

I have code that looks for a specific subject line in an email on Outlook and grabs the attachment from the email.
We merged our emails with a corporate buyout and updated our Microsoft accounts to Office 365. Aside from this, my original VBA code should work since it doesn't look for any specific email folder. All references for Outlook are checked.
I get "nothing" for olMi and it exits the if statement.
Function Report()
Dim rng As Range
Dim OutApp As Object
Dim OutMail As Object
Dim olApp As Outlook.Application
Dim olNs As Namespace
Dim olFldr As MAPIFolder
Dim olItms As Items
Dim olMi As MailItem
Dim olEmail As Outlook.MailItem
Dim olAtt As Attachment
Dim MyPath As String
Dim wB As Workbook
Set olApp = GetObject(, "Outlook.Application")
Set olNs = olApp.GetNamespace("MAPI")
Set olFldr = olNs.GetDefaultFolder(olFolderInbox)
Set olItms = olFldr.Items
Set olEmail = olApp.CreateItem(olMailItem)
Set rng = Nothing
Set OutApp = CreateObject("Outlook.Application")
Set OutMail = OutApp.CreateItem(0)
Application.DisplayAlerts = False
Application.EnableEvents = False
Application.ScreenUpdating = False
subj = "Scheduled Report - Instructor List"
Set olMi = olItms.Find("[Subject] = " & Chr(34) & subj & Chr(34))
''___> I get "OlMi = Nothing" here and it used to work
If Not (olMi Is Nothing) Then
For Each olAtt In olMi.Attachments
olAtt.SaveAsFile "C:\Users\Instructor\Desktop\temp\Instructor_Master.xls"
Next olAtt
Else
End If
End Function
The default mailbox can change.
To determine the current default mailbox.
Option Explicit
Private Sub defaultAfterUpgrade()
Dim defInbx As Folder
Dim defMailbox As Folder
Set defInbx = Session.GetDefaultFolder(olFolderInbox)
Set defMailbox = defInbx.Parent
Debug.Print "The default mailbox is: " & defMailbox.name
End Sub
As you found, when this occurs you have to change to the long version of referencing an inbox that includes the mailbox name.

Refer 'To' field in Outlook to cell

I'm trying to create a macro on Excel VBA that will create an email and will populate the To field from the Excel cell K6.
When this code runs, I get the error message Run-time error'5': Invalid procedure call or argument.
Dim OutApp As Object
Dim MItem As Object
Dim cell As Range
Dim rng As Range
Dim Subj As String
Dim EmailAddr As String
Dim myRecipient As Object
Dim myRecipients As Object
Dim Recipient As String
Dim Msg As String
Dim ws1 As Worksheet
Dim DateNow As Date
Set ws1 = Sheets("Email")
'Create Outlook object
Set rng = ws1.Range("B6:F26").SpecialCells(xlCellTypeVisible)
With Application
.EnableEvents = False
.ScreenUpdating = False
End With
Set OutApp = CreateObject("Outlook.Application")
Set MItem = OutApp.CreateItem(0)
Set myRecipients = MItem.Recipients
myRecipients = ws1.Cells.Range("K6")
If Not myRecipients.ResolveAll Then
For Each myRecipient In myRecipients
If Not myRecipient.Resolved Then
MsgBox myRecipient.Name
End If
Next
End If
DateNow = Format(Now, "dd/MM/yyyy")
DateNow2 = Format(Now, "h:mm")
Msg = "This report was generated on " & DateNow & " at " & DateNow2 & "."
With MItem
.CC = EmailAddr2
.Subject = Subj
.HTMLBody = RangetoHTML(rng) & Msg
.Display
End With
On Error GoTo 0
With Application
.EnableEvents = True
.ScreenUpdating = False
End With
Set MItem = Nothing
Set OutApp = Nothing
End Sub
If I use Set myRecipients = ws1.Cells.Range("K6") I get the error message Run-time error '438': Object doesn't support this property or method.
If I set the myRecipients As String, it says Object required.
I'm having lots of problems to understand late-binding Outlook in Excel VBA and I've read lots of things, but haven't found many sources on it that could explain this in a more didactic way.
Besides that, I'm also trying to, after adding the content of the cell, to Resolve (the effect of using ctrl + K on Outlook to resolve the email to the display name) the emails added to the To field, but I can't test it without making the first part work.
Thanks for the attention,
Edit: after Bruce Wayne's suggestion, I put them as Range, but now I'm getting a different error: Run-time error '-2147352567 (800200009)': Property is read-only.
Dim myRecipient As Range
Dim myRecipients As Range
In the middle of the code:
Set OutApp = CreateObject("Outlook.Application")
Set MItem = OutApp.CreateItem(0)
Set myRecipients = ws1.Cells.Range("K6")
Set MItem.Recipients = myRecipients
After Dmitry's suggestion:
Set OutApp = CreateObject("Outlook.Application")
Set MItem = OutApp.CreateItem(0)
Set myRecipients = ws1.Cells.Range("K6")
Set myRecipient = MItem.Recipients.Add(myRecipients)
If Not myRecipients.ResolveAll Then
For Each myRecipient In myRecipients
If Not myRecipient.Resolved Then
MsgBox myRecipient.Name
End If
Next
End If
But I get the error message: Run-time error '438': Object doesn't support this property or method marked on the If Not myRecipients.ResolveAll Then. If I delete all the If part, the code runs fine. But it's very important to me that I'm able to resolve the names and emails in the To/CC fields.
Recipients property is indeed read-only. You need to either call MailItem.Recipients.Add for each recipient or set the To / CC/ BCC properties to a ";" separated list of names or addresses.
UPDATE:
Set OutApp = CreateObject("Outlook.Application")
Set MItem = OutApp.CreateItem(0)
Set recipName = ws1.Cells.Range("K6").Value
Set myRecipient = MItem.Recipients.Add(recipName)
If Not myRecipient.Resolve Then
MsgBox myRecipient.Name
End If
I think it's due to the fact that you're setting myRecipients and myRecipient as an Object but want to set it with what is essentially a Range type. Try:
Dim myRecipients as Range, myRecipient as Range
Dim objMyRecipients as Object, objMyRecipient as Object 'create a variable that holds the object
Then, when you need to use them as an object, you have a separate variable to do so.

Activating specific email in Outlook with VBA & deleting signature from the copied text

I'm looking to use the get function in vba in order to activate a specific email in Outlook and then copy the body into a new email and send. I can use the getlast function to get the latest email in the inbox, however I would like to refine the code some more by selecting the latest email from a specific email address.
Also, I'd love how to know how to delete the signature from the text pasted into the new email.
Sub Negotiations()
Dim objMsg As Outlook.MailItem
Dim objItem As Outlook.MailItem
Dim BodyText As Object
Dim myinspector As Outlook.Inspector
Dim myItem As Outlook.MailItem
Dim NewMail As MailItem, oInspector As Inspector
Set myItem = Application.Session.GetDefaultFolder(olFolderInbox).Items.GetLast
myItem.Display
'copy body of current item
Set activeMailMessage = ActiveInspector.CurrentItem
activeMailMessage.GetInspector().WordEditor.Range.FormattedText.Copy
' Create the message.
Set objMsg = Application.CreateItem(olMailItem)
'paste body into new email
Set BodyText = objMsg.GetInspector.WordEditor.Range
BodyText.Paste
'set up and send notification email
With objMsg
.To = "#gmail.com"
.Subject = "Negotiations"
.HTMLBody = activeMailMessage.HTMLBody
.Display
End With
End Sub
any help would be appreciated, thank you guys!
Open the Inbox folder using Namespace.GetDefaultFolder(olFolderInbox), retrieve the Items collection from MAPIFolder.Items. Sort the items (Items.Sort) on the ReceivedTime property, retrieve the latest email using Items.Find on the SenderEmailAddress property.
Dependant on what your property of .SenderEmailAddress returns, you can adapt what the while statement evaluates for. This should work for you, by first looking at the last e-mail, and then checking each previous e-mail for the correct sender address.
Sub display_mail()
Dim outApp As Object, objOutlook As Object, objFolder As Object
Dim myItems As Object, myItem As Object
Dim strSenderName As String
Set outApp = CreateObject("Outlook.Application")
Set objOutlook = outApp.GetNamespace("MAPI")
Set objFolder = objOutlook.GetDefaultFolder(olFolderInbox)
Set myItems = objFolder.Items
strSenderName = UCase(InputBox("Enter the e-mail Alias."))
Set myItem = myItems.GetLast
While Right(myItem.SenderEmailAddress, Len(strSenderName)) <> strSenderName
Set myItem = myItems.GetPrevious
Wend
myItem.Display
End Sub
Application.Session.GetDefaultFolder(olFolderInbox).Items.GetLast
activeMailMessage.GetInspector().WordEditor.Range.FormattedText.Copy
First of all, I'd recommend breaking the chain of calls. Declare each property or method call on a separate line of code, so you will be able to debug the code at any time and see what happens under the hood.
The GetLast method returns the last object in the collectio. But it doesn't mean that the item is recieved last. You need to sort the collection using the Sort method as Dmitry suggested passing the ReceivedTime property as a parameter to sort on. Only in that case you will get the last recieved item from the collection.
The Outlook object model doesn't provide any special method or property for identifying signatures. You need to parse the message body and find it programmatically.
Sub Nego()
Dim objMsg As Outlook.MailItem
Dim myItem As Outlook.MailItem
Dim BodyText As Object
Dim Inspector As Outlook.MailItem
Dim olNameSpace As Outlook.NameSpace
Dim olfolder As Outlook.MAPIFolder
Dim msgStr As String
Dim endStr As String
Dim endStrStart As Long
Dim endStrLen As Long
Dim myItems As Outlook.Items
'Access folder Nego
Const olFolderInbox = 6
Set objOutlook = CreateObject("Outlook.Application")
Set objNamespace = objOutlook.GetNamespace("MAPI")
Set objInbox = objNamespace.GetDefaultFolder(olFolderInbox)
strFolderName = objInbox.Parent
Set objMailbox = objNamespace.Folders(strFolderName)
Set objFolder = objMailbox.Folders("Nego")
'Mark as read
For Each objMessage In objFolder.Items
objMessage.UnRead = False
Next
'Sort
Set myItems = objFolder.Items
For Each myItem In myItems
myItems.Sort "Received", False
Next myItem
myItems.GetLast.Display
'copy body of current item
Set activeMailMessage = ActiveInspector.CurrentItem
activeMailMessage.GetInspector().WordEditor.Range.FormattedText.Copy
' Create the message.
Set objMsg = Application.CreateItem(olMailItem)
'paste body into new email
Set BodyText = objMsg.GetInspector.WordEditor.Range
BodyText.Paste
'Search Body
Set activeMailMessage = ActiveInspector.CurrentItem
endStr = "first line of signature"
endStrLen = Len(endStr)
msgStr = activeMailMessage.HTMLBody
endStrStart = InStr(msgStr, endStr)
activeMailMessage.HTMLBody = Left(msgStr, endStrStart + endStrLen)
'set up and send email
With objMsg
.To = "#email"
.Subject = "Nego"
.HTMLBody = activeMailMessage.HTMLBody
.HTMLBody = Replace(.HTMLBody, "First line of signature", " ")
.Send
End With
End Sub

How to forward emails in a folder and change the reply to address to the original sender?

I have a user who wants to redirect any email to other people in their department so that when that person replies to the email it will go back to the person who originally sent it.
I am trying to make VBA code to forward all emails in a specified folder and change the reply to address so that they don't have to manually put it in every time.
Sub SendFolder()
Dim olApp As Outlook.Application
Dim olNS As Outlook.NameSpace
Dim MyFolder As Outlook.MAPIFolder
Dim ObjMail As Outlook.MailItem
Set olApp = Outlook.Application
Set olNS = olApp.GetNamespace("MAPI")
Set MyFolder = Application.Session.Folders("me#us.com").Folders("test")
For i = MyFolder.Items.Count To 0 Step -1
Set ObjMail.Subject = MyFolder.Itmes(i).Subject
Set ObjMail.ReplyRecipients = MyFolder.Itmes(i).ReplyRecipients
Set ObjMail.Body = MyFolder.Itmes(i).Body
Set ObjMail.Attachments = MyFolder.Itmes(i).Attachments
Set ObjMail.BodyFormat = MyFolder.Itmes(i).BodyFormat
Set ObjMail.To = "test#us.com"
ObjMail.Send
Next
End Sub
You are missing
Set ObjMail = Application.CreateItem(olMailItem)
Then your code would become
With ObjMail
.Subject = MyFolder.Itmes(i).Subject
.ReplyRecipients = MyFolder.Items(i).ReplyRecipients
.Body = MyFolder.Items(i).Body
.Attachments = MyFolder.Items(i).Attachments
.BodyFormat = MyFolder.Items(i).BodyFormat
.To = "test#us.com"
.Send
End with
It it runs now, the ReplyTo does not change.
You will want to set the ObjMail's ReplyRecipients property
Something like .ReplyRecipients.Add MyFolder.Items(i).SenderEmailAddress
To simplify the issue, .Forward the mail as is, and set only the ReplyRecipients property.
Check out this alternative. The mail is sent as an attachment. The receiver automatically replies to the original sender.
Untested
Sub SendFolderItemsAsAttachments()
' Run this VBA code while in Outlook
Dim MyFolder As MAPIFolder
Dim notMyItems as Items
Dim notReplyingToMe as mailitem
Dim i as long
Set MyFolder = Application.Session.Folders("me#us.com").Folders("test")
Set notMyItems = MyFolder.Items
For i = notMyItems.Count To 1 Step -1
If TypeOf notMyItems(i) Is MailItem Then
Set notReplyingToMe = Application.CreateItem(olMailItem)
With notReplyingToMe
.Subject = notMyItems(i).Subject & " - " & _
notMyItems(i).SenderName
.HTMLBody = "Redirecting for your action."
.Attachments.Add notMyItems(i), olEmbeddeditem
.To = "test#us.com"
.Send
End With
notMyItems(i).Delete
End If
Next
Set MyFolder = = Nothing
Set notMyItems = Nothing
Set notReplyingToMe = Nothing
End Sub

Return email address of recipient

I'm building a macro that will run automatically when I move into the body of an email to check the email address of the recipient.
I cannot get the address of the recipient to load into a variable.
Sub BuildTable()
Dim myItem As Outlook.MailItem
Dim myRecipient As String
Set myItem = Application.CreateItem(olMailItem)
Set myRecipient = myItem.Recipient.Address
....
It seems that you are running in MS Outlook and in an Active Inspector, so perhaps:
Sub CheckAddresses()
Dim oEmail As Outlook.MailItem
Dim r As Recipient
Dim rList As Recipients
Set oEmail = Application.ActiveInspector.CurrentItem
Set rList = oEmail.Recipients
rList.ResolveAll
For Each r In rList
Debug.Print r.Address
Next
End Sub
I'm not sure what version of Outlook you are using, but according to Microsoft (http://msdn.microsoft.com/en-us/library/office/aa211006(v=office.11).aspx) you need to use the .Recipients(Index) to get a Recipient. From there you may be able to get the address. I also saw mention of some sort of ResolveAll method attached to .Recipients, though that referenced Outlook 2000 (eww).
Try doing
Dim myItem As Outlook.MailItem
Dim myRecipient as String
Set myItem = Application.CreateItem(olMailItem)
Set myRecipient = myItem.Recipients.Item(0).Address
This will give you the address of the first recipient (note I can't remember if VBA starts at index 0 or 1, if you get IndexOutOfRange, change to 1). If you need others, you're going to need to do a loop. Something like this:
For Each Recipient in myItem.Recipients
// do some stuff here
Next Recipient
Hope this helps.
This is what this segment of code ended up looking like:
Sub BuildTable1()
Dim oEmail As Outlook.MailItem
Set oEmail = Application.ActiveInspector.currentItem
Set xlApp = CreateObject("Excel.Application")
xlApp.Application.Visible = True
xlApp.workbooks.Open FileName:= file location
xlApp.WorkSheets("Contacts").Activate
xlApp.Range("A6").Value = oEmail.To
//filtering by value, copying, pasting, etc.
End Sub
-ZL