Send mails, using oft template, with addresses in Excel - excel

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.

Related

Excel VBA creating a new Outlook appointment results in a cancelled appointment

When I run the following code with .display, the Outlook Appointment gets created in the correct way (shared calendar, recipients, time etc) and I can send the resultant meeting request and it is received by the recipient as a meeting request. However, if I change .display to .send, everything appears to work OK, but the recipient recieves a meeting cancellation (for a meeting that doesn't exist!).
Can anyone point out where I'm going wrong?
Sub CreateMeetings()
Dim olApp As Outlook.Application
Dim olAppItem As Outlook.AppointmentItem
Dim r As Long
Dim oApp As Object
Dim oNameSpace As Namespace
Dim myCalendar As Object
Dim OLNS As Object
Const olAppointmentItem As Long = 1
Dim OLAppointment As Object
Dim MeetingKey As String
Dim datenum As Long
Dim smtprecipient As String
Dim MeetingKeyString As String
Dim emailchk As Long
Set oApp = New Outlook.Application
Set olApp = CreateObject("Outlook.Application")
On Error Resume Next
Set olApp = GetObject("", "Outlook.Application")
On Error GoTo 0
If olApp Is Nothing Then
On Error Resume Next
Set olApp = CreateObject("Outlook.Application")
On Error GoTo 0
If olApp Is Nothing Then
MsgBox "Outlook is not available!"
Exit Sub
End If
End If
'get default user email address
smtprecipient = GetSMTPEmailAddress
'check to see if email address returned is a valid one
emailchk = InStr(1, smtprecipient, "#company_domain.co.uk")
'get a valid email address if the check fails
If emailchk = 0 Then
smtprecipient = InputBox("Enter your Company Email Address", "Email Address Required")
End If
Set OLNS = olApp.GetNamespace("MAPI")
OLNS.Logon
Dim objRec As Outlook.Recipient
Set objRec = OLNS.CreateRecipient(smtprecipient)
objRec.Resolve
Set myCalendar = OLNS.GetSharedDefaultFolder(objRec, olFolderCalendar).Folders("Frontline")
Set OLAppointment = myCalendar.Items.Add(olAppointmentItem)
Dim i As Long, Schedsht As Worksheet
Set Schedsht = Worksheets("Shift Allocation")
Sheets("Shift Allocation").Select
For i = 6 To Range("A" & Rows.Count).End(xlUp).Row
If Schedsht.Range("T" & i).Value = "" And Schedsht.Range("S" & i).Value = True Then
datenum = Date + (Time * 10000) + i
MeetingKeyString = Schedsht.Range("Z" & i).Value
MeetingKey = "S" & CStr(datenum) & Schedsht.Range("B" & i).Value
With OLAppointment
.Subject = "Shift" & " (" & MeetingKey & ")"
.RequiredAttendees = Schedsht.Range("I" & i).Value & ";" & Schedsht.Range("J" & i).Value _
& ";" & Schedsht.Range("K" & i).Value
.Start = Schedsht.Range("D" & i).Value
.End = Schedsht.Range("E" & i).Value
.Location = Schedsht.Range("C" & i).Value
.ReminderMinutesBeforeStart = 720
.MeetingStatus = olMeeting
.Body = Schedsht.Range("M" & i).Value & vbCrLf & vbCrLf & "Welcome to our new Rota system. For details on how this all works, _
please go to xxxx."
.Display
'.Send
On Error GoTo 0
End With
Schedsht.Range("T" & i).Value = True
Schedsht.Range("Y" & i).Value = MeetingKey
Schedsht.Range("AA" & i).Value = MeetingKeyString
Else
End If
Next i
MsgBox "All Shifts Processed"
Set olAppItem = Nothing
Set olApp = Nothing
Set oFolder = Nothing
Exit Sub
Set olAppItem = Nothing
Set olApp = Nothing
Set oFolder = Nothing
End Sub
See above. changing to .display works OK, .send doesn't
You can not send items from a shared folder explicitly because an incorrect sender will be used. You can use the SentOnBehalfOfName property for mail items, but not appointments, when you need to send items on behalf of another person.
Call the Save method before the Send one to submit the item from a shared folder.

VBA Outlook does not generate new mailitem from this code

When I go to sent emails with the code below it sends a previous version of the email. It doesn't reset.
Private Sub CommandButton16_Click()
Dim EmailApp As Outlook.Application
Dim EmailItem As Outlook.MailItem
Set EmailApp = New Outlook.Application
Dim EmailAddress As String
Dim EmpName As String
Dim ProvName As String
Dim PayMonth As String
Dim Filename As String
Dim Filepath As String
Dim FileExists As String
Dim Subject As String
Dim Source As String
Dim AltEmail As String
Dim ExtraMsg As String
Dim i As Long
'Loop through and get email address and names
i = 2
PayMonth = TextBox6.Value
AltEmail = TextBox7.Value
ExtraMsg = TextBox8.Value
Do While Worksheets("Provider Template").Cells(i, 1).Value <> ""
ProvName = Worksheets("Provider Template").Cells(i, 1).Value
EmpName = Worksheets("Provider Template").Cells(i, 11).Value
If AltEmail = "" Then EmailAddress = Worksheets("Provider Template").Cells(i, 20).Value Else EmailAddress = AltEmail
Filename = ProvName & " " & PayMonth
Filepath = ThisWorkbook.Path & "\Remittance PDFs\"
Source = Filepath & Filename & ".pdf"
Subject = "Monthly Remittance Advice for" & " " & ProvName & " - " & PayMonth
FileExists = Dir(Source)
If FileExists = "" Then GoTo Lastline Else GoTo SendEmail
SendEmail:
Set EmailItem = EmailApp.CreateItem(olMailItem)
With EmailItem
EmailItem.To = EmailAddress
EmailItem.CC = "******************"
EmailItem.Subject = Subject
EmailItem.HTMLBody = "<html><body><p>Here is the tax invoice and calculation sheet for " & ProvName & ".</p><p>" & ExtraMsg & "</p><p>Kind regards, ******</p><p>****** ******</p><p>Practice Manager</p></body></html>"
EmailItem.Attachments.Add Source
EmailItem.Send
End With
GoTo Lastline
Lastline:
i = i + 1
Loop
End Sub
I thought it was a problem in the code then I ran it on a different machine and fresh emails were sent. I uploaded the updated version to a work machine and the old emails are going again, like there is a cache of this stuff somewhere.
You can try to check your "Sent" box in outlook next time. It's possible that outlook did'nt sent them (offline or other reason),thety are still there as a draft. That could be the reason that they where sent later.
And adjust:
With EmailItem .To = EmailAddress
And you can leave this out;
GoTo Lastline Lastline:

Send Email Automatically when Triggered

I have found a lot of examples using KuTools, but I don't want this to be interactive, I want the dates in my spreadsheet to trigger an email to be sent.
So the issue I am currently having, is that the Ranges I am trying to fetch are being returned as Nothing, hence, my program doesn't work. Hope someone can help me.
Public Sub sendEmail()
Dim dueDates As Excel.Range
Dim certs As Excel.Range
Dim remainingDays As Long
Dim triggerDate As Long
Set dueDates = ThisWorkbook.Worksheets("worksheetName").Range("D3:D12")
Set certs = ThisWorkbook.Worksheets("worksheetName").Range("C3:C12")
remainingDays = 90
triggerDate = today.AddDays(remainingDays)
Dim toWhom As Excel.Range
Dim subject As String
Dim bodyOpen As String
Dim bodyClose As String
Dim bodyFull As String
Dim mail As Object
Dim outlook As Object
Set toWhom = ThisWorkbook.Worksheets("worksheetName").Range("B16")
subject = "Cert renewal reminder"
bodyOpen = "<HTML><BODY><br>"
bodyClose = "<br></HTML></BODY>"
bodyFull = ""
On Error Resume Next
For Each cell in dueDates
If cell.Value Is Nothing Then Exit Sub (my code is breaking at this line)
If cell.Value <> "" Then
If cell.Value < triggerDate Then
remainingDays = cell.Value - today
bodyFull = bodyOpen + "Certificate " + certs.ActiveCell.row.Value + " will expire in " + remainingDays + " days.<br>Official expiration day = " + cell.Value + ".<br>Please schedule renewal soon<br>" + bodyClose
Set outlook = CreateObject("Outlook.Application")
Set mail = outlook.CreateItem(0)
If toWhom <> "" Then
With mail
.subject = subject
.To = toWhom
.HTMLBody = bodyFull
.Display
.Send
End With
On Error GoTo 0
Set mail = Nothing
End If
End If
End If
End If
Next cell
Set outlook = Nothing
End Sub
This is my first macro, never used VBA before so I may be miss-using types and such things, any advise is taken.

Attach files in batches of 7, change Subject & Body accordingly

The below code attaches one file per email. I need to attach seven files from the folder.
I have approximately 150 files.
I need to
In the first email attach the first 7 files and then loop to attach 7 files to each subsequent email then in the last email attach the remaining three PDF files.
Subject for the first email: Invoice 001 to Invoice 007
Body for First Email:
Please find attached the following invoices
Invoice 001 to Invoice 007 (7 invoices)
...
Subject for the last email: Invoice 148 to Invoice 150
Body for last Email:
Please find attached the following invoices
Invoice 148 to Invoice 150 (3 invoices)
Sub sendmailsss()
Dim path As String
Dim counter As Integer
counter = ThisWorkbook.Worksheets("Sheet").Range("I4")
path = ThisWorkbook.Worksheets("Sheet").Range("M2")
If ThisWorkbook.Worksheets("Sheet").Range("M2") = "" Then
MsgBox "No folder selected. Please Select a folder with Invoives."
Exit Sub
End If
fpath = path & "\*.pdf"
fname = Dir(path)
Dim OutApp As Outlook.Application
Dim Source As String
Dim subj() As String
Do While fname <> ""
subj = Split(fname, ".")
Set OutApp = CreateObject("Outlook.Application")
On Error GoTo 0
Dim OutMail As Outlook.MailItem
Dim OutAccount As Outlook.Account
Set OutAccount = OutApp.Session.Accounts.Item(2)
Set OutMail = OutApp.CreateItem(olMailItem)
Source = path & fname
With OutMail
.To = "info#abc.co.uk"
.Subject = "Company Ltd " & subj(0)
.HTMLBody = "Invoice attached"
.Attachments.Add Source
.SendUsingAccount = OutAccount
'.Display
.Send
End With
If Err Then
MsgBox "Error while sending Email" & vbLf & "Press OK to check it in the Outlook", vbExclamation
'.Display
Else
ms = ms + 1
End If
On Error GoTo 0
Application.Wait Now + #12:00:10 AM#
fname = Dir()
'If ms = 3 Then
' Exit Do
'End If
Loop
MsgBox "Process Completed. " & ms & " emails sent."
End Sub
Here is the re-built code:
Sub SendMailSSS()
Dim path As String
'Dim counter As Integer
Dim outApp As Outlook.Application
Dim outMail As Outlook.MailItem
Dim outAccount As Outlook.Account
Dim source As String
'Dim subj() As String
Dim fPath As String
Dim fName As String
Dim fileList As Variant
Dim innerLoop As Integer
Dim fileCounter As Integer
'counter = ThisWorkbook.Worksheets("Sheet").Range("I4")
path = ThisWorkbook.Worksheets("Sheet1").Range("M2")
If path <> "" Then
fileList = FncGetFilesFromPath(path)
fileCounter = 0
Do While fileCounter < UBound(fileList)
Set outApp = CreateObject("Outlook.Application")
Set outAccount = outApp.Session.Accounts.Item(2)
Set outMail = outApp.CreateItem(olMailItem)
With outMail
.To = "info#abc.co.uk"
.Subject = "Company Ltd " & "Whatever 'subj' array was supposed to be doing in your code"
.HTMLBody = "Invoice attached"
.SendUsingAccount = outAccount
'Gets next up to 7 files
For innerLoop = fileCounter To (fileCounter + 7)
If innerLoop <= UBound(fileList) Then
.Attachments.Add fileList(innerLoop)
Else
Exit For
End If
Next innerLoop
End With
outMail.Send
fileCounter = fileCounter + innerLoop
Loop
Else
MsgBox "No folder selected. Please Select a folder with Invoices."
End If
Set outApp = Nothing
Set outMail = Nothing
Set outAccount = Nothing
End Sub
Private Function FncGetFilesFromPath(fPath As String) As Variant
Dim result As Variant
Dim fName As String
Dim i As Integer
ReDim result(0)
i = 0
fName = Dir(fPath)
Do While fName <> ""
ReDim Preserve result(i)
result(i) = fPath & fName
i = i + 1
fName = Dir()
Loop
FncGetFilesFromPath = result
End Function
You should be able to adapt this into your existing code. What you need to do I think is add all the references to the attachment files to an array first. This will allow you to loop over them according to your specific counting requirements of 7 per e-mail:
Sub SendMailSSS()
Dim path As String
'Dim counter As Integer
Dim outApp As Outlook.Application
Dim outMail As Outlook.MailItem
Dim outAccount As Outlook.Account
Dim source As String
'Dim subj() As String
Dim fPath As String
Dim fName As String
Dim fileList As Variant
Dim innerLoop As Integer
Dim fileCounter As Integer
'counter = ThisWorkbook.Worksheets("Sheet").Range("I4")
path = ThisWorkbook.Worksheets("Sheet1").Range("M2")
If path <> "" Then
fileList = FncGetFilesFromPath(path & "\*.pdf")
fileCounter = 0
Do While fileCounter < UBound(fileList)
Set outApp = CreateObject("Outlook.Application")
Set outAccount = outApp.Session.Accounts.Item(2)
Set outMail = outApp.CreateItem(olMailItem)
With outMail
.To = "info#abc.co.uk"
.Subject = "Company Ltd " & "Whatever 'subj' array was supposed to be doing in your code"
.HTMLBody = "Invoice attached"
.SendUsingAccount = outAccount
'Gets next up to 7 files
For innerLoop = fileCounter To (fileCounter + 7)
If innerLoop <= UBound(fileList) Then
.Attachments.Add fileList(innerLoop)
Else
Exit For
End If
Next innerLoop
End With
outMail.Send
fileCounter = fileCounter + innerLoop
Loop
Else
MsgBox "No folder selected. Please Select a folder with Invoices."
End If
Set outApp = Nothing
Set outMail = Nothing
Set outAccount = Nothing
End Sub
Private Function FncGetFilesFromPath(fPath As String) As Variant
Dim result As Variant
Dim fName As String
Dim i As Integer
ReDim result(0)
i = 0
fName = Dir(fPath)
Do While fName <> ""
ReDim Preserve result(i)
result(i) = fPath & fName
i = i + 1
fName = Dir()
Loop
FncGetFilesFromPath = result
End Function
I'm not sure what "subj" or "counter" are supposed to be doing in your code so I have commented them out. I cannot 100% test this, because I don't have Outlook on this machine, but it should give you the idea of how the looping will work.

Impossible Excel-VBA Email Loop

If someone could help me from going insane, my mother would appreciate it.
I have a long list of email addresses (many repeats) with associated Audit Locations. Basically I need to create one email for each email address and populate said email body with a list of all the associated Audit Locations.
e.g.
Column One (Email Address) | Column 2 (Audit Location)
Yoda1#lightside.org | Coruscant
Yoda1#lightside.org | Death Star
Yoda1#lightside.org | Tatooine
Vader#Darkside.org | Death Star
Vader#Darkside.org | Coruscant
Jarjar#terrible.org | Yavin
So far I have created a CommandButton Controlled vba that takes Column One and makes it unique in a new worksheet.
Then I have another sub that creates an email for each unique email address. But I am stuck on the "If...Then" statement. Essentially, I want to add the information in Column 2 (Audit Location) if the Recipient of the email is the email address in Column One and then continue to append to the email body until the email address no longer equals the recipient email address. Any guidance would be huge.
Private Sub CommandButton1_Click()
Call MakeUnique
Call EmailOut
End Sub
Sub MakeUnique()
Dim vaData As Variant
Dim colUnique As Collection
Dim aOutput() As Variant
Dim i As Long
'Put the data in an array
vaData = Sheet1.Range("A:A").Value
'Create a new collection
Set colUnique = New Collection
'Loop through the data
For i = LBound(vaData, 1) To UBound(vaData, 1)
'Collections can't have duplicate keys, so try to
'add each item to the collection ignoring errors.
'Only unique items will be added
On Error Resume Next
colUnique.Add vaData(i, 1), CStr(vaData(i, 1))
On Error GoTo 0
Next i
'size an array to write out to the sheet
ReDim aOutput(1 To colUnique.Count, 1 To 1)
'Loop through the collection and fill the output array
For i = 1 To colUnique.Count
aOutput(i, 1) = colUnique.Item(i)
Next i
'Write the unique values to column B
Sheets.Add.Name = "Unique"
ActiveSheet.Range("A1").Resize(UBound(aOutput, 1), UBound(aOutput, 2)).Value = aOutput
End Sub
Sub EmailOut()
Dim xOutApp As Object
Dim xOutMail As Object
Dim xMailBody As String
On Error Resume Next
Dim cell As Range
For Each cell In Worksheets("Unique").Columns("a").Cells.SpecialCells(xlCellTypeConstants)
recip = cell.Value
Set xOutApp = CreateObject("Outlook.Application")
Set xOutMail = xOutApp.CreateItem(0)
For Each org In Columns("b").Cells.SpecialCells(xlCellTypeConstants)
If org.Value Like recip Then
xMailBody = "Body content" & vbNewLine & vbNewLine & _
"This is line 1" & " " & cell.Offset(0, 3).Value & vbNewLine & _
[B5] & vbNewLine & _
"This is line 2"
End If
Next org
On Error Resume Next
With xOutMail
.To = recip
.CC = ""
.BCC = ""
.Subject = cell.Offset(0, 2).Value & " " & cell.Offset(0, 3).Value & " " & "Remittance Advice"
.Body = xMailBody
.Display 'or use .Send
End With
On Error GoTo 0
Set xOutMail = Nothing
Set xOutApp = Nothing
Next
End Sub
Based on your example I quickly wrote the following:
Option Explicit
Public Sub SendEmails()
Dim dictEmailData As Object
Dim CurrentWorkBook As Workbook
Dim WrkSht As Worksheet
Dim rngToLookUp As Range
Dim lngLastRow As Long, i As Long
Dim arryEmailData As Variant
Dim objOutlookApp As Object, objOutlookEmail As Object
Dim varKey As Variant
Application.ScreenUpdating = False
Set CurrentWorkBook = Workbooks("SomeWBName")
Set WrkSht = CurrentWorkBook.Worksheets("SomeWSName")
lngLastRow = WrkSht.Cells(WrkSht.Rows.Count, "A").End(xlUp).Row 'Find last row with data
Set rngToLookUp = WrkSht.Range("A2:B" & lngLastRow) 'set range for last row of data
arryEmailData = rngToLookUp.Value2 'Get the email data from the sheet into an array
Set dictEmailData = CreateObject("Scripting.Dictionary") 'set the dicitonary object
On Error GoTo CleanFail
For i = LBound(arryEmailData, 1) To UBound(arryEmailData, 1)
varKey = UCase(Trim(arryEmailData(i, 1)))
If Not dictEmailData.Exists(varKey) Then
dictEmailData(varKey) = vbNewLine & vbNewLine & Trim(arryEmailData(i, 2))
Else
dictEmailData(varKey) = dictEmailData(varKey) & vbNewLine & Trim(arryEmailData(i, 2))
End If
varKey = Empty
Next i
'for each unique key in the dicitonary
'get the corresponding item
'created in the loop above
Set objOutlookApp = CreateObject("Outlook.Application") 'set the outlook object
Dim Msg As String, MailBody As String
For Each varKey In dictEmailData.Keys
Msg = dictEmailData.Item(varKey)
Set objOutlookEmail = objOutlookApp.CreateItem(0)
MailBody = "Dear Colleague," & Msg
With objOutlookEmail
.To = varKey
.Subject = "Remittance Advice"
.Body = MailBody
.Send
End With
Set objOutlookEmail = Nothing
Msg = Empty: MailBody = Empty
Next
MsgBox "All Emails have been sent", vbInformation
CleanExit:
Set objOutlookApp = Nothing
Application.ScreenUpdating = True
Exit Sub
CleanFail:
Resume CleanExit
End Sub
Add the first occurrence of a varKey = email address to the dictionary dictEmailData along with its corresponding item dictEmailData(varKey) = Email body. On the next occurrence of the email address, append to the Email body. Once the dictionary is built, loop through it and send the emails
Printing to the immediate window yields:

Resources