The code is asking me who to send this to, but the purpose of the email would be to send it to multiple people at a time. The problem in the code is ".send". I need the code to send it automatically without having to manually input each email within the code.
The first thing I tried was being specific to who I wanted the email to be send with in the code itself. It did not work.
Sub SendReminderMail()
Dim OutLookApp As Object
Dim OutLookMailItem As Object
Dim iCounter As Integer
Dim MailDest As String
Dim StrFrom As String
Dim StrTo As String
Set OutLookApp = CreateObject("Outlook.Application")
Set OutLookMailItem = OutLookApp.CreateItem(0)
With OutLookMailItem
MailDest = ""
For iCounter = 1 To WorksheetFunction.CountA(Columns(4))
If MailDest = "" And Cells(iCounter, 8).Offset(0, -1) = "Send Reminder" Then
MailDest = Cells(iCounter, 8).Value
ElseIf MailDest <> "" And Cells(iCounter, 8).Offset(0, -1) = "send Reminder" Then
MailDest = MailDest & ";" & Cells(iCounter, 8).Value
End If
Next iCounter
.BCC = MailDest
.Subject = "FYI"
.Body = "Reminder: The patient is overdue please contact the patient to reschedule. Please ignore if appointment has been made."
.Send
End With
Set OutLookMailItem = Nothing
Set OutLookApp = Nothing
End Sub
The error I get is "run-time error 462" stating the remote machine does not exist.
I refactored your code (moved variable declarations directly before initialization, changed Integer to Long, reordered the statements to group the ones related to Outlook together, and removed the superfluous Settings to Nothing).
Sub SendReminderMail()
Dim MailDest As String: MailDest = vbNullString
Dim iCounter As Long: For iCounter = 1 To WorksheetFunction.CountA(Columns(4))
If MailDest = "" And Cells(iCounter, 8).Offset(0, -1) = "Send Reminder" Then
MailDest = Cells(iCounter, 8).Value
ElseIf MailDest <> "" And Cells(iCounter, 8).Offset(0, -1) = "Send Reminder" Then
MailDest = MailDest & ";" & Cells(iCounter, 8).Value
End If
Next iCounter
Dim OutLookApp As Object: Set OutLookApp = CreateObject("Outlook.Application")
Dim OutLookMailItem As Object: Set OutLookMailItem = OutLookApp.CreateItem(0)
With OutLookMailItem
.BCC = MailDest
.Subject = "FYI"
.Body = "Reminder: The patient is overdue please contact the patient to reschedule. Please ignore if appointment has been made."
.Send
End With
End Sub
However, I don't think that these changes would correct the error.
I found in Microsoft's Knowledge Base an article regarding this issue: https://support.microsoft.com/en-us/help/189618/you-may-receive-the-run-time-error-2147023174-800706ba-error-message-o
To summarize it quickly: If you use unqualified references to refer to variables (e.g. Set a = ActiveDocument instead of Set a = WordApp.ActiveDocument) then VBA creates a hidden global variable to store which Application's ActiveDocument it refers to. Therefore if you try to quit that Application, you won't succeed and the Application will continue to run (without a visible window and without an error message) and the next time you want to refer to the ActiveDocument, it won't refer to the that Application's ActiveDocument which you started last time but the old Application's ActiveDocument, which, however was destroyed when the old Application started its process of exiting.
I examined your code and found no such unqualified reference.
My theory is that either (A) you judged some part of your code irrelevant to the problem and did not post it; and that contains such an unqualified reference; or (B) you are in the middle of developing this Sub and previous versions of the code created some dangling references.
In case (A) please post all other parts of your code that handles Outlook in any way.
In case (B) check in the Task Manager how many Outlook processes are running. Sign out from windows to make sure that all your Applications are closed, sign in, and try if the error still occurs.
Related
I have an Excel sheet with about 200 e-mail addresses in a column.
I'm trying to create an email with a standard recipient in the "to" field, and loop through those 200 addresses and put a fixed number of addresses in the "bcc" field and then create another mail with the next following fixed number of addresses, and so on until I have reached the end of the list.
I modified the following code I found online to send individual mails:
Sub BulkMail()
Application.ScreenUpdating = False
ThisWorkbook.Activate
'Creating references to Application and MailItem Objects of Outlook
Dim outApp As Outlook.Application
Dim outMail As Outlook.MailItem
'Creating variable to hold values of different items of mail
Dim sendTo, subj, atchmnt, msg, ccTo, bccTo As String
Dim lstRow As Long
ThisWorkbook.Sheets("Sheet1").Activate
'Getting last row of containing email id in column 5.
lstRow = Cells(Rows.Count, 5).End(xlUp).Row
'Variable to hold all email ids
Dim rng As Range
Set rng = Range("E2:E" & lstRow, 20)
'initializing outlook object to access its features
Set outApp = New Outlook.Application
On Error GoTo cleanup 'to handle any error during creation of object.
'Loop to iterate through each row, hold data in of email in variables and send
'mail to each email id.
For Each cell In rng
sendTo = Range(cell.Address).Offset(0, 0).Value2
subj = Range(cell.Address).Offset(0, 1).Value2 & "-MS"
msg = Range(cell.Address).Offset(0, 2).Value2
atchmnt = Range(cell.Address).Offset(0, -1).Value2
ccTo = Range(cell.Address).Offset(0, 3).Value2
bccTo = Range(cell.Address).Offset(0, 4).Value2
On Error Resume Next 'to hand any error during creation of below object
Set outMail = outApp.CreateItem(0)
'Writing and sending mail in new mail
With outMail
.To = sendTo
.BCC = bccTo
.Body = "Hi this is a test"
.Subject = "Test"
.Attachments.Add atchmnt
.Send 'this send mail without any notification. If you want see mail
'before send, use .Display method.
End With
On Error GoTo 0 'To clean any error captured earlier
Set outMail = Nothing 'nullifying outmail object for next mail
Next cell 'loop ends
cleanup: 'freeing all objects created
Set outApp = Nothing
Application.ScreenUpdating = True
Application.ScreenUpdating = True
End Sub
My searches to see if I can modify the step size didn't provide me with anything that seemed useful.
I understand that my range is set from the value in the second row until the last value found in a cell in (in this case) column E.
I essentially don't want to use For Each cell In rng but something like For every 20 cells In rng (the last one obviously doesn't work, but it might be a useful pseudo code example).
I've read that an array might be more useful, and from what I understood I could potentially store ranges of values in multiple arrays and then loop through the array. I want to learn to do this.
You need to replace the following piece of code:
For Each cell In rng
sendTo = Range(cell.Address).Offset(0, 0).Value2
subj = Range(cell.Address).Offset(0, 1).Value2 & "-MS"
msg = Range(cell.Address).Offset(0, 2).Value2
atchmnt = Range(cell.Address).Offset(0, -1).Value2
ccTo = Range(cell.Address).Offset(0, 3).Value2
bccTo = Range(cell.Address).Offset(0, 4).Value2
On Error Resume Next 'to hand any error during creation of below object
Set outMail = outApp.CreateItem(0)
'Writing and sending mail in new mail
With outMail
.To = sendTo
.BCC = bccTo
.Body = "Hi this is a test"
.Subject = "Test"
.Attachments.Add atchmnt
.Send 'this send mail without any notification. If you want see mail
'before send, use .Display method.
End With
On Error GoTo 0 'To clean any error captured earlier
Set outMail = Nothing 'nullifying outmail object for next mail
Next cell 'loop ends
First of all, there is no need to create a new mail item object for each row in the worksheet. So, you need to create a mail item out of the loop:
Set outMail = outApp.CreateItem(0)
sendTo = Range(cell.Address).Offset(0, 0).Value2
subj = Range(cell.Address).Offset(0, 1).Value2 & "-MS"
msg = Range(cell.Address).Offset(0, 2).Value2
atchmnt = Range(cell.Address).Offset(0, -1).Value2
Set recipients = outMail.Recipients
For Each cell In rng
ccTo = Range(cell.Address).Offset(0, 3).Value2
bccTo = Range(cell.Address).Offset(0, 4).Value2
recipientTo = recipients.Add(ccTo)
recipientTo.Type = Outlook.OlMailRecipientType.olTo
recipientBCC = recipients.Add(bccTo)
recipientBCC.Type = Outlook.OlMailRecipientType.olBCC
Next cell 'loop ends
recipients.ResolveAll()
.Body = "Hi this is a test"
.Subject = "Test"
.Attachments.Add atchmnt
.Send 'this send mail without any notification. If you want see mail
Set outMail = Nothing 'nullifying outmail object for next mail
Use the Recipients property of the MailItem class for adding recipients which contains a collection of Recipient objects for an Outlook item. Use the Add method to create a new Recipient object and add it to the Recipients object. The Type property of a new Recipient object is set to the default for the associated AppointmentItem, JournalItem, MailItem, or TaskItem object and must be reset to indicate another recipient type. The name can be a string that represents the display name, the alias, the full SMTP email address, or the mobile phone number of the recipient. A good practice is to use the SMTP email address for a mail message.
Read more about that in the How To: Fill TO,CC and BCC fields in Outlook programmatically article.
I used the below coding earlier for some other type of mail but this time is not sending the mails.
Also not picking the email IDs and data given in Excel.
I have to send mails to different people with CC to their respective managers. I updated their Email IDs in Excel but the details updated in Excel are not taking and a draft mail is created without anything in To and CC.
Sub Send_Recertification_From_Excel()
Dim oXlWkBk As Excel.Workbook ' Excel Work Book Object
Dim oOLApp As Outlook.Application
Dim oOLMail As MailItem
Dim lRow As Long
Dim olMailItem
Dim sMailID As String
Dim sSalutation As String
Dim sName As String
Dim sDetails As String
Dim sSubject As String
Dim mailsSentString As String
Dim templateName As String
templateName = "C:\Users\m540797\Desktop\Recertification\Recertifications"
On Error GoTo Err_Trap
Set oXlWkBk = ActiveWorkbook
Set oOLApp = GetObject(, "Outlook.Application")
If oOLApp Is Nothing Then
MsgBox "Please Open Outlook.."
Exit Sub
End If
Dim i As Integer
For i = 6 To 50
If Len(Trim(Sheet1.Cells(i, 1))) > 1 Then
Set oOLMail = oOLApp.CreateItemFromTemplate(templateName)
sMailID = Sheet1.Cells(i, 4)
sSubject = "Recertification"
With oOLMail
.BodyFormat = olFormatHTML
.HTMLBody = Replace(.HTMLBody, "<NAME>", Sheet1.Cells(i, 3))
.SentOnBehalfOfName = "my mail ID given here"
.To = sMailID
.Subject = sSubject
.CC = Sheet1.Cells(i, 6)
.Send
End With
oOLMail.Send
Else
Exit For
End If
Next i
MsgBox "Mails successfully sent to :" + vbCrLf + mailsSentString + vbCrLf + "with using the template :" + templateName
Destroy_Objects:
If Not oOLApp Is Nothing Then Set oOLApp = Nothing
Err_Trap:
If Err <> 0 Then
MsgBox Err.Description, vbInformation, "VBADUD AutoMail"
Err.Clear
GoTo Destroy_Objects
End If
End Sub
Not giving any error just says mail sent successfully but it is lying in draft.
Below code displays e-mail creation screen in outlook each time i run it. i tried removing .display from the second function but it gives run-time error.
I am new to VBA macros ,Please advice on how to hide the e-mail creation screen for each new e-mail that is being triggered. thanks a lot in advance.
Public Sub loopCheck()
Dim NumRows As Integer
Dim eID As String
Dim eName As String
Dim eEmail As String
Dim supportGroup As String
Dim managerEmail As String
Dim acName As String
Dim x As Integer
Application.ScreenUpdating = False
NumRows = Worksheets("Data").Range("A5", Range("A5").End(xlDown)).Rows.Count ' Set numrows = number of rows of data.
Worksheets("Data").Range("A5").Select ' Select first record.
For x = 1 To NumRows ' Establish "For" loop to loop "numrows" number of times.
eID = Worksheets("Data").Range("A" & x + 4).Value
eName = Worksheets("Data").Range("B" & x + 4).Value
eEmail = Worksheets("Data").Range("C" & x + 4).Value
supportGroup = Worksheets("Data").Range("F" & x + 4).Value
managerEmail = Worksheets("Data").Range("G" & x + 4).Value
acName = Worksheets("Data").Range("I" & x + 4).Value
'Prepare table to be sent locally.
Worksheets("Data").Range("AA5").Value = eID
Worksheets("Data").Range("AB5").Value = eName
Worksheets("Data").Range("AC5").Value = eEmail
Worksheets("Data").Range("AF5").Value = supportGroup
managerEmail = managerEmail + ";" + Worksheets("Data").Range("AA1").Value
'Call Emails function.
Call Emails(eEmail, managerEmail)
ActiveCell.Offset(1, 0).Select
Next
Application.ScreenUpdating = True
End Sub
Public Sub Emails(y As String, z As String)
Dim outlook As Object
Dim newEmail As Object
Dim xInspect As Object
Dim pageEditor As Object
Dim a As String
Dim b As String
a = y
b = z
Set outlook = CreateObject("Outlook.Application")
Set newEmail = outlook.CreateItem(0)
With newEmail
.To = a
.CC = b
.BCC = ""
.Subject = "test loop"
.Body = ""
.display
Set xInspect = newEmail.GetInspector
Set pageEditor = xInspect.WordEditor
Worksheets("Data").Range("AA4:AF5").Copy
pageEditor.Application.Selection.Start = Len(.Body)
pageEditor.Application.Selection.End = pageEditor.Application.Selection.Start
pageEditor.Application.Selection.PasteAndFormat (wdFormatPlainText)
.display
.send
Set pageEditor = Nothing
Set xInspect = Nothing
End With
Set newEmail = Nothing
Set outlook = Nothing
End Sub
You have two instances of .display in your Emails sub .If first instance is suppressed it locks the editor and would not allow program to run. Second instance can be commented out and .send is enough for program working. Still first instance will display on screen . In order to totally disable e-mail creation screen display please take reference from programs at roundebruin which covers all types of possibilities of sending emails without displaying email creation screen. Method followed by you is a preferred method for embedding of images or charts in the HTML body.
your adopted code is similar to SO Question . Please refer to opening comments in Answer by Dmitry Streblechenko " --
You should also use MailItem.GetInspector instead of
Application.ActiveInspector since the message is not yet displayed.
So if you want to suppress e-mail creation screen display, please adopt other approach as suggested earlier.
Further Eugene Astafiev also mentioned while answering a question HERE
That's a known issue in Outlook. You have to call the Display method first to get the inspector visible.
Otherwise it won't work.
I think you can not suppress display of e-mail creation screen display by invoking this approach.
I'm writting macro that finds an e-mail and replies to it. The problem is that the text I want to reply with does not add. Could you please tell me what I'm doing wrong?
Sub Test()
Dim olApp As Object
Dim olNs As Object
Dim Fldr As Object
Dim i As Long
Set olApp = CreateObject("Outlook.Application")
Set olNs = olApp.GetNamespace("MAPI").GetDefaultFolder(olFolderInbox).Folders("Test")
i = 1
For Each olMail In olNs.Items
If InStr(olMail.Subject, "kanapka") <> 0 Then
With olMail.ReplyAll
.CC = "xyz#xyz"
.Body = "Dear All," _
& vbCrLf & "aaaaaa" 'these two lines should add
olMail.Reply.Display
End With
i = i + 1
End If
Next olMail
End Sub
Try adding this to your code:
For Each olMail In olNs.Items
If InStr(olMail.Subject, "testme") <> 0 Then
Set oReply = olMail.Reply
Set oRecip = oReply.Recipients.Add("x#y.z")
oRecip.Type = olCC
oReply.HTMLBody = "Thank you!!!" & oReply.HTMLBody
oReply.Display
Stop ' - remove this once you try the code.
End If
Next olMail
As you see, you have to declare oReply and oRecip as Objects, but these two make your life really easier.
In order to add some text to the answer, simply increment the body this way:
oReply.HTMLBody = "Thank you!!!" & oReply.HTMLBody
I have also included a Stop in your code, to make sure that it does not display plenty of emails.
I'm working towards improving my efficiency at my workplace. For this there is a task of sending an e-mail to a list of people.
For this I have created the following code. Would like to know if this can be improved? This code takes the information from sheet "Final_list" in a workbook and headers are in row 1.
Sub EmailToAll()
Dim outlookApp As Outlook.Application
Dim outlookMail As Outlook.MailItem
Set outlookApp = CreateObject("Outlook.Application")
Set outlookMail = outlookApp.CreateItem(olMailItem)
Dim sh As Worksheet
Dim RowCount As Integer
Worksheets("Final_List").Activate
RowCount = 2
Set sh = ActiveSheet
Do While IsEmpty(sh.Cells(RowCount, 1).Value) = False
Set outlookApp = CreateObject("Outlook.Application")
Set outlookMail = outlookApp.CreateItem(olMailItem)
With outlookMail
'MsgBox sh.Cells(RowCount, 7).Value
.To = sh.Cells(RowCount, 7).Value
.CC = sh.Cells(RowCount, 9).Value
.BCC = Empty
.Subject = "[Update]" & " " & sh.Cells(RowCount, 1).Value & "-" & sh.Cells(RowCount, 8).Value
.BodyFormat = 2
.HTMLBody = "Hello "
'.Display
'.Save
'.Close
.Send
'MsgBox "Mail saved for" & sh.Cells(RowCount, 7).Value & "!"
RowCount = RowCount + 1
End With
Loop
Set outlookMail = Nothing
Set outlookApp = Nothing
MsgBox "All mails sent!"
End Sub
You do not need to create Outlook Object twice . Set outlookApp = CreateObject("Outlook.Application") and change Dim RowCount As Integer to Dim RowCount As Long
Also avoid .Activate
Option Explicit
Sub EmailToAll()
Dim outlookApp As Outlook.Application
Dim outlookMail As Outlook.MailItem
Dim RowCount As Long
Set outlookApp = CreateObject("Outlook.Application")
RowCount = 2
With Worksheets("Final_List")
Do While IsEmpty(Cells(RowCount, 1).Value) = False
Set outlookMail = outlookApp.CreateItem(olMailItem)
With outlookMail
.To = Cells(RowCount, 7).Value
.CC = Cells(RowCount, 9).Value
.BCC = Empty
.Subject = "[Update]" & " " & Cells(RowCount, 1).Value & "-" & Cells(RowCount, 8).Value
.BodyFormat = 2
.HTMLBody = "Hello "
.Send
End With
RowCount = RowCount + 1
Loop
End With
Set outlookMail = Nothing
Set outlookApp = Nothing
MsgBox "All mails sent!"
End Sub
Not sure exactly what parts of this you would like to optimise but after looking at your example, here are a couple of things which I would look at changing;
The only things which are changing within the loop are the recipients and the subject line, the body is always the same (obviously I don't know what is stored in those cells) but maybe you could just construct the recipients string within the loop which should work fine if you separate the email addresses with semi-colons and send one email instead of multiple emails?
The other thing which I would mention is that you are stopping when you encounter a blank line which means that the loop may not pick up all recipients if someone deleted that line by mistake. There are many much more robust ways of locating the end of the data you could use.
Hope that helps.