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.
Related
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.
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
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
This sub in an Excel VBA application that has worked well for years, inserting an Outlook signature into an email before displaying the email for me to send (.Display). This has worked in Excel 2007 in Windows XP and 2013 in Windows 7.
Now I have Windows 8.1 and Office 2013 this comes out with Error 91 in my error routine. Could it be a problem with one of the References? - or some change needed in the code?
Sub InsertSig2007(strSigName As String)
Dim objItem As Object
Dim objInsp As Outlook.Inspector
' requires a project reference to the
' Microsoft Office library
Dim objCBP As Office.CommandBarPopup
Dim objCBP2 As Office.CommandBarPopup
Dim objCBB As Office.CommandBarButton
Dim colCBControls As Office.CommandBarControls
Set objInsp = ActiveInspector
If Not objInsp Is Nothing Then
Set objItem = objInsp.CurrentItem
If objItem.Class = olMail Then
' get Insert menu
Set objCBP = objInsp.CommandBars.ActiveMenuBar.FindControl(, 30005)
' get Signature submenu
Set objCBP2 = objCBP.CommandBar.FindControl(, 5608)
If Not objCBP2 Is Nothing Then
Set colCBControls = objCBP2.Controls
For Each objCBB In colCBControls
Debug.Print objCBB.Caption
If objCBB.Caption = strSigName Then
objCBB.Execute ' **** see remarks
Exit For
End If
Next
End If
End If
End If
Set objInsp = Nothing
Set objItem = Nothing
Set colCBControls = Nothing
Set objCBB = Nothing
Set objCBP = Nothing
Set objCBP2 = Nothing
End Sub
"this comes out with Error 91 in my error routine" When debugging do not use an error routine. That way you see the line with the problem and can say what it is in your question.
It is probably
Set objCBP = objInsp.CommandBars.ActiveMenuBar.FindControl(, 30005)
See CommandBars.FindControl Method (Office)
"The use of CommandBars in some Microsoft Office applications has been superseded by the new ribbon component of the Microsoft Office Fluent user interface."
Note: CommandBars.ExecuteMso Method (Office) works in 2013 but I believe the signature button is not available.
You will surely find a replacement for your code here Insert Outlook Signature in mail.
Likely this one:
Sub Mail_Outlook_With_Signature_Html_2()
' Don't forget to copy the function GetBoiler in the module.
' Working in Office 2000-2013
'Dim OutApp As Object
Dim OutMail As Object
Dim strbody As String
Dim SigString As String
Dim Signature As String
'Set OutApp = CreateObject("Outlook.Application")
'Set OutMail = OutApp.CreateItem(0)
Set OutMail = CreateItem(0)
strbody = "<H3><B>Dear Customer Ron de Bruin</B></H3>" & _
"Please visit this website to download the new version.<br>" & _
"Let me know if you have problems.<br>" & _
"Ron's Excel Page" & _
"<br><br><B>Thank you</B>"
'Change only Mysig.htm to the name of your signature
SigString = Environ("appdata") & _
"\Microsoft\Signatures\Mysig.htm"
If Dir(SigString) <> "" Then
Signature = GetBoiler(SigString)
Else
Signature = ""
End If
On Error Resume Next
With OutMail
'.To = "ron#debruin.nl"
.CC = ""
.BCC = ""
.Subject = "This is the Subject line"
.HTMLBody = strbody & "<br>" & Signature
'.Send
'or use
.Display
End With
On Error GoTo 0
Set OutMail = Nothing
'Set OutApp = Nothing
End Sub
Function GetBoiler(ByVal sFile As String) As String
'Dick Kusleika
Dim fso As Object
Dim ts As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Set ts = fso.GetFile(sFile).OpenAsTextStream(1, -2)
GetBoiler = ts.readall
ts.Close
End Function
I am using the below code to send an email from excel using outlook:
Private Sub SendEmail()
Set OutlookApp = CreateObject("Outlook.Application")
Set OlObjects = OutlookApp.GetNamespace("MAPI")
Set newmsg = OutlookApp.CreateItem(olMailItem)
newmsg.Recipients.Add ("name#domain.com; name2#domain.com; name3#domain.com")
newmsg.Subject = "Test Mail"
newmsg.Body = "This is a test email."
'newmsg.Display
newmsg.Send
End Sub
The code works just fine, however I get the below error from Outlook when trying to send the email:
ErrorScreen http://im58.gulfup.com/GRENlB.png
The strange thing is that if I leave the new message open for two or three minutes the names automatically get resolved:
Working http://im74.gulfup.com/qmOYGQ.png
However this doesn't suit me as I don't want the message to be displayed before it's sent. I am looking to have it send as soon as I run the code.
Any suggestions or workarounds will be appreciated.
As a side note: I have tried enabling the "Allow commas as email separators" option in outlook, and then using the commas instead of the semicolons, but I am still facing the same problem.
UPDATE:
Below is the working code, as per Dmitry Streblechenko's answer:
Private Sub SendEmail()
Dim OutApp As Object
Dim OutMail As Object
Dim strbody As String
Set OutApp = CreateObject("Outlook.Application")
Set OlObjects = OutApp.GetNamespace("MAPI")
Set OutMail = OutApp.CreateItem(olMailItem)
On Error Resume Next
With OutMail
.To = ("name#domain.com; name2#domain.com; name3#domain.com")
.Subject = "Test Mail"
.Body = "This is a test email."
'.Display
.Send
End With
End Sub
You cannot pass multiple names to Recipients.Add - you get a single recipient with the name of "name#domain.com; name2#domain.com; name3#domain.com". Either call Recipients.Add 3 times once for each recipient or set the To property - it will parse multiple names.
You should add a call to ResolveAll to explicitely resolve all recipients.
Otherwise, resolution is done automatically after a short waiting period.
Example:
Sub CheckRecipients()
Dim MyItem As Outlook.MailItem
Dim myRecipients As Outlook.Recipients
Dim myRecipient As Outlook.Recipient
Set myItem = Application.CreateItem(olMailItem)
Set myRecipients = myItem.Recipients
myRecipients.Add("Aaron Con")
myRecipients.Add("Nate Sun")
myRecipients.Add("Dan Wilson")
If Not myRecipients.ResolveAll Then
For Each myRecipient In myRecipients
If Not myRecipient.Resolved Then
MsgBox myRecipient.Name
End If
Next
End If
End Sub
Code copied from here.