I have created a macro in Outlook VBA below that replies with the sender first name added to the greeting, adds some text for the body, and adds a signature in the fonts I want.
What I need help with is getting the macro to pull ALL of the names of the senders, assigning a value to them that I can then place elsewhere in the body of the email. If that cannot be done, I would settle for just getting all of the names into the greeting, though it is much preferred to be able to move the names around.
Example: sender was Name1;Name2
Currently, this macro will pull only Name1 (giving "Dear Name1,"), but
I would like to get to "Dear Name1 and Name2," at the very least.
Best would be able to have Name1 be in the greeting, then Name2 is placed in the body of the text.
I believe I have taken this as far as I can on my own and now turn to you experts for assistance! Thank you!!
Sub AutoAddGreetingtoReply()
Dim oMail As MailItem
Dim oReply As MailItem
Dim GreetTime As String
Dim strbody As String
Dim SigString As String
Dim Signature As String
Dim R As Outlook.Recipient
Dim strGreetName As String
Select Case Application.ActiveWindow.Class
Case olInspector
Set oMail = ActiveInspector.CurrentItem
Case olExplorer
Set oMail = ActiveExplorer.Selection.Item(1)
End Select
strbody = "<H3><B></B></H3>" & _
"<br><br><B></B>" & _
"Please visit this website to view your transactions.<br>" & _
"Let me know if you have problems.<br>" & _
"Questions" & _
"<br><br>Thank you"
SigString = Environ("appdata") & _
"\Microsoft\Signatures\90 Days.htm"
On Error Resume Next
If Dir(SigString) <> "" Then
strGreetName = Left$(oMail.SenderName, InStr(1, oMail.SenderName, " ") - 1)
End If
If Dir(SigString) <> "" Then
Signature = GetBoiler(SigString)
Else
Signature = ""
End If
Set oReply = oMail.ReplyAll
With oReply
.CC = ""
.HTMLBody = "<Font Face=calibri>Dear " & strGreetName & "," & R1 & strbody & "<br>" & Signature
.Display
End With
End Sub
Given a string "First Last" then get the right side of the string like this
sndrName = oMail.SenderName
lastName = right(sndrName, len(sndrName) - InStr(1, sndrName, " "))
Using the format in your code:
strGreetName = Left$(oMail.SenderName, InStr(1, oMail.SenderName, " ") - 1)
lastName = right(oMail.SenderName, len(oMail.SenderName) - InStr(1, oMail.SenderName, " "))
If there is a space in the text InStr returns the position. https://msdn.microsoft.com/en-us/vba/language-reference-vba/articles/instr-function
Original mail has one sender. A ReplyAll has recipients, including the original mail sender.
Option Explicit
Private Sub ReplyFirstNames()
Dim oMail As mailitem
Dim oReply As mailitem
Dim strGreetName As String
Dim strGreetNameAll As String
Dim i As Long
Select Case Application.ActiveWindow.Class
Case olInspector
Set oMail = ActiveInspector.currentItem
Case olExplorer
Set oMail = ActiveExplorer.Selection.Item(1)
End Select
Set oReply = oMail.ReplyAll
With oReply
Debug.Print "The reply all recipients are:"
For i = 1 To .Recipients.count
Debug.Print .Recipients(i)
' Given the format First Last
strGreetName = Left(.Recipients(i), InStr(1, .Recipients(i), " ") - 1)
strGreetNameAll = strGreetNameAll & strGreetName & ", "
Next i
Debug.Print strGreetNameAll
' remove extra comma and space from end
strGreetNameAll = Left(strGreetNameAll, Len(strGreetNameAll) - 2)
Debug.Print strGreetNameAll
.htmlbody = "<Font Face=calibri>" & strGreetNameAll & .htmlbody
.Display
End With
End Sub
Related
I am trying to create an email and populate multiple recipients based off a listbox.
I tried putting the list box column reference in the ".To" line but it gives a null error.
I found code that should loop through the listbox values but it is not populating any recipients.
Public Sub cmdEmailContact_Click()
Dim appOutLook As Outlook.Application
Dim MailOutLook As Outlook.MailItem
Dim strPath As String
Dim strFilter As String
Dim strFile As String
Dim strFileEnd As String
Dim strEmailRecipients As String
strPath = "C:\Users\username\Desktop\Invoice Test\GCX"
strFilter = Me.txtInvNum
strFileEnd = ".pdf"
strFile = Dir(strPath & strFilter & strFileEnd)
strEmailRecipients = ""
For N = 0 To Me.lstContacts.ListCount - 1
If Me.lstContacts.Selected(N) = True Then
strEmailRecipients = strEmailRecipients & "; " & Me.lstContacts.Column(3, N)
End If
Next N
strEmailRecipients = Mid(strEmailRecipients, 3)
If strFile <> "" Then
Set appOutLook = CreateObject("Outlook.Application")
Set MailOutLook = appOutLook.CreateItem(olMailItem)
With MailOutLook
.BodyFormat = olFormatRichText
.To = strEmailRecipients
''.cc = ""
''.bcc = ""
.Subject = "text here"
.SentOnBehalfOfName = "emailname"
.HTMLBody = "text here"
.Attachments.Add (strPath & strFilter & strFileEnd)
'.Send
.Display
End With
Else
MsgBox "No file matching " & strPath & strFilter & strFileEnd & " found." & vbCrLf & _
"Process has been stopped."
Exit Sub
End If
End Sub
I expect strEmailRecipients to equal a semi-colon separated list of email addresses based off the listbox. There are no error messages.
Rather than building a semi-colon delimited string to populate the To property of the MailItem object, you may instead want to modify the contents of the Recipients collection when adding recipients (independent of the recipient type) to a MailItem object.
Adding an item to the Recipients collection using the Add method will yield a Recipient object, which has a Type property which may be used to designate the recipient as either to, cc, or bcc by setting the property to olTo, olCC, or olBCC (or 1, 2, or 3 if using late binding).
Hence the construction of the email might become something along the lines of the following:
Dim idx
With MailOutLook
With .Recipients
For Each idx In lstContacts.ItemsSelected
With .Add(lstContacts.ItemData(idx))
.Type = olTo
End With
Next idx
End With
.BodyFormat = olFormatRichText
' ... etc.
End With
I need a macro which can match domain name of the email ids in TO and CC from a list of emails(preferably from excel) and if any of the email address does not match, it should throw a pop-up asking if the user wants to continue and if yes then the mail should be sent as it is and a email id should be added in BCC.
Please find the sample code, it works but I also want to compare the domain name as a sub-string in the subject.
Ex: The if the subject line is "ABC Report- Company1- Jan-2 and it is sent to a1#company1.com, a2#compay2.com then it should prompt that the a2#company2.com is an unauthorized email and ask if still the user want to proceed, if Yes it should copy admin#mycompany.com in BCC and delay the mail by 5mins.
Private Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean)
Dim recips As Outlook.Recipients
Dim recip As Outlook.Recipient
Dim pa As Outlook.PropertyAccessor
Dim prompt As String
Dim strMsg As String
Dim Address As String
Dim lLen
Dim strSubject As String
Const PR_SMTP_ADDRESS As String = "http://schemas.microsoft.com/mapi/proptag/0x39FE001E"
strSubject = Item.Subject
If strSubject Like "*ACB Report*" Or strSubject Like "*XYZ Report*" Then
Set recips = Item.Recipients
For Each recip In recips
Set pa = recip.PropertyAccessor
Address = LCase(pa.GetProperty(PR_SMTP_ADDRESS))
lLen = Len(Address) - InStrRev(Address, "#")
Select Case Right(Address, lLen)
Case "cdolive.com", "gmail.com", "slipstick.com", "outlookmvp.com"
Case Else ' remove case else line to be warned when sending to the addresses
strMsg = strMsg & " " & Address & vbNewLine
End Select
Next
If strMsg <> "" Then
prompt = "This email will be sent outside of the company to:" & vbNewLine & strMsg & vbNewLine & "Please check recipient address." & vbNewLine & vbNewLine & "Do you still wish to send?"
If MsgBox(prompt, vbYesNo + vbExclamation + vbMsgBoxSetForeground, "Check Address") = vbNo Then
Cancel = True
End If
End If
End If
End Sub
Private Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean)
Dim recips As Outlook.Recipients
Dim recip As Outlook.Recipient
Dim pa As Outlook.PropertyAccessor
Dim prompt As String
Dim strMsg As String
Dim Address As String
Dim lLen
Dim strSubject As String
Const PR_SMTP_ADDRESS As String = "http://schemas.microsoft.com/mapi/proptag/0x39FE001E"
strSubject = Item.subject
If strSubject Like "*ABC Report*" Or strSubject Like "*XYZ Report*" Then
Set recips = Item.Recipients
For Each recip In recips
If recip.Type <> olBCC Then
Set pa = recip.PropertyAccessor
Address = LCase(pa.GetProperty(PR_SMTP_ADDRESS))
'rlen = Len(Address) - InStrRev(Address, "#")
'If strSubject Like "*rlen*" Then
lLen = Len(Address) - InStrRev(Address, "#")
'Select Case Left(Address, rlen)
'Case "acceture", "slipstick"
'Case Else
'strMsg = strMsg & " " & Address & vbNewLine
'End Select
'Next
Dim SendMail As Boolean
Select Case Right(Address, lLen)
Case "cdolive.com", "slipstick.com", "outlookmvp.com", "accenture.com"
' "select case" is doing nothing in this case
SendMail = True
Case Else ' remove case else line to be warned when sending to the addresses
strMsg = strMsg & " " & Address & vbNewLine
End Select
If strMsg <> "" And Not SubjectContainsEmailDomain(strSubject, Address) Then
prompt = "The system has detected that you are sending this email to some unauthorized user:" & vbNewLine & strMsg & vbNewLine & "Please check recipient address." & vbNewLine & vbNewLine & "Do you still wish to send?"
If MsgBox(prompt, vbYesNo + vbExclamation + vbMsgBoxSetForeground, "Check Address") = vbNo Then
Cancel = True
Else
' add BCC
Dim objRecip As Recipient
Set objRecip = Item.Recipients.Add("myid#gmail.com")
objRecip.Type = olBCC
objRecip.Resolve
'MailItem.DeferredDeliveryTime = DateAdd("n", 90, Now)
End If
End If
' Cancel if not in "cdolive.com", "slipstick.com", "outlookmvp.com"
If Not SendMail Then Cancel = True
MsgBox "The entered email address(s) are not aliged to you" & vbNewLine & "Please add the domain name in the code"
'End If
'End If
End If
Next
Last:
End If
End If
End If
End Sub
Function GetDomain(emailAddress As String) As String
Dim arr As Variant
arr = Split(emailAddress, "#")
GetDomain = Left(arr(1), InStrRev(arr(1), ".") - 1)
End Function
Function SubjectContainsEmailDomain(subject As String, email As String) As Boolean
Dim domain As String
domain = GetDomain(email)
Dim index As Integer
SubjectContainsEmailDomain = InStr(LCase(subject), LCase(domain))
End Function
The next to last part of an email address is the Second Level Domain (2LD).
This seems to be finding Recipient2LD that is different from the Subject Company.
The Subject seems to be free form typing by users, and I have no idea how to parse the SubjectCompany out of the Subject line, but if you could then this could be added after EndSelect and before Next.
Dim RecipDomainParts() As String
RecipDomainParts = Split(Right(Address, lLen), ".")
Dim Recip2LD As String ' Recipient Second Level Domain
Recip2LD = DomainParts(UBound(DomainParts) - 1)
' I have no idea how to parse the SubjectCompany out of the Subject line
If Recip2LD <> SubjectCompany Then
strMsg = strMsg & " " & Address & vbNewLine
End If
->>added 9/2/18
you need to decide yourself the general outline of your process: whether to possibly have an error message for each Recipient for each problem (List or Subject) or to combine into one message for a Recipient, while doing each Recipient, or append each msg into one message at the end of all Recipients... Then follow your outline. Work at refining the outline first, then write the code to match.
It may be good to make sub for "Recip_in_List" and make a sub for "RecipDomain_in_Subject" after you revise the outline.
BCC probably should not be skipped, as user might try to put an email there.
Your xyz#qwerty.com should be in the List.
variable SendMail cannot be set to True because it would wipe out False that had been set on prior Recipient. By doing Exit Sub when vbNo you eliminate this boolean.
Set Delay = 0min
For each Recip
If Recip not in List
Popup to user
If vbNo then Cancel=True and exit without send
Else add BCC of xyz#qwerty.com if not there
endif
endif
If RecipDomain not in Subject
Popup to user
If vbNo then Cancel=True and exit without send
Else add BCC of admin#qwerty.com if not there
set Delay = 5min
endif
endif
Next Recip
SEND with Delay
My VBA code loops through Column "I" with people's names and creates a list of emails. In email body there's a list of rows for each person from columns B, C, G, I. Pretty straightforward, however I encounter an issue with the latter. It only takes the first row for each person, i.e. doesn't loop through the list to get all of the rows for one recipient.
I have a feeling this somehow stops it from looping further:
If InStr(1, PriorRecipients, EmailAddr) <> 0 Then
GoTo NextRecipient
End If
But not sure how to implement a second loop??
Full code:
Sub SendEmail2()
Dim OutlookApp
Dim MItem
Dim cell As Range
Dim Subj As String
Dim EmailAddr As String
Dim Recipient As String
Dim Msg As String
Dim Projects As String
Dim ProjectsMsg As String
Dim bSendMail As Boolean
'Create Outlook object
Set OutlookApp = CreateObject("Outlook.Application")
Set MItem = OutlookApp.CreateItem(0)
'Loop through the rows
For Each cell In Columns("I").Cells.SpecialCells(xlCellTypeVisible)
If cell.Value <> "" And _
(Cells(cell.Row, "L").Value) = "No" And (Cells(cell.Row, "K").Value) <> "Yes" Then
'first build email address
EmailAddr = LCase$(Replace(cell.Value, " ", ".")) & "#company.com"
'then check if it is in Recipient List build, if not, add it, otherwise ignore
If InStr(1, Recipient, EmailAddr) = 0 Then Recipient = Recipient & ";" & EmailAddr
Projects = vbCrLf & "Document: " & Cells(cell.Row, "B").Value & "; " & Cells(cell.Row, "C").Value & "; " & "Rev " & Cells(cell.Row, "G").Value & "; " & Cells(cell.Row, "I").Value
If InStr(1, ProjectsMsg, Projects) = 0 Then ProjectsMsg = ProjectsMsg & Projects & vbCrLf
If InStr(1, Recipient, cell.Offset(1).Value) <> 0 Then
bSendMail = True
Recipient = Recipient & ";" & cell.Offset(1)
Else
bSendMail = False
End If
End If
Next
Msg = "You have the following outstanding documents to be reviewed at: "& ProjectsMsg
Subj = "Outstanding Documents to be Reviewed"
'Create Mail Item and view before sending
If bSendMail Then Set MItem = OutlookApp.CreateItem(olMailItem)
With MItem
.To = Recipient 'full recipient list
.Subject = Subj
.Body = Msg
.display
End With
End Sub
Change this block of code:
If InStr(1, PriorRecipients, EmailAddr) <> 0 Then
GoTo NextRecipient
End If
PriorRecipients = PriorRecipients & ";" & EmailAddr
To this
If InStr(1, PriorRecipients, EmailAddr) = 0 Then
PriorRecipients = PriorRecipients & ";" & EmailAddr
End If
'checks if it's the last email for that unique person and if so,
`it's done looping rows for that email and the email is good to send
If Instr(1, PriorRecipients, cell.Offset(1).Value) <> 0 Then
Dim bSendMail as Boolean
bSendMail = True
PriorRecipients = PriorRecipients & ";" & cell.Offset(1)
Else
bSendMail = False
End If
If bSendMail Then
Set MItem = OutlookApp.CreateItem(olMailItem)
' rest of code to send mail ...
End If
I have a Userform which has 3 buttons on it and based on the click the respective text needs to be inserted in the body of the email, for this e-mail the To, CC, Subject, will be taken from Listview box in Sheet1 which inturn extracts the values stored in Sheet2 and paste it in To, CC, Subject of the email.
When i paste the code in the buttonclick () command the variables are not getting passed from the maincode to the userform code where it shows the To, CC and Subject as blanks.
Here's the code:
Sub Worksheet_Activate()
Dim rngCell As Range
ListView41.ListItems.Clear
For Each rngCell In Worksheets("MFRs Contacts").Range("A2:A400")
If Not rngCell = Empty Then
With ListView41.ListItems.Add(, , rngCell.Value)
.ListSubItems.Add , , rngCell.Offset(0, 1).Value
.ListSubItems.Add , , rngCell.Offset(0, 2).Value
End With
End If
Next rngCell
End Sub
Sub ListView41_DblClick()
Dim strName As String
Dim strEmail As String
Dim strEmail1 As String
Dim OutApp As Object
Dim OutMail As Object
Dim Singlepart As String
Dim SigString As String
Dim Signature As String
Dim strbody As String
Dim SigFilename
strName = ListView41.SelectedItem.Text
strEmail = ListView41.SelectedItem.ListSubItems(1).Text
strEmail1 = ListView41.SelectedItem.ListSubItems(2).Text
check = MsgBox("Send e-mail, To : " & strName & " - " & strEmail & "?" & vbNewLine & _
"CC : " & strEmail1, vbYesNo)
If check <> vbYes Then Exit Sub
Singlepart = MsgBox("For Single Part or Multiple Parts ? " & vbNewLine & vbNewLine & _
"Single Part = Yes" & vbNewLine & _
"Multiple Parts = No", vbYesNo)
If Singlepart = vbYes Then
' For Single Part Numbers
Set OutApp = CreateObject("Outlook.Application")
Set OutMail = OutApp.CreateItem(0)
strbody = "<H3><B>Dear Customer Ron de Bruin</B></H3>" & _
"Please visit this website to download the new version.<br>" & _
"Let me know if you have problems.<br>" & _
"Ron's Excel Page" & _
"<br><br><B>Thank you</B>"
'Signature of User
SigString = Environ("appdata") & _
"\Microsoft\Signatures\Rohith UTAS.htm"
If Dir(SigString) <> "" Then
Signature = GetBoiler(SigString)
Else
Signature = ""
End If
On Error Resume Next
Userform1.Show
'With Outlook
With OutMail
.Display
.To = strEmail
.CC = strEmail1
.BCC = ""
.Subject = strName & "_Request for Product Information"
.HTMLBody = strbody & vbNewLine & Signature
.Display 'or .Display if you want the user to view e-mail and send it manually
End With
Else
Set OutMail = Nothing
Set OutApp = Nothing
End Sub
Can you please help me on this.
Your variables you need to access on your form (I'm assuming strName, strEmail, and strEmail1) only have scope in Sub ListView41_DblClick(). If you need to use them in your form, you'll have to pass them as parameters (my preferred way to do it) or give them global scope.
A UserForm is a class, so you can give it properties like any other class - i.e. in UserForm1:
Private mEmail As String
Public Property Let Email(inputVal As String)
mEmail = inputVal
End Property
Public Property Get Email() As String
Email = mEmail
End Property
Then you would call it like any other object:
Dim nameless_form As UserForm1
Set nameless_form = New UserForm1
nameless_form.Email = strEmail
nameless_form.Show
I have some Excel VBA code which save active sheet as PDF then attach that PDF file to outlook new mail everything works fine except the signature in outlook when the code starts outlook and new message it does not show the signature despite its in HTML and I can already insert it manually.
so any adjustment to the code will be appreciated.
Sub Send_To_Pdf()
Dim PdfPath As String
Dim BoDy As String
BoDy = Msg = "Dear Mr. " & vbCrLf & vbCrLf & "Good Day" & vbCrLf & vbCrLf & "Kindly find the attahched P.O to be delivered to " & Cells(10, 12)
PdfPath = Save_as_pdf
EnvoiMail Right(PdfPath, InStr(1, StrReverse(PdfPath), "\") - 1), "recepient1#domain.com;recepient2#domain.com", , , BoDy, 1, PdfPath
End Sub
Public Function Save_as_pdf() As String
Dim FSO As Object
Dim s(1) As String
Dim sNewFilePath As String
Set FSO = CreateObject("Scripting.FileSystemObject")
s(0) = "C:\Users\" & Environ("UserName") & "\Desktop\" & ThisWorkbook.Name
If FSO.FileExists(ThisWorkbook.FullName) Then
'//Change Excel Extension to PDF extension in FilePath
s(1) = FSO.GetExtensionName(s(0))
If s(1) <> "" Then
s(1) = "." & s(1)
sNewFilePath = Replace(s(0), s(1), ".pdf")
'//Export to PDF with new File Path
ActiveSheet.ExportAsFixedFormat _
Type:=xlTypePDF, _
Filename:=sNewFilePath, _
Quality:=xlQualityStandard, IncludeDocProperties:=True, _
IgnorePrintAreas:=False, OpenAfterPublish:=False
End If
Else
'//Error: file path not found
MsgBox "Error: this workbook may be unsaved. Please save and try again."
End If
Set FSO = Nothing
Save_as_pdf = sNewFilePath
End Function
Sub EnvoiMail(Subject As String, Destina As String, Optional CCdest As String, Optional CCIdest As String, Optional BoDyTxt As String, Optional NbPJ As Integer, Optional PjPaths As String)
Dim MonOutlook As Object
Dim MonMessage As Object
Set MonOutlook = CreateObject("Outlook.Application")
Set MonMessage = MonOutlook.createitem(0)
Dim PJ() As String
PJ() = Split(PjPaths, ";")
With MonMessage
.Subject = Subject '"Je suis content"
.To = Destina '"marcel#machin.com;julien#chose.com"
.cc = CCdest '"chef#machin.com;directeur#chose.com"
.bcc = CCIdest '"un.copain#supermail.com;une-amie#hotmail.com"
.BoDy = BoDyTxt
If PjPaths <> "" And NbPJ <> 0 Then
For i = 0 To NbPJ - 1
'MsgBox PJ(I)
.Attachments.Add PJ(i) '"C:\Mes Documents\Zoulie Image.gif"
Next i
End If
.display
'.send '.Attachments.Add ActiveWorkbook.FullName
End With '?plusieurs?MonMessage.Attachments.Add "D:\Prof\Janvier\Base clients.mdb"
Set MonOutlook = Nothing
End Sub
After a new message is created you need to insert a new text before the default signature (not to overwrite it), for example:
.BoDy = BoDyTxt
The default signature will be erased in that case.
.Body = BoDyTxt & .Body
In that case the text will be inserted in the beginning of the message leaving the signature as is.
The Outlook object model provides three different ways for working with item bodies:
Body - a plain text.
HTMLBody - an HTML markup.
The Word Editor. Outlook uses Word as an email editor, so you can use it to format the email message. The WordEditor property of the Inspector class returns an instance of the Document class which represents the message body.
You can read more about all these ways in the Chapter 17: Working with Item Bodies in MSDN.
thanks Eugene Astafiev
i changed some of the code and i got it worked after all
the changed part is as following:
Sub EnvoiMail(Subject As String, Destina As String, Optional CCdest As String, Optional CCIdest As String, Optional BoDyTxt As String, Optional NbPJ As Integer, Optional PjPaths As String)
Dim MonOutlook As Object
Dim MonMessage As Object
Dim strbody As String 'i added this part <<>>>'
Set MonOutlook = CreateObject("Outlook.Application")
Set MonMessage = MonOutlook.CreateItem(0)
strbody = "Hello" ' i put my messages here as well which i change it in my main code to get values from cells <<<<>>>'
Dim PJ() As String
PJ() = Split(PjPaths, ";")
With MonMessage
.Display ' <<<<< the most important part of the code which solved 50% of the problem >>>>'
.Subject = Subject
.To = Destina
.CC = CCdest
.BCC = CCIdest
.HTMLBoDy = strbody & "<br>" & .HTMLBoDy ' <<<< the second import part of the code and solved the other 50% >>>>> '
If PjPaths <> "" And NbPJ <> 0 Then
For i = 0 To NbPJ - 1
'MsgBox PJ(I)
.Attachments.Add PJ(i)
Next i
End If
.Display
'.send
End With
Set MonOutlook = Nothing
End Sub