This is code to send emails from an Excel file.
I want to choose the Outlook account from which the emails are sent ("abc#abc.com").
Sub SendEmail()
Dim i As Integer, Mail_Object, Email_Subject, o As Variant, lr As Long
lr = Cells(Rows.Count, "A").End(xlUp).Row
Set Mail_Object = CreateObject("Outlook.Application")
For i = 2 To lr
With Mail_Object.CreateItem(o)
.Subject = Range("B" & i).Value
.To = Range("A" & i).Value
.Body = Range("C" & i).Value
'.CC = Range("G" & i).Value
'.Send
.display 'disable display and enable send to send automatically
End With
Next i
MsgBox "E-mail successfully sent", 64
Application.DisplayAlerts = False
Set Mail_Object = Nothing
End Sub
I think you're after the SentOnBehalfOfName property:
With Mail_Object.CreateItem(o)
.Subject = Range("B" & i).Value
.To = Range("A" & i).Value
.Body = Range("C" & i).Value
.SentOnBehalfOfName = "abc#abc.com"
'.CC = Range("G" & i).Value
'.Send
.display 'disable display and enable send to send automatically
End With
I'm using the below code to tell me when emails have been sent and display the text "sent" so I know there were no errors. But I was testing the code and I use a vlookup to display emails once I add the vendor name. My goal is to not let the macro debug and to let it keep going on to the next but at the same time let me know there was an error on one row either because that vendor did not have an email listed and I need to fill an email in. When I listed the vendors I left a cell blank to test code. Even tho I have valid emails and those emails sent the VBA displays "Not sent" to the ones that were sent out. Since the macro could not find an email due to one cell being blank it debugged and next to all the valid emails the text "Not sent" populates. What am I missing or doing wrong? I just want to avoid debugs to tell me there is an error and just tell me that one row was "not sent" and to just keep sending the rest and populate those that do send with a "sent" text.
Sub Send_Multiple_Emails()
dim sh as worksheet
set sh = thisworkbook.sheets("sheet1") <-- rename to what the tabs name is
dim OA as Object
Dim msg As object
set OA = createobject("Outlook.Application")
Dim i as integer
dim last_row As Integer
last_row = application.worksheetfunction.counta(sh.range("B:B"))
for i = 2 To last_row
Set msg = OA.createitem(0)
msg.to = sh.Range("B" & i).Value
msg.cc = sh.Range("C" & i).Value
msg.subject = sh.range("D" & i ).Value
msg.body = sh.Range("E" & i).Value
if sh.Range("F" & i).Value <> "" Then
msg.attachments.add sh.range("F" & i).Value
End If
msg.send
**If Issent = True Then
Range("G" & i).Value = "Sent"
Else
Range("G" & i).Value = "Not Sent"
End If**
next i
msgbox "Mails Sent"
End Sub
Try replacing of this code part, please:
msg.send
If Issent = True Then
Range("G" & i).Value = "Sent"
Else
Range("G" & i).Value = "Not Sent"
End If
with this one:
Dim Issent As Boolean
On Error Resume Next
msg.send
If Err.Number <> 0 Then
Err.Clear: On Error GoTo 0
Issent = False
Else
On Error GoTo 0
Issent = True
End If
If Issent = True Then
Range("G" & i).Value = "Sent"
Else
Range("G" & i).Value = "Not Sent"
End If
Edited:
I do not think that the above inserted lines can bother your code smooth operation. Even if not this was the question, please try the next adapted code. It also deals with eventual wrong paths to documents to be attached:
Add a reference to Microsoft Outlook ... Object Library. Being in VBE (Visual Basic Editor), go: Tools (menu) -> References... Scroll down until you find the above mentioned reference. Check it and press OK.
Copy the next code instead of yours, or near it (I will change the Sub name) and run it:
Sub Send_Multiple_Emails_bis()
Dim sh As Worksheet, Issent As Boolean, i As Long, last_row As Long
Dim OA As New Outlook.Application, msg As Outlook.MailItem
Set sh = ActiveSheet ' ThisWorkbook.Sheets("sheet1")
last_row = sh.Range("B" & Rows.count).End(xlUp).row
For i = 2 To last_row
Set msg = OA.CreateItem(0)
With msg
.To = sh.Range("B" & i).Value
.cc = sh.Range("C" & i).Value
.Subject = sh.Range("D" & i).Value
.body = sh.Range("E" & i).Value
'.display 'un-comment if you want to see each mail sending window
End With
If sh.Range("F" & i).Value <> "" Then
If Dir(sh.Range("F" & i).Value) <> "" Then
msg.Attachments.aDD sh.Range("F" & i).Value
Else
Range("G" & i).Value = "Wrong attachment path"
GoTo NextMail
End If
End If
On Error Resume Next
msg.send
If Err.Number <> 0 Then
Err.Clear: On Error GoTo 0
Issent = False
Else
On Error GoTo 0
Issent = True
End If
If Issent = True Then
Range("G" & i).Value = "Sent"
Else
Range("G" & i).Value = "Not Sent"
End If
NextMail:
Set msg = Nothing
Next i
MsgBox "Mails Sent"
End Sub
I would like to receive some feedback regarding its behavior...
This VBA code for Excel should take info from specific cells in each row to populate an automated email follow up.
The code moves through each row of the sheet and opens an email draft in Outlook. This is problematic when the sheet has too many lines, Outlook will typically crash.
I tried using various loops but it either breaks the script or causes the draft to reopen forcing me to have to kill Outlook.
Is there a way to have open the draft and wait until the window is either closed or sent before it moves on to the next line?
I am using .Display rather than .Send so that the email drafts can be reviewed, edited, or cancelled prior to send.
Is there something that checks for .Display = True before moving to the new row in Excel?
Sub SendEmails()
Dim OutApp As Object
Dim OutMail As Object
Dim cell As Range
Dim Name As String
Dim FirstName As String
Dim LastName As String
Dim Temp
Application.ScreenUpdating = False
Set OutApp = CreateObject("Outlook.Application")
On Error GoTo cleanup
For Each cell In Columns("W").Cells.SpecialCells(xlCellTypeConstants)
i = cell.Row
Temp = Split(Sheets("Sheet1").Range("P" & i).Value)
FirstName = WorksheetFunction.Proper(Temp(LBound(Temp)))
If Sheets("Sheet1").Range("A" & i).Value = "Yellow" And Sheets("Sheet1").Range("AE" & i).Value = "Red" Then
Set OutMail = OutApp.CreateItem(0)
On Error Resume Next
With OutMail
.To = cell.Value
.subject = "Yellow Red" & Sheets("Sheet1").Range("A" & i).Value & " - " & Sheets("Sheet1").Range("D" & i).Value
.HTMLBody = "<p>Good Afternoon " & FirstName & "," & "</p>" & "<p>Thank you for Yellow.</p>" & "<p> Thanks </p>"
.Display
End With
On Error GoTo 0
Set OutMail = Nothing
End If
If Sheets("Sheet1").Range("A" & i).Value = "Blue" Then
Set OutMail = OutApp.CreateItem(0)
On Error Resume Next
With OutMail
.To = cell.Value
.subject = "Blue" & Sheets("Sheet1").Range("A" & i).Value & " - " & Sheets("Sheet1").Range("D" & i).Value
.HTMLBody = "<p>Good Afternoon " & FirstName & "," & "</p>" & "<p>Thank you for Blue.</p>" & "<p> Thanks </p>"
.Display
End With
On Error GoTo 0
Set OutMail = Nothing
End If
If Sheets("Sheet1").Range("A" & i).Value = "Yellow" And Sheets("Sheet1").Range("AE" & i).Value <> "Red" Then
Set OutMail = OutApp.CreateItem(0)
On Error Resume Next
With OutMail
.To = cell.Value
.subject = "Yellow" & Sheets("Sheet1").Range("A" & i).Value & " - " & Sheets("Sheet1").Range("D" & i).Value
.HTMLBody = "<p>Good Afternoon " & FirstName & "," & "</p>" & "<p>Thank you for Yellow .</p>" & "<p> Thanks </p>"
.Display
End With
On Error GoTo 0
Set OutMail = Nothing
End If
Next cell
cleanup:
Set OutApp = Nothing
Application.ScreenUpdating = True
End Sub
not tested
first of all , sorry for replying with answer, i cannot comment due to not enough rep.
Ok i did some research online on your question, you might want to look into .Display True
It seems adding "True" to the display it makes the pop-up window modal.
being modal puts the loop on hold until you click the send the email.
just wanted to let you know about this , but cant comment.
My sheet 'Volglijst' contains a list with all packages that have been registerd for sending.
When the package is picked up by the supplier or courrier, the goods reception service registers the date and who picked up the package.
When they close the file, a pop-up appears that is asking if they want to send e-mail confirmation to the person who requested the sending.
When they select yes VBA should check all rows in sheet 'Volglijst' where there is a date in Column B and Column Q, and where column S is empty (the 3 conditions should apply at the same time, if not, no e-mail needs to be send).
I'm getting my outlook to start and create a new e-mail, but it remains empty.
The body is working for an other e-mail only the reference to the cell content is adjusted to match the rows for which the conditions apply.
Dim OutApp As Object
Dim OutMail As Object
Dim i As Long
Dim t As Range
Dim WkSht As Worksheet
Dim strbody As String
Set WkSht = Sheets("Volglijst")
For i = 1 To 999
If WkSht.Cells(i, 2).Value <> "" And WkSht.Cells(i, 17).Value <> "" And WkSht.Cells(i, 19).Value = "" Then
Dim rng As Range
With Application.Intersect(WkSht.Rows(i), WkSht.UsedRange)
Set rng = WkSht.Range(WkSht.Cells(i, 3), .Cells(.Cells.Count))
End With
If rng Is Nothing Then
Exit Sub
End If
End If
Next
On Error Resume Next
Set OutApp = CreateObject("Outlook.Application")
Set OutMail = OutApp.CreateItem(0)
strbody = "<font size=""3"" face=""Calibri"">" & _
"Beste Collega,<br><br>" & _
"Uw pakket met nummer <B>" & WkSht.Cells(WkSht.Rows(i), 1).Value & "</B> werd <B>" & WkSht.Cells(WkSht.Rows(i), 17).Value & "</B> opgehaald door <B>" & WkSht.Cells(WkSht.Rows(i), 16).Value & "</B>.<br>" & _
"Bijkomende opmerkingen goederenontvangst: <B>" & WS.Cells(WkSht.Rows(i), 18).Value & "</B>.<br>" & _
"<br><br>In geval van vragen gelieve contact op te nemen." & _
"<br><br> Met vriendelijke groeten, </font>"
On Error Resume Next
With OutMail
.To = WS.Cells(WkSht.Rows(i), 5).Value
.CC = ""
.BCC = ""
.Subject = "Ophaling pakket " & WS.Cells(i, 1).Value & ""
.HTMLBody = strbody
.Display 'or use .Send
End With
A separate email sould be sent for each row with column B <> ""; column Q <> "", Column S = "" , and the recepient is the e-mail adres of column E in that row. Details in the email body should also come from the applicable row.
Will attempt to compartmentalize this, but you have a couple significant issue:
You utilize i in the outlook aspect of this email OUTSIDE of the loop, so you're just using i = 999, or was this intended to be within the loop?
The references in your strbody were to different worksheets... check your references. I called out the first occurrence in the Excel_Activities subroutine when I started defining each use.
Public bdy_a as string, bdy_b as string, bdy_c as string, bdy_d as string
Public to_ as string
Public sub_ as string
'
Sub Excel_Activities()
Dim i as Long, t As Range
Dim WkSht As Worksheet
Dim strbody As String
Set WkSht = Sheets("Volglijst")
For i = 1 To 999
If WkSht.Cells(i, 2).Value <> "" And WkSht.Cells(i, 17).Value <> "" And WkSht.Cells(i, 19).Value = "" Then
Dim rng As Range
With Application.Intersect(WkSht.Rows(i), WkSht.UsedRange)
Set rng = WkSht.Range(WkSht.Cells(i, 3), .Cells(.Cells.Count))
End With
If rng Is Nothing Then
Exit Sub
Else
bdy_a = WkSht.Cells(i, 1).Value
bdy_b = WkSht.Cells(i, 17).Value
bdy_c = WkSht.Cells(i, 16).Value
bdy_d = WS.Cells(i, 18).Value 'IS THIS CORRECT SHEET?
to_ = WS.Cells(WkSht.Rows(i), 5).Value
sub_ = WS.Cells(i, 1).Value
Application.Run("Outlook_Activities")
End If
End If
Next
End Sub
Then deal with the saved values to create the desired email, which appears to occur within the Loop based on the use of i in your original post strbody.
Private Sub Outlook_Activities()
Dim OutApp As Object
Dim OutMail As Object
Set OutApp = CreateObject("Outlook.Application")
Set OutMail = OutApp.CreateItem(0)
strbody = "<font size=""3"" face=""Calibri"">" & "Beste Collega,<br><br>" & "Uw pakket met nummer <B>" & bdy_a & "</B> werd <B>" & bdy_b & "</B> opgehaald door <B>" & bdy_c & "</B>.<br>" & "Bijkomende opmerkingen goederenontvangst: <B>" & & "</B>.<br>" & "<br><br>In geval van vragen gelieve contact op te nemen." & "<br><br> Met vriendelijke groeten, </font>"
With OutMail
.To = to_
.CC = ""
.BCC = ""
.Subject = "Ophaling pakket " & sub_ & ""
.HTMLBody = strbody
.Display 'or use .Send
End With
End Sub
I believe the following is what you are looking for, this will loop from Row 1 to the last in the UsedRange, check whether Columns B & Q are not empty and Column S is empty then deal with the email per row:
Sub LoopThroughRange_SendEmail()
Dim OutApp As Object: Set OutApp = CreateObject("Outlook.Application")
Dim OutMail As Object: Set OutMail = OutApp.CreateItem(0)
Dim i As Long
Dim strbody As String
Dim WkSht As Worksheet: Set WkSht = Sheets("Volglijst")
For i = 1 To WkSht.UsedRange.Rows.Count
If WkSht.Cells(i, "B").Value <> "" And WkSht.Cells(i, "Q").Value <> "" And WkSht.Cells(i, "S").Value = "" Then
strbody = "<html><body><font size=""3"" face=""Calibri"">Beste Collega,<br><br>Uw pakket met nummer <b>" & _
WkSht.Cells(i, "A").Value & "</b> werd <b>" & WkSht.Cells(i, "Q").Value & "</b> opgehaald door <b>" & _
WkSht.Cells(i, "P").Value & "</b>.<br>Bijkomende opmerkingen goederenontvangst: <b>" & _
WkSht.Cells(i, "R").Value & "</B>.<br><br><br>In geval van vragen gelieve contact op te nemen.<br><br>" & _
"Met vriendelijke groeten, </font></body></html>"
With OutMail
.To = WkSht.Cells(i, "E").Value
.CC = ""
.BCC = ""
.Subject = "Ophaling pakket " & WkSht.Cells(i, "A").Value & ""
.HTMLBody = strbody
.Display 'or use .Send
End With
End If
Next i
End Sub
UPDATE:
To also validate the email address before attempting to send the email, the below will help, it will allow multiple email addresses in a single cells separated by a ;
Sub LoopThroughRange_SendEmail()
Dim oRegEx As Object
Set oRegEx = CreateObject("VBScript.RegExp")
Dim OutApp As Object: Set OutApp = CreateObject("Outlook.Application")
Dim OutMail As Object: Set OutMail = OutApp.CreateItem(0)
Dim i As Long
Dim strbody As String
Dim WkSht As Worksheet: Set WkSht = Sheets("Volglijst")
For i = 1 To WkSht.UsedRange.Rows.Count
If ValidEmail(WkSht.Cells(i, "E").Value, oRegEx) Then
If WkSht.Cells(i, "B").Value <> "" And WkSht.Cells(i, "Q").Value <> "" And WkSht.Cells(i, "S").Value = "" Then
strbody = "<html><body><font size=""3"" face=""Calibri"">Beste Collega,<br><br>Uw pakket met nummer <b>" & _
WkSht.Cells(i, "A").Value & "</b> werd <b>" & WkSht.Cells(i, "Q").Value & "</b> opgehaald door <b>" & _
WkSht.Cells(i, "P").Value & "</b>.<br>Bijkomende opmerkingen goederenontvangst: <b>" & _
WkSht.Cells(i, "R").Value & "</B>.<br><br><br>In geval van vragen gelieve contact op te nemen.<br><br>" & _
"Met vriendelijke groeten, </font></body></html>"
With OutMail
.To = WkSht.Cells(i, "E").Value
.CC = ""
.BCC = ""
.Subject = "Ophaling pakket " & WkSht.Cells(i, "A").Value & ""
.HTMLBody = strbody
.Display 'or use .Send
End With
End If
Else
'email address is not valid
End If
Next i
End Sub
Public Function ValidEmail(pAddress As String, ByRef oRegEx As Object) As Boolean
With oRegEx
.Pattern = "^(([a-zA-Z0-9_\-\.\']+)#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)(\s*;\s*|\s*$))+$" 'pattern for multiple email addresses included
ValidEmail = .test(pAddress)
End With
End Function
I am using below code to send email from excel when user press the button. it works fine. i actually want to fine tune this because right now what is happening is when in Column C there is a duplicate email and in column N it is all yes separate emails are generated. what i want to do is if there is a duplicate email in column C one email should be generated with subject and body from the duplicate rows
Dim xOutApp As Object
Dim xOutMail As Object
Dim xMailBody As String
'On Error Resume Next
LastRow = Range("C" & Rows.Count).End(xlUp).Row
For Each Cell In Range("C8:C" & LastRow)
If WorksheetFunction.CountIf(Range("C8:C" & Cell.Row), Cell) = 1 Then
If Cells(Cell.Row, 14) = "Yes" Then
Set xOutApp = CreateObject("Outlook.Application")
Set xOutMail = xOutApp.CreateItem(0)
xMailBody = "Dear " & Cells(Cell.Row, 2) & vbNewLine & vbNewLine & _
Cells(Cell.Row, 7) & " " & Cells(Cell.Row, 6) & vbNewLine & _
"were issue to you for project " & Cells(Cell.Row, 8) & vbNewLine & vbNewLine & vbNewLine & vbNewLine & _
"This is a system generated email and doesn't require signature"
On Error Resume Next
With xOutMail
.To = Cells(Cell.Row, 3)
.CC = Cells(Cell.Row, 5)
.BCC = ""
.Subject = Cells(Cell.Row, 7) & " " & Cells(Cell.Row, 6) & " Issued to " & Cells(Cell.Row, 4)
.Body = xMailBody
'.Attachments.Add ActiveWorkbook.FullName
.Display
End With
On Error GoTo 0
Set xOutMail = Nothing
Set xOutApp = Nothing
End If
End If
Next Cell
You can try:
Option Explicit
Public Sub Get_Unique_Count_Paste_Array()
Dim Ob As Object
Dim rng As Range
Dim LR As Long
Dim str As String
With Worksheets("Sheet1")
LR = .Range("C" & Rows.Count).End(xlUp).Row
Set Ob = CreateObject("scripting.dictionary")
For Each rng In .Range("C8:C" & LR)
str = Trim(rng.Value)
If Len(str) > 0 Then
Ob(str) = Ob(str) + 1
If Ob(str) = 1 Then '<= Check how many times email address appears in the array & if it s appears only one time then..
MsgBox str '<= Insert your code here
End If
End If
Next rng
End With
End Sub