How to send only visible cells in email? - excel

The VBA code below sends email with a specific range in body.
Despite selecting only visible cells, I receive all cells.
It seems SpecialCells(xlCellTypeVisible).Select does not work.
Sub VBA_AUTO_MAIL()
Dim sh As Worksheet
Set sh = ThisWorkbook.Sheets("Arkusz1")
Dim lr As Integer
lr = sh.Range("A" & Application.Rows.Count).End(xlUp).Row
sh.Range("A1:H" & lr).SpecialCells(xlCellTypeVisible).Select
ThisWorkbook.EnvelopeVisible = True
With Selection.Parent.MailEnvelope.Item
.to = sh.Range("L6").Value
.cc = sh.Range("L8").Value
.Subject = sh.Range("L9").Value
.attachments.Add "C:\Users\test\Desktop\TEST VBA\TEST_VBA.txt"
.send
End With
End Sub
I expect only visible columns in email body but I receive all columns.

Try the following
Option Explicit
Sub VBA_AUTO_MAIL()
Dim sh As Worksheet
Set sh = ThisWorkbook.Sheets("Arkusz1")
Dim lr As Long
lr = sh.Range("A" & Application.Rows.Count).End(xlUp).Row
Dim rng As Range
Set rng = sh.Range("A1:H" & lr).SpecialCells(xlCellTypeVisible)
rng.Copy
Dim olApp As Object
Set olApp = CreateObject("Outlook.Application")
Dim Email As Object
Set Email = olApp.CreateItem(0)
Dim wdDoc As Word.Document
Set wdDoc = Email.GetInspector.WordEditor
With Email
.To = sh.Range("L6").Value
.CC = sh.Range("L8").Value
.BCC = ""
.Subject = sh.Range("L9").Value
'.Attachments.Add "C:\Users\test\Desktop\TEST VBA\TEST_VBA.txt"
.Display
wdDoc.Range.PasteAndFormat Type:=wdChartPicture
.Send
End With
End Sub
Make sure to Reference Microsoft Word xx.x Object Library
https://stackoverflow.com/a/42662697/4539709

Related

Send email to each of the mail addresses saved in a column using VBA

I have list of email addresses on column D. I am trying to send mail to each of them using Outlook template (.oft) saved on a path.
It pops up a single email to the last email address on column D.
When I try to debug, it give me "Object variable or With block variable not set (Error 91)".
Sub Sample()
Dim OutApp As Object, OutMail As Object
Dim ws As Worksheet
Dim i As Long, lRow As Long
Dim oEMail As Object
Set OutApp = CreateObject("Outlook.Application")
Set OutMail = OutApp.CreateItemFromTemplate("C:\Users\XXXXX\Desktop\Macro\OutlookTemplate.oft")
Set ws = ThisWorkbook.Sheets("DUFFF")
With ws
lRow = Application.WorksheetFunction.CountA(Columns(4))
For i = 2 To lRow
With OutMail
.To = ws.Range("D" & i).Value
.Subject = "Blah Blah"
.HTMLBody = OutMail.HTMLBody
'.Attachments.Add "C:\Temp\Sample.Txt"
.Display
End With
'On Error GoTo 0
'Set OutApp = Nothing
Next i
End With
End Sub
You are overwriting the .To every loop. Thus, only the last one would be left at the end.
You need to concatenate with ; between the addresses.
Like this:
.To = .To & ";" & ws.Range("D" & i).Value
On help from #Applecore, if it helps anyone, below is the working code to send email to each row from a column using Outlook Template (.oft):
Option Explicit
Sub Sample()
Dim OutApp As Object, OutMail As Object
Dim ws As Worksheet
Dim i As Long, lRow As Long
Dim oEMail As Object
Workbooks("AAA.xlsm").Activate
Worksheets("BBB").Activate
Set ws = ThisWorkbook.Sheets("BBB")
With ws
lRow = Application.WorksheetFunction.CountA(Columns(4))
For i = 2 To lRow
If ws.Range("I" & i).Value = "Yes" Then
Set OutApp = CreateObject("Outlook.Application")
Set OutMail = OutApp.CreateItemFromTemplate("C:\Users\XXXX\Desktop\Macro\ Template.oft")
With OutMail
.To = ws.Range("D" & i).Value
.Subject = "Blah Blah"
.HtmlBody = Replace(OutMail.HtmlBody, "CandiName", ws.Range("B" & i).Value)
'.Attachments.Add "C:\Temp\Sample.Txt"
.Display
End With
End If
Next i
End With
MsgBox ("Mailed Successfully!")
End Sub

Using different e-mail account to send mail

I want to use a Excel macro to send a mail to a company. This mail should consist of a piece of text, a table and then the rest of the text.
In the function below I've compiled some code that works the way I want, but I would like to send the e-mail not from my personal account but from a corporate business account (in the code I refer to the latter as myemailadres#outlook.com). I think I have to use the .SendUsingAccount function, but if I implement it like shown below, the e-mail is send using my personal email account and not the one I specify. Can somebody help?
Sub Test()
Dim rng As Range
Dim OutApp As Object
Dim OutMail As Object
Dim TargetSheet As String
Dim i As Long
Dim StrBodybegin As String
Dim StrBodyend As String
Dim Startcell
Dim TargetRow As Integer
TargetSheet = Range("L24").value 'L24 refers to a name of a company, there is also a sheet in the workbook with the exact same name.
With Application.WorksheetFunction 'this I copied from the code from Ron de Bruijn
Set OutApp = CreateObject("Outlook.Application")
Set OutMail = OutApp.CreateItem(0)
TargetRow = .Match("TOTAAL", ThisWorkbook.Worksheets(TargetSheet).Range("W1:W60"), 0) 'setting range of table I want to copy
Set Startcell = ThisWorkbook.Worksheets(TargetSheet).Range("W15")
Set rng = ThisWorkbook.Worksheets(TargetSheet).Range(Startcell, ThisWorkbook.Worksheets(TargetSheet).Cells(TargetRow + 1, 38))
With Application
.EnableEvents = False
.ScreenUpdating = False
End With
StrBodybegin = "Text 1"
StrBodyend = "Text 2"
On Error Resume Next
With OutMail
.To = ThisWorkbook.Worksheets("Voorblad").Range("L23").value 'L23 refers to email adress
.CC = ""
.BCC = ""
.Subject = "Subject"
.HTMLBody = StrBodybegin & RangetoHTML(rng) & StrBodyend 'using the Ron de Bruin function RangetoHTML to copy in the table defined by the rng
.SendUsingAccount = OutApp.Session.Accounts("myemailadres#outlook.com") 'the line that does not work :(
.Send
End With
On Error GoTo 0
With Application
.EnableEvents = True
.ScreenUpdating = True
End With
Set OutMail = Nothing
Set OutApp = Nothing
End With
End Sub
You can use the property .SentOnBehalfOfName = "user#domain" if you have access to that mailbox or user or whatever. Even if it's not added to your outlook, like this:
Option Explicit
Sub Test()
Dim rng As Range
Dim OutApp As Object
Dim OutMail As Object
Dim TargetSheet As String
Dim i As Long
Dim StrBodybegin As String
Dim StrBodyend As String
Dim Startcell
Dim TargetRow As Integer
TargetSheet = Range("L24").Value 'L24 refers to a name of a company, there is also a sheet in the workbook with the exact same name.
With Application.WorksheetFunction 'this I copied from the code from Ron de Bruijn
Set OutApp = CreateObject("Outlook.Application")
Set OutMail = OutApp.CreateItem(0)
TargetRow = .Match("TOTAAL", ThisWorkbook.Worksheets(TargetSheet).Range("W1:W60"), 0) 'setting range of table I want to copy
Set Startcell = ThisWorkbook.Worksheets(TargetSheet).Range("W15")
Set rng = ThisWorkbook.Worksheets(TargetSheet).Range(Startcell, ThisWorkbook.Worksheets(TargetSheet).Cells(TargetRow + 1, 38))
With Application
.EnableEvents = False
.ScreenUpdating = False
End With
StrBodybegin = "Text 1"
StrBodyend = "Text 2"
On Error Resume Next
With OutMail
.SentOnBehalfOfName = "user#domain"
.To = ThisWorkbook.Worksheets("Voorblad").Range("L23").Value 'L23 refers to email adress
.CC = ""
.BCC = ""
.Subject = "Subject"
.HTMLBody = StrBodybegin & RangetoHTML(rng) & StrBodyend 'using the Ron de Bruin function RangetoHTML to copy in the table defined by the rng
.SendUsingAccount = OutApp.Session.Accounts("myemailadres#outlook.com") 'the line that does not work :(
.Send
End With
On Error GoTo 0
With Application
.EnableEvents = True
.ScreenUpdating = True
End With
Set OutMail = Nothing
Set OutApp = Nothing
End With
End Sub
Try, please:
.SendUsingAccount = outApp.GetNamespace("MAPI").accounts.Item("myemailadres#outlook.com")
And, when you try debugging, it is recommended to comment the line On Error Resume Next. You can not see where and what error appears. In fact, it should not exist at all, if everything is correct..
Find your account loop through accounts.
Dim outApp As object, outNS as object
Dim accounts As object, account As object, myAccount As object
set outApp =createobject("outlook.application")
set outNS = outApp.GetNamespace("MAPI")
Set accounts = outNS.Accounts
For Each account in accounts
if account.SmtpAddress = "myemailadrs#outlook.com" then
set myAccount = account
Exit For
end if
Next account
With outApp.CreateItem(0)
.to = "someone#abc.com"
'...
Set .SendUsingAccount = myAccount
'....
End With

Sending multiple email using range with attachment in VBA

This is the first time I am trying from Excel to send email using VBA code.
Here is my structure of my Excel. Sometimes the email list will have 1 - 20 or only 1 also
A (col) B C D E F G
Sl.No First Name To Email CC Email Subj File to Send Message
Code:
Option Explicit
Sub SendMail()
Dim objOutlook As Object
Dim objMail As Object
Dim rngTo As Range
Dim rngSubject As Range
Dim rngBody As Range
Dim rngAttach As Range
Set objOutlook = CreateObject("Outlook.Application")
Set objMail = objOutlook.CreateItem(0)
With ActiveSheet
Set rngTo = .Range("C2")
Set rngSubject = .Range("E2")
Set rngBody = .Range("G2")
Set rngAttach = .Range("F2")
End With
With objMail
.To = rngTo.Value
.Subject = rngSubject.Value
.Body = rngBody.Value
.Attachments.Add rngAttach.Value
.Display
End With
Set objOutlook = Nothing
Set objMail = Nothing
Set rngTo = Nothing
Set rngSubject = Nothing
Set rngBody = Nothing
Set rngAttach = Nothing
End Sub
Here is my code this was working perfectly fine but for single emails to send, but not for multiple email.
I am struggling here to find how to send for multiple email with attachment using the tested code.
Maybe Try this:
Option Explicit
Sub SendMail()
Dim objOutlook As Object
Dim objMail As Object
Dim rngTo As Range
Dim rngSubject As Range
Dim rngBody As Range
Dim rngAttach As Range
Dim i As Integer
Set objOutlook = CreateObject("Outlook.Application")
For i = 2 To 21 ' Loop from 2 to 21
With ActiveSheet
Set rngTo = .Range("C" & i)
Set rngSubject = .Range("E" & i)
Set rngBody = .Range("G" & i)
Set rngAttach = .Range("F" & i)
End With
Set objMail = objOutlook.CreateItem(0)
With objMail
.To = rngTo.Value
.Subject = rngSubject.Value
.HTMLBody = "<B><U>" & rngBody.Value & ":</B></U>"
.Attachments.Add rngAttach.Value
.Display
End With
Set objMail = Nothing
Next
Set objOutlook = Nothing
Set rngTo = Nothing
Set rngSubject = Nothing
Set rngBody = Nothing
Set rngAttach = Nothing
End Sub
You can loop through the Range to generate 20 emails.
Update
Added .HTMLBody instead of .Body to make text Bold And Underlined
You can use more HTML commands to make certain portions of the Text Bold and More.
Try it this way.
Make a list in Sheets("Sheet1") with :
In column A : Names of the people
In column B : E-mail addresses
In column C:Z : Filenames like this C:\Data\Book2.xls (don't have to be Excel files)
The Macro will loop through each row in "Sheet1" and if there is a E-mail address in column B
and file name(s) in column C:Z it will create a mail with this information and send it.
Sub Send_Files()
'Working in Excel 2000-2016
'For Tips see: http://www.rondebruin.nl/win/winmail/Outlook/tips.htm
Dim OutApp As Object
Dim OutMail As Object
Dim sh As Worksheet
Dim cell As Range
Dim FileCell As Range
Dim rng As Range
With Application
.EnableEvents = False
.ScreenUpdating = False
End With
Set sh = Sheets("Sheet1")
Set OutApp = CreateObject("Outlook.Application")
For Each cell In sh.Columns("B").Cells.SpecialCells(xlCellTypeConstants)
'Enter the path/file names in the C:Z column in each row
Set rng = sh.Cells(cell.Row, 1).Range("C1:Z1")
If cell.Value Like "?*#?*.?*" And _
Application.WorksheetFunction.CountA(rng) > 0 Then
Set OutMail = OutApp.CreateItem(0)
With OutMail
.to = cell.Value
.Subject = "Testfile"
.Body = "Hi " & cell.Offset(0, -1).Value
For Each FileCell In rng.SpecialCells(xlCellTypeConstants)
If Trim(FileCell) <> "" Then
If Dir(FileCell.Value) <> "" Then
.Attachments.Add FileCell.Value
End If
End If
Next FileCell
.Send 'Or use .Display
End With
Set OutMail = Nothing
End If
Next cell
Set OutApp = Nothing
With Application
.EnableEvents = True
.ScreenUpdating = True
End With
End Sub
https://www.rondebruin.nl/win/s1/outlook/amail6.htm
You need a loop for that. The below code will start with the second row and continue until it finds an empty row.
Option Explicit
Sub SendMail()
Dim objOutlook As Object
Dim objMail As Object
Dim rngTo As Range
Dim rngSubject As Range
Dim rngBody As Range
Dim rngAttach As Range
Set objOutlook = CreateObject("Outlook.Application")
Dim r As Long: For r = 2 To ActiveSheet.Range("C2").End(xlDown).Row
With ActiveSheet
Set rngTo = .Range("C" & r)
Set rngSubject = .Range("E" & r)
Set rngBody = .Range("G" & r)
Set rngAttach = .Range("F" & r)
End With
Set objMail = objOutlook.CreateItem(0)
With objMail
.to = rngTo.Value
.Subject = rngSubject.Value
.Body = rngBody.Value
.Attachments.Add rngAttach.Value
.Display
.Send ' If you want to send it without clicking
End With
Next
End Sub
Also note: These Set x = Nothing lines are superfluous, delete them because they just make the code less readable for humans. Regarding this issue you can also refer to this SO question: Is there a need to set Objects to Nothing inside VBA Functions
Update
Sorry this line has to be inside the loop, I updated the code:
Set objMail = objOutlook.CreateItem(0)

Copying a template from Excel to Outlook

I have a template that is stationed in an excel file. Once I click the preview button, this template will be displayed in outlook as well as its subject, to and etc.
I have this code that works fine but is not working in the body field.
Sub previewMail()
Dim objMail, objOutLook As Object
Dim rngTo, rngCC, rngBCC, rngBody As Range
Dim lRow As Long
Dim i As Integer
Set objOutLook = CreateObject("Outlook.Application")
Set objMail = objOutLook.CreateItem(0)
Set main = ThisWorkbook.Sheets("Main")
lRow = main.Cells(Rows.Count, 2).End(xlUp).Row
For i = 11 To lRow
With main
Set rngTo = .Range("B" & i)
Set rngBody = .Range(.Range("C10:N30"), .Range("C10:N30"))
End With
With objMail
.To = rngTo.Value
.Subject = "Sample"
'i like the rngbody to be here
.HTMLBody = RangetoHTML(rngBody)' from Ron de Bruin site
.Display
End With
Next i
End Sub
This is the template stationed in the said range above.
Can anyone please help me figure this out? I have tried this from Ron de Bruin but I can't make it work. This only gives a product that is an "invisible table".
EDIT: OP has indicated text is not in range, but in a textbox in front of range.
Use this code to find the textbox name:
for i = 1 to activesheet.chartobjects.count
debug.print chartobjects(i).name
next i
It will be like Textbox1 or something, then use(untested):
dim strBody as string
Set strBody = activesheet.chartobjects("Textbox1").Value
.HTMLBody = strbody
Try Range.PasteAndFormat wdChartPicture
Example
Option Explicit
Sub previewMail()
Dim objMail, Main, objOutLook As Object
Dim rngTo, rngCC, rngBCC, rngBody As Range
Dim lRow As Long
Dim i As Integer
Dim wordDoc As Word.Document '<---
Set objOutLook = CreateObject("Outlook.Application")
Set objMail = objOutLook.CreateItem(0)
Set Main = ThisWorkbook.Sheets("Main")
Set wordDoc = objMail.GetInspector.WordEditor '<---
lRow = Main.Cells(Rows.count, 2).End(xlUp).Row
For i = 11 To lRow
With Main
Set rngTo = .Range("B" & i)
Set rngBody = .Range(.Range("C10:N30"), .Range("C10:N30"))
rngBody.Copy '<---
End With
With objMail
.To = rngTo.Value
.Subject = "Sample"
.Display
wordDoc.Range.PasteAndFormat wdChartPicture '<---
' Or
'wordDoc.Range.PasteAndFormat wdChartPicture & .HTMLBody = " "
End With
Next i
End Sub
Make sure to set references to the Microsoft Outlook and Microsoft Word Object libraries
Tools > References...

Email a single attachment from folder of files each to a different person

I have a folder with 50 files and I have a list of 50 email addresses. Each file goes to a different email address. Is there a way to write a macro that performs this task?
The problem with the set of code below is two-fold:
1) I have 3 COLUMNS of data in an Excel file: One for subject, one for email address to send to, and the third for the FILE PATH of where the attachment to be attached is stored.
The code below does not allow for a pre-determined set of subject arguments. It also uses ROWS?? for the filepath field instead of a column like it does for send to? So confusing.
Sub Send_Files()
Dim OutApp As Object
Dim OutMail As Object
Dim sh As Worksheet
Dim cell As Range
Dim FileCell As Range
Dim rng As Range
With Application
.EnableEvents = False
.ScreenUpdating = False
End With
Set sh = Sheets("Sheet1")
Set OutApp = CreateObject("Outlook.Application")
For Each cell In sh.Columns("B").Cells.SpecialCells(xlCellTypeConstants)
'Enter the path/file names in the C:Z column in each row
Set rng = sh.Cells(cell.Row, 1).Range("C1:Z1")
If cell.Value Like "?*#?*.?*" And _
Application.WorksheetFunction.CountA(rng) > 0 Then
Set OutMail = OutApp.CreateItem(0)
With OutMail
.to = cell.Value
.Subject = "Testfile"
.Body = "Hi " & cell.Offset(0, -1).Value
For Each FileCell In rng.SpecialCells(xlCellTypeConstants)
If Trim(FileCell) <> "" Then
If Dir(FileCell.Value) <> "" Then
.Attachments.Add FileCell.Value
End If
End If
Next FileCell
.Send 'Or use .Display
End With
Set OutMail = Nothing
End If
Next cell
Set OutApp = Nothing
With Application
.EnableEvents = True
.ScreenUpdating = True
End With
End Sub
Here is quick example, assuming col A = Email, Col B = Subject & Col C = Path
Option Explicit
Public Sub Example()
Dim olApp As Object
Dim olMail As Object
Dim olRecip As Object
Dim olAtmt As Object
Dim iRow As Long
Dim Recip As String
Dim Subject As String
Dim Atmt As String
iRow = 2
Set olApp = CreateObject("Outlook.Application")
Dim Sht As Worksheet
Set Sht = ThisWorkbook.Worksheets("Sheet1")
Do Until IsEmpty(Sht.Cells(iRow, 1))
Recip = Sht.Cells(iRow, 1).Value
Subject = Sht.Cells(iRow, 2).Value
Atmt = Sht.Cells(iRow, 3).Value ' Attachment Path
Set olMail = olApp.CreateItem(0)
With olMail
Set olRecip = .Recipients.Add(Recip)
.Subject = Subject
.Body = "Hi "
.Display
Set olAtmt = .Attachments.Add(Atmt)
olRecip.Resolve
End With
iRow = iRow + 1
Loop
Set olApp = Nothing
End Sub

Resources