How to attach a variable number of attachments? - vba

The below code is an auto email sender. It works only if there are attachments.
Some emails have 1 or more attachments. If the path is blank it will not work.
Each email has a variable number of attachments and some paths is empty. Is there any way to make the pdfadd1 to pdfadd5 ignore adding attachment if the path is empty?
Sub send_mass_email_display_only()
Dim i As Integer
Dim name As String, email As String, body As String, subject As String, copy As String, pdfadd1 As String, pdfadd2 As String, pdfadd3 As String, pdfadd4 As String, pdfadd5 As String
Dim OutApp As Object
Dim OutMail As Object
body = ActiveSheet.TextBoxes("TextBox 1").Text
For i = 2 To 3
'Specific rows
name = Split(Cells(i, 1).Value, " ")(0)
'name = Cells(i, 1).Value
email = Cells(i, 2).Value
subject = Cells(i, 3).Value
copy = Cells(i, 4).Value
pdfadd1 = Cells(i, 5).Value
pdfadd2 = Cells(i, 6).Value
'pdfadd3 = Cells(i, 7).Value
'pdfadd4 = Cells(i, 8).Value
'pdfadd5 = Cells(i, 9).Value
body = Replace(body, "C1", name)
Set OutApp = CreateObject("Outlook.Application")
Set OutMail = OutApp.CreateItem(0)
With OutMail
.SentOnBehalfOfName = Cells(7, 17).Value
.To = email
.cc = copy
.subject = subject
.body = body
.Attachments.Add (pdfadd1)
.Attachments.Add (pdfadd2)
'.Attachments.Add (pdfadd3)
'.Attachments.Add (pdfadd4)
'.Attachments.Add (pdfadd5)
.display
'.Send
End With
body = ActiveSheet.TextBoxes("TextBox 1").Text 'reset body text
Next i
Set OutMail = Nothing
Set OutApp = Nothing
'MsgBox "Email(s) Sent!"
End Sub

Here is the relevant part. I just added an If statement to each one to make sure the length is greater than zero.
.body = body
If Len(pdfadd1) > 0 Then .Attachments.Add pdfadd1
If Len(pdfadd2) > 0 Then .Attachments.Add pdfadd2
If Len(pdfadd3) > 0 Then .Attachments.Add pdfadd3
If Len(pdfadd4) > 0 Then .Attachments.Add pdfadd4
If Len(pdfadd5) > 0 Then .Attachments.Add pdfadd5
.display
Also, you do not need the parenthesis around the argument for .Add in this case as it's not returning anything.

Related

Sending an automatic email based on cell value

I have this code that I have cobbled together but, sadly I am stuck I can’t seem to work out how to only have the email addresses for overdue entries in the BCC.
I want it to create a single email to multiple email addresses from a list of emails that have a due date that is overdue and a previous email hasn't already been sent.
Sub Over_due()
Dim OutApp As Object
Dim OutMail As Object
Dim lLastRow As Long
Dim lRow As Long
Dim rng As Range
strbody = "Text goes here"
lLastRow = Cells(Rows.Count, 3).End(xlUp).Row
For lRow = 2 To lLastRow
If Cells(lRow, 6) <> "Email Sent" Then
If Cells(lRow, 5) <= Date Then
Set xOutlook = CreateObject("Outlook.Application")
Set xMailItem = xOutlook.CreateItem(0)
For Each rng In Range("C:C")
If rng.Value Like "*#*" Then
If xEmailAddr = "" Then
xEmailAddr = rng.Value
Else
xEmailAddr = xEmailAddr & ";" & rng.Value
End If
End If
Next
On Error Resume Next
With xMailItem
.To = ""
.CC = ""
.BCC = xEmailAddr
.Subject = Range("A1").Value
.HTMLBody = strbody
'.Attachments.Add
.Display
End With
MsgBox "E-mail successfully created", 64
Application.DisplayAlerts = False
Set Mail_Object = Nothing
Cells(lRow, 6) = "Sent email"
Cells(lRow, 7) = "" & Now()
End If
End If
Next
Set OutApp = Nothing
End Sub
I use a sub which automatically creates emails. and call it from various other subs - might come in handy:
Sub SendEmail(Optional ToAddresses As String, Optional CcAddresses As String, _
Optional BccAddresses As String, Optional Subject As String, _
Optional Body As String, Optional AttachFiles As Variant = False, Optional AutoSend As Boolean = False)
'RULES:
' Where there are multiple Addresses in ToAddresses, CCAddresses
' etc, they have to be separated by a semicolon
' AttachFiles should either be a string containing the full
' filename including the path, or (for multiple files) an array
' of same.
' Body can be HTML or just plain text.
Dim OutApp As Object
Dim OutMail As Object
Set OutApp = CreateObject("Outlook.Application")
Set OutMail = OutApp.CreateItem(0)
With OutMail
.to = ToAddresses
.CC = CcAddresses
.Bcc = BccAddresses
.Subject = Subject
If Body Like "*</*>*" Then
.HtmlBody = Body
Else
.Body = Body
End If
If Not AttachFiles = False Then
If IsArray(AttachFiles) Then
For x = LBound(AttachFiles) To UBound(AttachFiles)
.Attachments.Add (AttachFiles(x))
Next
Else
.Attachments.Add (AttachFiles)
End If
End If
If AutoSend = True Then
.Send
Else
.Display
End If
End With
Set OutMail = Nothing
Set OutApp = Nothing
End Sub
It's not totally my code, I adapted it from here.
It won't completely solve your problem, but it might condense it down to something simpler and more like:
Sub OverDue()
Dim strBody as String
Dim Row as Long
Dim lLastRow as Long
StrBody = "Text here"
lLastRow = UsedRange.Rows.Count
For a = 2 to lLastRow
If Cells(a, 6) <> "Email Sent" And Cells(a, 5)<= Date Then 'This checks each row to see if that person needs an email
' DO STUFF HERE
' Either Call the other sub separately each time
' (which can allow for more personalised messages, like a mail merge),
' or add the person's email address to a string and call the sub
' after the loop.
Next
End Sub
Over to you to work out the rest of the details though!!
I fixed your code like that
Sub Over_due()
Dim OutApp As Object
Dim OutMail As Object
Dim lLastRow As Long
Dim lRow As Long
Dim rng As Range
Dim strbody As String
Dim xOutlook
Dim xMailItem
Dim xEmailAddr
strbody = "Text goes here"
lLastRow = Cells(Rows.Count, 3).End(xlUp).Row
For lRow = 2 To lLastRow
If Cells(lRow, 6) <> "Email Sent" Then
If Cells(lRow, 5) <= Date Then
Set xOutlook = CreateObject("Outlook.Application")
Set xMailItem = xOutlook.CreateItem(0)
' For Each rng In Range("C:C")
' If rng.Value Like "*#*" Then
' If xEmailAddr = "" Then
' xEmailAddr = rng.Value
' Else
' xEmailAddr = xEmailAddr & ";" & rng.Value
' End If
' End If
' Next
'Do you really want to have all emails addresses in BCC because thats what you are doing
'I changed the above code to the following lines which will not take the complete column
Set rng = Range("C2:C" & lRow)
xEmailAddr = Join(WorksheetFunction.Transpose(rng), ",")
On Error Resume Next
With xMailItem
.To = ""
.CC = ""
.BCC = xEmailAddr
.Subject = Range("A1").Value
.HTMLBody = strbody
'.Attachments.Add
.Display
End With
MsgBox "E-mail successfully created", 64
Application.DisplayAlerts = False
' I changed that to Email Sent otherwise it will create the mai over and over again
Cells(lRow, 6) = "Email Sent"
Cells(lRow, 7) = "" & Now()
End If
End If
Next
Set OutApp = Nothing
End Sub

Send automated mails from excel with envelope

I have created this macro to send automatically mails via outlook! My macro runs but there is an issue. Instead of sending in the content of the mail only the value of the offset that I ask for, it sends the entire worksheet. I am providing the code below:
Dim ToArray As String
Dim CCArray As String
Dim Subject As String
Dim Content As String
Dim cell3 As Range
For Each cell3 In ws1.Range("D2:D" & lastrow1)
ToArray = cell3.Offset(0, 16).Value
CCArray = cell3.Offset(0, 17).Value
Subject = cell3.Offset(0, 18).Value
Content = cell3.Offset(0, 19).Value
ActiveWorkbook.EnvelopeVisible = True
With ws1.MailEnvelope
.Introduction = Content
.Item.To = ToArray
.Item.CC = CCArray
.Item.Subject = Subject
.Item.Send
End With
Application.DisplayAlerts = False
Next cell3
I think you should try to use that:
Set Mail_Object = CreateObject("Outlook.Application")
Set Mail_Single = Mail_Object.CreateItem(0)
With Mail_Single
.Subject = Subject
.To = "email#address.com"
.cc = "email#address.com"
.BCC = "email#address.com"
.SentOnBehalfOfName = "email#address.com"
.HTMLBody = Content
.send
End With
Hope that helps...

Mails with attachments through vba macro

I am running a macro for sending mails to multiple recipients via Outlook with one or more attachments through vba excel. I am not well versed in macros and hence took some inputs from various sources and came upon the below final code.
However I have mentioned max. limit of 3 file attachments which is constant for all recipients but have to disable by commenting whenever I have to attach only 1 or 2 files accordingly like e.g in the below code I have disabled the 2nd and 3rd attachment columns for attaching 1 file across.
Is there any way where the macro would automatically take the inputs according to the values entered and left blank e.g If one recipient has 1 attachment and the next recipient has 2 or 3 attachments
Sub SendMail()
Dim objOutlook As Object
Dim objMail As Object
Dim ws As Worksheet
Set objOutlook = CreateObject("Outlook.Application")
Set ws = ActiveSheet
For Each cell In ws.Range("A2:A1000")
Set objMail = objOutlook.CreateItem(0)
With objMail
.To = cell.Value
.Cc = cell.Offset(0, 1).Value
.Bcc = cell.Offset(0, 2).Value
.Subject = cell.Offset(0, 3).Value
.Body = cell.Offset(0, 4).Value
.Attachments.Add cell.Offset(0, 5).Value
'.Attachments.Add cell.Offset(0, 6).Value
'.Attachments.Add cell.Offset(0, 7).Value
.Send
End With
Set objMail = Nothing
Next cell
Set ws = Nothing
Set objOutlook = Nothing
End Sub
Dim i As Long, c As Range
'....
With objMail
.To = cell.Value
.Cc = cell.Offset(0, 1).Value
.Bcc = cell.Offset(0, 2).Value
.Subject = cell.Offset(0, 3).Value
.Body = cell.Offset(0, 4).Value
For i = 5 to 6
Set c = cell.Offset(0, i)
If c.Value <> "" Then .Attachments.Add c.Value
Next i
.Send
End With
'....

VBA send email from excel (depending on condition)

I am an absolute beginner and try to facilitate a few tasks in my colleagues daily work. I want to create a code that sends reminder mails with information from an excel file. The idea is that Excel should check every relevant row from row 12 on and check if there is an "x" written in a column that marks for which row I would like to send a reminder.
With the code below I can generate all the emails, but I have difficulties where and how to include the check for if ('If Cells(s, 6).Value = "x" Then') so that that Excel continues through all the rows that are filled out.
Many thanks for your help!
Sub SendReminderMail()
Dim s As Long
Dim OutLookApp As Object
Dim OutLookMailItem As Object
Dim iCounter As Integer
Dim MailDest As String
If MsgBox("Are you sure?", vbYesNo) = vbNo Then Exit Sub
Set OutLookApp = CreateObject("Outlook.application")
Set OutLookMailItem = OutLookApp.CreateItem(0)
s = 12
Do Until Trim$(Cells(s, 1).Value) = ""
Set OutLookMailItem = OutLookApp.CreateItem(0)
With OutLookMailItem
.To = Cells(s, 5).Value
.Subject = "Reminder: " & Cells(1, 7).Value
.Body = "Text, " & vbCrLf & vbCrLf & "Text'" & Cells(s, 2).Value
s = s + 1
.Display
End With
Loop
End Sub
Since you are checking every row with the Do...Loop then you need to check the if inside that loop. I've moved the increment to s outside the If so that it happens whether or not you create a mail item. Otherwise you'd only change rows if there was a mail item to send, and that means you'd be stuck looping on a row where there was no "x".
Sub SendReminderMail()
Dim s As Long
Dim OutLookApp As Object
Dim OutLookMailItem As Object
Dim iCounter As Integer
Dim MailDest As String
If MsgBox("Are you sure?", vbYesNo) = vbNo Then Exit Sub
Set OutLookApp = CreateObject("Outlook.application")
Set OutLookMailItem = OutLookApp.CreateItem(0)
s = 12
Do Until Trim$(Cells(s, 1).Value) = ""
If Cells(s,6).Value = "x" Then
Set OutLookMailItem = OutLookApp.CreateItem(0)
With OutLookMailItem
.To = Cells(s, 5).Value
.Subject = "Reminder: " & Cells(1, 7).Value
.Body = "Text, " & vbCrLf & vbCrLf & "Text'" & Cells(s, 2).Value
.Display
End With
End If
s = s + 1
Loop
End Sub

Adding multiple attachments where number of attachments varies

I am sending emails out to approximately 150 individuals, each email may have between 1 and 3 attachments.
I can send emails out just fine with one attachment...getting multiple attachments is difficult.
Lets say the attachment file path is located in A1 through C1.
How can I Perform.
If A1 is empty, go to Send, if not, attach file
If B1 is empty, go to Send, if not, attach file
If C1 is empty, go to Send, if not, attach file
Send:
This is the code I have currently: I realize my ranges are different than what I posted above. The following script works...its just for the one attachment however.
Set rngEntries = ActiveSheet.Range("b5:b172")
For Each rngEntry In rngEntries
Set objMail = objOutlook.CreateItem(0)
With objMail
.To = rngEntry.Offset(0, 11).Value
.Subject = rngEntry.Offset(0, 8).Value
.Body = rngEntry.Offset(0, 10).Value
.Attachments.Add rngEntry.Offset(0, 9).Value
.send
End With
Next rngEntry
What I want would look a little like this....
Set rngEntries = ActiveSheet.Range("b5:b172")
For Each rngEntry In rngEntries
Set objMail = objOutlook.CreateItem(0)
With objMail
.To = rngEntry.Offset(0, 11).Value
.Subject = rngEntry.Offset(0, 8).Value
.Body = rngEntry.Offset(0, 10).Value
If rngEntry.Offset(0, 1) is empty, goto Send
.Attachments.Add rngEntry.Offset(0, 1).Value
If rngEntry.Offset(0, 2) is empty, goto Send
.Attachments.Add rngEntry.Offset(0, 2).Value
If rngEntry.Offset(0, 3) is empty, goto Send
.Attachments.Add rngEntry.Offset(0, 3).Value
Send:
.send
End With
Next rngEntry
It's always best to avoid GoTo statements in VBA at all costs, because things can get hairy very quickly. Just write this:
If Not IsEmpty(rngEntry.Offset(0, 1)) Then .Attachments.Add rngEntry.Offset(0, 1).Value
If Not IsEmpty(rngEntry.Offset(0, 2)) Then .Attachments.Add rngEntry.Offset(0, 2).Value
If Not ISEmpty(rngEntry.Offset(0, 3)) then .Attachments.Add rngEntry.Offset(0, 3).Value
Additional Info
You may also be interested in a function I built to send emails, which passes attachments as a | separated string values and then splits them into an array to load them. In this way, you can send one or more with the same function, plus a few other nifty things.
A few notes: I declared Outlook outside the function in the capacity I was using it, so you'd have to either do the same, or add it into the function. It also uses Early Binding as I use inside other MS Office Products.
Option Explicit
Sub SendMail(strTo As String, strSubject As String, strBody As String, strAttachments As String, Optional strCC As String, Optional strFolder As String, Optional blSend As Boolean)
'requires declaration of Outlook Application outside of sub-routine
'passes file name and folder separately
'strAttachments is a "|" separate listed of attachment paths
Dim olNs As Outlook.Namespace
Dim oMail As Outlook.MailItem
'login to outlook
Set olNs = oApp.GetNamespace("MAPI")
olNs.Logon
'create mail item
Set oMail = oApp.CreateItem(olMailItem)
'display mail to get signature
With oMail
.Display
End With
Dim strSig As String
strSig = oMail.HTMLBody
'build mail and send
With oMail
.To = strTo
.CC = strCC
.Subject = strSubject
.HTMLBody = strBody & strSig
Dim strAttach() As String, x As Integer
strAttach() = Split(strAttachments, "|")
For x = LBound(strAttach()) To UBound(strAttach())
If FileExists(strFolder & strAttach(x)) Then .Attachments.Add strFolder & strAttach(x)
Next
.Display
If blSend Then .Send
End With
Set olNs = Nothing
Set oMail = Nothing
End Sub
Here is the FileExists that checks if the attachment exists before trying to add it:
Function FileExists(sFile As String) As Boolean
'requires reference to Microsoft Scripting RunTime
Dim fso As FileSystemObject
Set fso = CreateObject("Scripting.FileSystemObject")
If fso.FileExists(sFile) Then
FileExists = True
Else
FileExists = False
End If
Set fso = Nothing
End Function